Download animations and navigation bar fixes

This commit is contained in:
Ilya Laktyushin 2019-01-16 21:32:32 +04:00
parent c9631285bf
commit 06fc9e6aab
30 changed files with 907 additions and 213 deletions

View File

@ -17,6 +17,8 @@
091346982183498A00846E49 /* InstantPageArticleNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091346972183498A00846E49 /* InstantPageArticleNode.swift */; }; 091346982183498A00846E49 /* InstantPageArticleNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091346972183498A00846E49 /* InstantPageArticleNode.swift */; };
0913469A218528D200846E49 /* InstantPageTableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09134699218528D200846E49 /* InstantPageTableItem.swift */; }; 0913469A218528D200846E49 /* InstantPageTableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09134699218528D200846E49 /* InstantPageTableItem.swift */; };
0913469C21883C3700846E49 /* InstantPageDetailsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0913469B21883C3700846E49 /* InstantPageDetailsItem.swift */; }; 0913469C21883C3700846E49 /* InstantPageDetailsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0913469B21883C3700846E49 /* InstantPageDetailsItem.swift */; };
091417F221EF4E5D00C8325A /* WallpaperGalleryController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091417F121EF4E5D00C8325A /* WallpaperGalleryController.swift */; };
091417F421EF4F5F00C8325A /* WallpaperGalleryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091417F321EF4F5F00C8325A /* WallpaperGalleryItem.swift */; };
091BEAB3214552D9003AEA30 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D02DADBE2138D76F00116225 /* Vision.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 091BEAB3214552D9003AEA30 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D02DADBE2138D76F00116225 /* Vision.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
092F368D2154AAEA001A9F49 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */; }; 092F368D2154AAEA001A9F49 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */; };
092F36902157AB46001A9F49 /* ItemListCallListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */; }; 092F36902157AB46001A9F49 /* ItemListCallListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */; };
@ -1141,6 +1143,8 @@
091346972183498A00846E49 /* InstantPageArticleNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageArticleNode.swift; sourceTree = "<group>"; }; 091346972183498A00846E49 /* InstantPageArticleNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageArticleNode.swift; sourceTree = "<group>"; };
09134699218528D200846E49 /* InstantPageTableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageTableItem.swift; sourceTree = "<group>"; }; 09134699218528D200846E49 /* InstantPageTableItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageTableItem.swift; sourceTree = "<group>"; };
0913469B21883C3700846E49 /* InstantPageDetailsItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageDetailsItem.swift; sourceTree = "<group>"; }; 0913469B21883C3700846E49 /* InstantPageDetailsItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstantPageDetailsItem.swift; sourceTree = "<group>"; };
091417F121EF4E5D00C8325A /* WallpaperGalleryController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperGalleryController.swift; sourceTree = "<group>"; };
091417F321EF4F5F00C8325A /* WallpaperGalleryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperGalleryItem.swift; sourceTree = "<group>"; };
092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SFCompactRounded-Semibold.otf"; sourceTree = "<group>"; }; 092F368C2154AAE9001A9F49 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SFCompactRounded-Semibold.otf"; sourceTree = "<group>"; };
092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListCallListItem.swift; sourceTree = "<group>"; }; 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListCallListItem.swift; sourceTree = "<group>"; };
09310D14213BC5DE0020033A /* anim_read.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_read.json; sourceTree = "<group>"; }; 09310D14213BC5DE0020033A /* anim_read.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_read.json; sourceTree = "<group>"; };
@ -3148,6 +3152,8 @@
09F664CF21EBCFB900AB7E26 /* WallpaperCropNode.swift */, 09F664CF21EBCFB900AB7E26 /* WallpaperCropNode.swift */,
09DD5D5121ED175300D7007A /* WallpaperColorPickerNode.swift */, 09DD5D5121ED175300D7007A /* WallpaperColorPickerNode.swift */,
0900678C21ED5EA800530762 /* WallpaperColorPanelNode.swift */, 0900678C21ED5EA800530762 /* WallpaperColorPanelNode.swift */,
091417F121EF4E5D00C8325A /* WallpaperGalleryController.swift */,
091417F321EF4F5F00C8325A /* WallpaperGalleryItem.swift */,
); );
name = Themes; name = Themes;
sourceTree = "<group>"; sourceTree = "<group>";
@ -5871,6 +5877,7 @@
D093D7E22062F40100BC3599 /* SecureIdDocumentFormControllerNode.swift in Sources */, D093D7E22062F40100BC3599 /* SecureIdDocumentFormControllerNode.swift in Sources */,
D0B2F7702052B5A800D3BFB9 /* InviteContactsControllerNode.swift in Sources */, D0B2F7702052B5A800D3BFB9 /* InviteContactsControllerNode.swift in Sources */,
D0EC6E211EB9F58900EBF1C3 /* InstantPageController.swift in Sources */, D0EC6E211EB9F58900EBF1C3 /* InstantPageController.swift in Sources */,
091417F221EF4E5D00C8325A /* WallpaperGalleryController.swift in Sources */,
D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */, D0671F232143BDA6000A8AE7 /* TwoStepVerificationEmptyItem.swift in Sources */,
D0EC6E221EB9F58900EBF1C3 /* InstantPageControllerNode.swift in Sources */, D0EC6E221EB9F58900EBF1C3 /* InstantPageControllerNode.swift in Sources */,
D0EC6E231EB9F58900EBF1C3 /* StickerPackPreviewController.swift in Sources */, D0EC6E231EB9F58900EBF1C3 /* StickerPackPreviewController.swift in Sources */,
@ -5935,6 +5942,7 @@
D01C06BE1FBCAF06001561AB /* ChatMessageBubbleMosaicLayout.swift in Sources */, D01C06BE1FBCAF06001561AB /* ChatMessageBubbleMosaicLayout.swift in Sources */,
0900678D21ED5EA800530762 /* WallpaperColorPanelNode.swift in Sources */, 0900678D21ED5EA800530762 /* WallpaperColorPanelNode.swift in Sources */,
D0EC6E451EB9F58900EBF1C3 /* ItemListMultilineTextItem.swift in Sources */, D0EC6E451EB9F58900EBF1C3 /* ItemListMultilineTextItem.swift in Sources */,
091417F421EF4F5F00C8325A /* WallpaperGalleryItem.swift in Sources */,
D02F4AE91FCF370B004DFBAE /* ChatMessageInteractiveMediaBadge.swift in Sources */, D02F4AE91FCF370B004DFBAE /* ChatMessageInteractiveMediaBadge.swift in Sources */,
D0EC6E461EB9F58900EBF1C3 /* ItemListLoadingIndicatorEmptyStateItem.swift in Sources */, D0EC6E461EB9F58900EBF1C3 /* ItemListLoadingIndicatorEmptyStateItem.swift in Sources */,
D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */, D067B4A5211C911C00796039 /* LegacyChannelIntroController.swift in Sources */,

View File

@ -3619,7 +3619,11 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
if let button = leftNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.leftNavigationButton, target: self, selector: #selector(self.leftNavigationButtonAction)) { if let button = leftNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.leftNavigationButton, target: self, selector: #selector(self.leftNavigationButtonAction)) {
if self.leftNavigationButton != button { if self.leftNavigationButton != button {
self.navigationItem.setLeftBarButton(button.buttonItem, animated: transition.isAnimated) var animated = transition.isAnimated
if let currentButton = self.leftNavigationButton?.action, currentButton == button.action {
animated = false
}
self.navigationItem.setLeftBarButton(button.buttonItem, animated: animated)
self.leftNavigationButton = button self.leftNavigationButton = button
} }
} else if let _ = self.leftNavigationButton { } else if let _ = self.leftNavigationButton {
@ -3629,7 +3633,11 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
if let button = rightNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.rightNavigationButton, target: self, selector: #selector(self.rightNavigationButtonAction), chatInfoNavigationButton: self.chatInfoNavigationButton) { if let button = rightNavigationButtonForChatInterfaceState(updatedChatPresentationInterfaceState, strings: updatedChatPresentationInterfaceState.strings, currentButton: self.rightNavigationButton, target: self, selector: #selector(self.rightNavigationButtonAction), chatInfoNavigationButton: self.chatInfoNavigationButton) {
if self.rightNavigationButton != button { if self.rightNavigationButton != button {
self.navigationItem.setRightBarButton(button.buttonItem, animated: transition.isAnimated) var animated = transition.isAnimated
if let currentButton = self.rightNavigationButton?.action, currentButton == button.action {
animated = false
}
self.navigationItem.setRightBarButton(button.buttonItem, animated: animated)
self.rightNavigationButton = button self.rightNavigationButton = button
} }
} else if let _ = self.rightNavigationButton { } else if let _ = self.rightNavigationButton {

View File

@ -11,7 +11,7 @@ final class ChatBackgroundNode: ASDisplayNode {
didSet { didSet {
if oldValue != self.parallaxEnabled { if oldValue != self.parallaxEnabled {
if self.parallaxEnabled { if self.parallaxEnabled {
let amount = 16.0 let amount = 24.0
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis) let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -amount horizontal.minimumRelativeValue = -amount
@ -57,10 +57,10 @@ final class ChatBackgroundNode: ASDisplayNode {
} }
} }
private var backgroundImageForWallpaper: (TelegramWallpaper, PresentationWallpaperMode, UIImage)? private var backgroundImageForWallpaper: (TelegramWallpaper, WallpaperPresentationOptions, UIImage)?
private var serviceBackgroundColorForWallpaper: (TelegramWallpaper, UIColor)? private var serviceBackgroundColorForWallpaper: (TelegramWallpaper, UIColor)?
func chatControllerBackgroundImage(wallpaper: TelegramWallpaper, mode: PresentationWallpaperMode = .still, postbox: Postbox) -> UIImage? { func chatControllerBackgroundImage(wallpaper: TelegramWallpaper, mode: WallpaperPresentationOptions = [], postbox: Postbox) -> UIImage? {
var backgroundImage: UIImage? var backgroundImage: UIImage?
if wallpaper == backgroundImageForWallpaper?.0, mode == backgroundImageForWallpaper?.1 { if wallpaper == backgroundImageForWallpaper?.0, mode == backgroundImageForWallpaper?.1 {
backgroundImage = backgroundImageForWallpaper?.2 backgroundImage = backgroundImageForWallpaper?.2
@ -77,7 +77,7 @@ func chatControllerBackgroundImage(wallpaper: TelegramWallpaper, mode: Presentat
}) })
case let .image(representations): case let .image(representations):
if let largest = largestImageRepresentation(representations) { if let largest = largestImageRepresentation(representations) {
if case .blurred = mode { if mode.contains(.blur) {
var image: UIImage? var image: UIImage?
let _ = postbox.mediaBox.cachedResourceRepresentation(largest.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in let _ = postbox.mediaBox.cachedResourceRepresentation(largest.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in
if data.complete { if data.complete {
@ -91,7 +91,7 @@ func chatControllerBackgroundImage(wallpaper: TelegramWallpaper, mode: Presentat
} }
} }
case let .file(file): case let .file(file):
if case .blurred = mode { if mode.contains(.blur) {
var image: UIImage? var image: UIImage?
let _ = postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in let _ = postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in
if data.complete { if data.complete {
@ -255,7 +255,7 @@ func backgroundContrastColor(for image: Signal<UIImage?, NoError>) -> Signal<UIC
}) })
var matching: Int = 0 var matching: Int = 0
var total: Int = Int(context.size.width) * Int(context.size.height) let total: Int = Int(context.size.width) * Int(context.size.height)
for y in 0 ..< Int(context.size.height) { for y in 0 ..< Int(context.size.height) {
for x in 0 ..< Int(context.size.width) { for x in 0 ..< Int(context.size.width) {
var saturation: CGFloat = 0.0 var saturation: CGFloat = 0.0

View File

@ -241,7 +241,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
self.backgroundNode.image = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, mode: chatPresentationInterfaceState.chatWallpaperMode, postbox: account.postbox) self.backgroundNode.image = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, mode: chatPresentationInterfaceState.chatWallpaperMode, postbox: account.postbox)
if case .perspective = chatPresentationInterfaceState.chatWallpaperMode { if chatPresentationInterfaceState.chatWallpaperMode.contains(.motion) {
self.backgroundNode.parallaxEnabled = true self.backgroundNode.parallaxEnabled = true
} }
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8) self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
@ -540,28 +540,28 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight) self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
let transitionIsAnimated: Bool // let transitionIsAnimated: Bool
if case .immediate = transition { // if case .immediate = transition {
transitionIsAnimated = false // transitionIsAnimated = false
} else { // } else {
transitionIsAnimated = true // transitionIsAnimated = true
} // }
//
if let _ = self.chatPresentationInterfaceState.search, let interfaceInteraction = self.interfaceInteraction { // if let _ = self.chatPresentationInterfaceState.search, let interfaceInteraction = self.interfaceInteraction {
var activate = false // var activate = false
if self.searchNavigationNode == nil { // if self.searchNavigationNode == nil {
activate = true // activate = true
self.searchNavigationNode = ChatSearchNavigationContentNode(theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings, chatLocation: self.chatPresentationInterfaceState.chatLocation, interaction: interfaceInteraction) // self.searchNavigationNode = ChatSearchNavigationContentNode(theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings, chatLocation: self.chatPresentationInterfaceState.chatLocation, interaction: interfaceInteraction)
} // }
self.navigationBar?.setContentNode(self.searchNavigationNode, animated: transitionIsAnimated) // self.navigationBar?.setContentNode(self.searchNavigationNode, animated: transitionIsAnimated)
self.searchNavigationNode?.update(presentationInterfaceState: self.chatPresentationInterfaceState) // self.searchNavigationNode?.update(presentationInterfaceState: self.chatPresentationInterfaceState)
if activate { // if activate {
self.searchNavigationNode?.activate() // self.searchNavigationNode?.activate()
} // }
} else if let _ = self.searchNavigationNode { // } else if let _ = self.searchNavigationNode {
self.searchNavigationNode = nil // self.searchNavigationNode = nil
self.navigationBar?.setContentNode(nil, animated: transitionIsAnimated) // self.navigationBar?.setContentNode(nil, animated: transitionIsAnimated)
} // }
var dismissedTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode? var dismissedTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode?
var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false
@ -1316,12 +1316,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if self.chatPresentationInterfaceState != chatPresentationInterfaceState { if self.chatPresentationInterfaceState != chatPresentationInterfaceState {
let themeUpdated = self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme let themeUpdated = self.chatPresentationInterfaceState.theme !== chatPresentationInterfaceState.theme
if self.chatPresentationInterfaceState.chatWallpaper != chatPresentationInterfaceState.chatWallpaper { if self.chatPresentationInterfaceState.chatWallpaper != chatPresentationInterfaceState.chatWallpaper || self.chatPresentationInterfaceState.chatWallpaperMode != chatPresentationInterfaceState.chatWallpaperMode {
self.backgroundNode.image = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, mode: chatPresentationInterfaceState.chatWallpaperMode, postbox: account.postbox) self.backgroundNode.image = chatControllerBackgroundImage(wallpaper: chatPresentationInterfaceState.chatWallpaper, mode: chatPresentationInterfaceState.chatWallpaperMode, postbox: account.postbox)
}
if chatPresentationInterfaceState.chatWallpaperMode.contains(.motion) {
if self.chatPresentationInterfaceState.chatWallpaperMode != chatPresentationInterfaceState.chatWallpaperMode {
if case .perspective = chatPresentationInterfaceState.chatWallpaperMode {
self.backgroundNode.parallaxEnabled = true self.backgroundNode.parallaxEnabled = true
} else { } else {
self.backgroundNode.parallaxEnabled = false self.backgroundNode.parallaxEnabled = false
@ -1393,6 +1391,29 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let layoutTransition: ContainedViewLayoutTransition = transition let layoutTransition: ContainedViewLayoutTransition = transition
let transitionIsAnimated: Bool
if case .immediate = transition {
transitionIsAnimated = false
} else {
transitionIsAnimated = true
}
if let _ = self.chatPresentationInterfaceState.search, let interfaceInteraction = self.interfaceInteraction {
var activate = false
if self.searchNavigationNode == nil {
activate = true
self.searchNavigationNode = ChatSearchNavigationContentNode(theme: self.chatPresentationInterfaceState.theme, strings: self.chatPresentationInterfaceState.strings, chatLocation: self.chatPresentationInterfaceState.chatLocation, interaction: interfaceInteraction)
}
self.navigationBar?.setContentNode(self.searchNavigationNode, animated: transitionIsAnimated)
self.searchNavigationNode?.update(presentationInterfaceState: self.chatPresentationInterfaceState)
if activate {
self.searchNavigationNode?.activate()
}
} else if let _ = self.searchNavigationNode {
self.searchNavigationNode = nil
self.navigationBar?.setContentNode(nil, animated: transitionIsAnimated)
}
if updatedInputFocus { if updatedInputFocus {
if !self.ignoreUpdateHeight { if !self.ignoreUpdateHeight {
self.scheduleLayoutTransitionRequest(layoutTransition) self.scheduleLayoutTransitionRequest(layoutTransition)

View File

@ -335,7 +335,7 @@ final class ChatPresentationInterfaceState: Equatable {
let search: ChatSearchData? let search: ChatSearchData?
let searchQuerySuggestionResult: ChatPresentationInputQueryResult? let searchQuerySuggestionResult: ChatPresentationInputQueryResult?
let chatWallpaper: TelegramWallpaper let chatWallpaper: TelegramWallpaper
let chatWallpaperMode: PresentationWallpaperMode let chatWallpaperMode: WallpaperPresentationOptions
let theme: PresentationTheme let theme: PresentationTheme
let strings: PresentationStrings let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat let dateTimeFormat: PresentationDateTimeFormat
@ -344,7 +344,7 @@ final class ChatPresentationInterfaceState: Equatable {
let accountPeerId: PeerId let accountPeerId: PeerId
let mode: ChatControllerPresentationMode let mode: ChatControllerPresentationMode
init(chatWallpaper: TelegramWallpaper, chatWallpaperMode: PresentationWallpaperMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation) { init(chatWallpaper: TelegramWallpaper, chatWallpaperMode: WallpaperPresentationOptions, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode, chatLocation: ChatLocation) {
self.interfaceState = ChatInterfaceState() self.interfaceState = ChatInterfaceState()
self.inputTextPanelState = ChatTextInputPanelState() self.inputTextPanelState = ChatTextInputPanelState()
self.editMessageState = nil self.editMessageState = nil
@ -383,7 +383,7 @@ final class ChatPresentationInterfaceState: Equatable {
self.mode = mode self.mode = mode
} }
init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, isContact: Bool, hasBots: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, chatWallpaperMode: PresentationWallpaperMode, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) { init(interfaceState: ChatInterfaceState, chatLocation: ChatLocation, renderedPeer: RenderedPeer?, isNotAccessible: Bool, explicitelyCanPinMessages: Bool, isContact: Bool, hasBots: Bool, inputTextPanelState: ChatTextInputPanelState, editMessageState: ChatEditInterfaceMessageState?, recordedMediaPreview: ChatRecordedMediaPreview?, inputQueryResults: [ChatPresentationInputQueryKind: ChatPresentationInputQueryResult], inputMode: ChatInputMode, titlePanelContexts: [ChatTitlePanelContext], keyboardButtonsMessage: Message?, pinnedMessageId: MessageId?, pinnedMessage: Message?, peerIsBlocked: Bool, peerIsMuted: Bool, canReportPeer: Bool, callsAvailable: Bool, callsPrivate: Bool, chatHistoryState: ChatHistoryNodeHistoryState?, botStartPayload: String?, urlPreview: (String, TelegramMediaWebpage)?, editingUrlPreview: (String, TelegramMediaWebpage)?, search: ChatSearchData?, searchQuerySuggestionResult: ChatPresentationInputQueryResult?, chatWallpaper: TelegramWallpaper, chatWallpaperMode: WallpaperPresentationOptions, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, fontSize: PresentationFontSize, accountPeerId: PeerId, mode: ChatControllerPresentationMode) {
self.interfaceState = interfaceState self.interfaceState = interfaceState
self.chatLocation = chatLocation self.chatLocation = chatLocation
self.renderedPeer = renderedPeer self.renderedPeer = renderedPeer
@ -712,7 +712,7 @@ final class ChatPresentationInterfaceState: Equatable {
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, chatWallpaperMode: self.chatWallpaperMode, theme: self.theme, strings: self.strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: self.chatWallpaper, chatWallpaperMode: self.chatWallpaperMode, theme: self.theme, strings: self.strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
} }
func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper, mode: PresentationWallpaperMode) -> ChatPresentationInterfaceState { func updatedChatWallpaper(_ chatWallpaper: TelegramWallpaper, mode: WallpaperPresentationOptions) -> ChatPresentationInterfaceState {
return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, chatWallpaperMode: mode, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode) return ChatPresentationInterfaceState(interfaceState: self.interfaceState, chatLocation: self.chatLocation, renderedPeer: self.renderedPeer, isNotAccessible: self.isNotAccessible, explicitelyCanPinMessages: self.explicitelyCanPinMessages, isContact: self.isContact, hasBots: self.hasBots, inputTextPanelState: self.inputTextPanelState, editMessageState: self.editMessageState, recordedMediaPreview: self.recordedMediaPreview, inputQueryResults: self.inputQueryResults, inputMode: self.inputMode, titlePanelContexts: self.titlePanelContexts, keyboardButtonsMessage: self.keyboardButtonsMessage, pinnedMessageId: self.pinnedMessageId, pinnedMessage: self.pinnedMessage, peerIsBlocked: self.peerIsBlocked, peerIsMuted: self.peerIsMuted, canReportPeer: self.canReportPeer, callsAvailable: self.callsAvailable, callsPrivate: self.callsPrivate, chatHistoryState: self.chatHistoryState, botStartPayload: self.botStartPayload, urlPreview: self.urlPreview, editingUrlPreview: self.editingUrlPreview, search: self.search, searchQuerySuggestionResult: self.searchQuerySuggestionResult, chatWallpaper: chatWallpaper, chatWallpaperMode: mode, theme: self.theme, strings: self.strings, dateTimeFormat: self.dateTimeFormat, nameDisplayOrder: self.nameDisplayOrder, fontSize: self.fontSize, accountPeerId: self.accountPeerId, mode: self.mode)
} }
} }

View File

@ -410,7 +410,7 @@ func openChatWallpaper(account: Account, message: Message, present: @escaping (V
let _ = (resolveUrl(account: account, url: content.url) let _ = (resolveUrl(account: account, url: content.url)
|> deliverOnMainQueue).start(next: { resolvedUrl in |> deliverOnMainQueue).start(next: { resolvedUrl in
if case let .wallpaper(parameter) = resolvedUrl { if case let .wallpaper(parameter) = resolvedUrl {
let source: WallpaperListPreviewSource let source: WallpaperListSource
switch parameter { switch parameter {
case let .slug(slug): case let .slug(slug):
source = .slug(slug, content.file) source = .slug(slug, content.file)

View File

@ -304,7 +304,7 @@ class PermissionInfoItemNode: ListViewItemNode {
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + 9.0), size: textLayout.size) strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: strongSelf.titleNode.frame.maxY + 9.0), size: textLayout.size)
strongSelf.closeButton.frame = CGRect(x: params.width - rightInset - 21.0, y: 10.0, width: 32.0, height: 32.0) strongSelf.closeButton.frame = CGRect(x: params.width - rightInset - 26.0, y: 10.0, width: 32.0, height: 32.0)
} }
}) })
} }

View File

@ -46,7 +46,7 @@ public final class PresentationData: Equatable {
public let strings: PresentationStrings public let strings: PresentationStrings
public let theme: PresentationTheme public let theme: PresentationTheme
public let chatWallpaper: TelegramWallpaper public let chatWallpaper: TelegramWallpaper
public let chatWallpaperMode: PresentationWallpaperMode public let chatWallpaperMode: WallpaperPresentationOptions
public let volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons public let volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons
public let fontSize: PresentationFontSize public let fontSize: PresentationFontSize
public let dateTimeFormat: PresentationDateTimeFormat public let dateTimeFormat: PresentationDateTimeFormat
@ -54,7 +54,7 @@ public final class PresentationData: Equatable {
public let nameSortOrder: PresentationPersonNameOrder public let nameSortOrder: PresentationPersonNameOrder
public let disableAnimations: Bool public let disableAnimations: Bool
public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, chatWallpaperMode: PresentationWallpaperMode, volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool) { public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, chatWallpaperMode: WallpaperPresentationOptions, volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool) {
self.strings = strings self.strings = strings
self.theme = theme self.theme = theme
self.chatWallpaper = chatWallpaper self.chatWallpaper = chatWallpaper
@ -236,7 +236,7 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
let effectiveTheme: PresentationThemeReference let effectiveTheme: PresentationThemeReference
var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper
var effectiveChatWallpaperMode: PresentationWallpaperMode = themeSettings.chatWallpaperMode var effectiveChatWallpaperOptions: WallpaperPresentationOptions = themeSettings.chatWallpaperOptions
if automaticThemeShouldSwitchNow(themeSettings.automaticThemeSwitchSetting, currentTheme: themeSettings.theme) { if automaticThemeShouldSwitchNow(themeSettings.automaticThemeSwitchSetting, currentTheme: themeSettings.theme) {
effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme) effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme)
@ -245,10 +245,10 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
switch themeSettings.automaticThemeSwitchSetting.theme { switch themeSettings.automaticThemeSwitchSetting.theme {
case .nightAccent: case .nightAccent:
effectiveChatWallpaper = .color(0x18222d) effectiveChatWallpaper = .color(0x18222d)
effectiveChatWallpaperMode = .still effectiveChatWallpaperOptions = []
case .nightGrayscale: case .nightGrayscale:
effectiveChatWallpaper = .color(0x000000) effectiveChatWallpaper = .color(0x000000)
effectiveChatWallpaperMode = .still effectiveChatWallpaperOptions = []
default: default:
break break
} }
@ -281,7 +281,7 @@ public func currentPresentationDataAndSettings(postbox: Postbox) -> Signal<Initi
let dateTimeFormat = currentDateTimeFormat() let dateTimeFormat = currentDateTimeFormat()
let nameDisplayOrder = contactSettings.nameDisplayOrder let nameDisplayOrder = contactSettings.nameDisplayOrder
let nameSortOrder = currentPersonNameSortOrder() let nameSortOrder = currentPersonNameSortOrder()
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, chatWallpaperMode: effectiveChatWallpaperMode, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations), automaticMediaDownloadSettings: automaticMediaDownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings) return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, chatWallpaperMode: effectiveChatWallpaperOptions, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations), automaticMediaDownloadSettings: automaticMediaDownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
} }
} }
@ -375,7 +375,7 @@ public func updatedPresentationData(postbox: Postbox, applicationBindings: Teleg
let themeValue: PresentationTheme let themeValue: PresentationTheme
let effectiveTheme: PresentationThemeReference let effectiveTheme: PresentationThemeReference
var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper var effectiveChatWallpaper: TelegramWallpaper = themeSettings.chatWallpaper
var effectiveChatWallpaperMode: PresentationWallpaperMode = themeSettings.chatWallpaperMode var effectiveChatWallpaperOptions: WallpaperPresentationOptions = themeSettings.chatWallpaperOptions
if shouldSwitch { if shouldSwitch {
effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme) effectiveTheme = .builtin(themeSettings.automaticThemeSwitchSetting.theme)
@ -384,10 +384,10 @@ public func updatedPresentationData(postbox: Postbox, applicationBindings: Teleg
switch themeSettings.automaticThemeSwitchSetting.theme { switch themeSettings.automaticThemeSwitchSetting.theme {
case .nightAccent: case .nightAccent:
effectiveChatWallpaper = .color(0x18222d) effectiveChatWallpaper = .color(0x18222d)
effectiveChatWallpaperMode = .still effectiveChatWallpaperOptions = []
case .nightGrayscale: case .nightGrayscale:
effectiveChatWallpaper = .color(0x000000) effectiveChatWallpaper = .color(0x000000)
effectiveChatWallpaperMode = .still effectiveChatWallpaperOptions = []
default: default:
break break
} }
@ -429,7 +429,7 @@ public func updatedPresentationData(postbox: Postbox, applicationBindings: Teleg
let nameDisplayOrder = contactSettings.nameDisplayOrder let nameDisplayOrder = contactSettings.nameDisplayOrder
let nameSortOrder = currentPersonNameSortOrder() let nameSortOrder = currentPersonNameSortOrder()
return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, chatWallpaperMode: effectiveChatWallpaperMode, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations) return PresentationData(strings: stringsValue, theme: themeValue, chatWallpaper: effectiveChatWallpaper, chatWallpaperMode: effectiveChatWallpaperOptions, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations)
} }
} else { } else {
return .complete() return .complete()
@ -445,5 +445,5 @@ public func defaultPresentationData() -> PresentationData {
let nameSortOrder = currentPersonNameSortOrder() let nameSortOrder = currentPersonNameSortOrder()
let themeSettings = PresentationThemeSettings.defaultSettings let themeSettings = PresentationThemeSettings.defaultSettings
return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, chatWallpaperMode: .still, volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations) return PresentationData(strings: defaultPresentationStrings, theme: defaultPresentationTheme, chatWallpaper: .builtin, chatWallpaperMode: [], volumeControlStatusBarIcons: volumeControlStatusBarIcons(), fontSize: themeSettings.fontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, disableAnimations: themeSettings.disableAnimations)
} }

View File

@ -10,10 +10,19 @@ public enum PresentationBuiltinThemeReference: Int32 {
case nightAccent = 3 case nightAccent = 3
} }
public enum PresentationWallpaperMode: Int32 { public struct WallpaperPresentationOptions: OptionSet {
case still public var rawValue: Int32
case perspective
case blurred public init(rawValue: Int32) {
self.rawValue = rawValue
}
public init() {
self.rawValue = 0
}
public static let motion = WallpaperPresentationOptions(rawValue: 1 << 0)
public static let blur = WallpaperPresentationOptions(rawValue: 1 << 1)
} }
public enum PresentationThemeReference: PostboxCoding, Equatable { public enum PresentationThemeReference: PostboxCoding, Equatable {
@ -147,7 +156,7 @@ public struct AutomaticThemeSwitchSetting: PostboxCoding, Equatable {
public struct PresentationThemeSettings: PreferencesEntry { public struct PresentationThemeSettings: PreferencesEntry {
public var chatWallpaper: TelegramWallpaper public var chatWallpaper: TelegramWallpaper
public var chatWallpaperMode: PresentationWallpaperMode public var chatWallpaperOptions: WallpaperPresentationOptions
public var theme: PresentationThemeReference public var theme: PresentationThemeReference
public var themeAccentColor: Int32? public var themeAccentColor: Int32?
public var fontSize: PresentationFontSize public var fontSize: PresentationFontSize
@ -164,12 +173,12 @@ public struct PresentationThemeSettings: PreferencesEntry {
} }
public static var defaultSettings: PresentationThemeSettings { public static var defaultSettings: PresentationThemeSettings {
return PresentationThemeSettings(chatWallpaper: .builtin, chatWallpaperMode: .still, theme: .builtin(.dayClassic), themeAccentColor: nil, fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent), disableAnimations: true) return PresentationThemeSettings(chatWallpaper: .builtin, chatWallpaperOptions: [], theme: .builtin(.dayClassic), themeAccentColor: nil, fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent), disableAnimations: true)
} }
public init(chatWallpaper: TelegramWallpaper, chatWallpaperMode: PresentationWallpaperMode, theme: PresentationThemeReference, themeAccentColor: Int32?, fontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, disableAnimations: Bool) { public init(chatWallpaper: TelegramWallpaper, chatWallpaperOptions: WallpaperPresentationOptions, theme: PresentationThemeReference, themeAccentColor: Int32?, fontSize: PresentationFontSize, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting, disableAnimations: Bool) {
self.chatWallpaper = chatWallpaper self.chatWallpaper = chatWallpaper
self.chatWallpaperMode = chatWallpaperMode self.chatWallpaperOptions = chatWallpaperOptions
self.theme = theme self.theme = theme
self.themeAccentColor = themeAccentColor self.themeAccentColor = themeAccentColor
self.fontSize = fontSize self.fontSize = fontSize
@ -179,7 +188,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
self.chatWallpaper = (decoder.decodeObjectForKey("w", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper) ?? .builtin self.chatWallpaper = (decoder.decodeObjectForKey("w", decoder: { TelegramWallpaper(decoder: $0) }) as? TelegramWallpaper) ?? .builtin
self.chatWallpaperMode = PresentationWallpaperMode(rawValue: decoder.decodeInt32ForKey("m", orElse: 0)) ?? .still self.chatWallpaperOptions = WallpaperPresentationOptions(rawValue: decoder.decodeInt32ForKey("o", orElse: 0))
self.theme = decoder.decodeObjectForKey("t", decoder: { PresentationThemeReference(decoder: $0) }) as! PresentationThemeReference self.theme = decoder.decodeObjectForKey("t", decoder: { PresentationThemeReference(decoder: $0) }) as! PresentationThemeReference
self.themeAccentColor = decoder.decodeOptionalInt32ForKey("themeAccentColor") self.themeAccentColor = decoder.decodeOptionalInt32ForKey("themeAccentColor")
self.fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular self.fontSize = PresentationFontSize(rawValue: decoder.decodeInt32ForKey("f", orElse: PresentationFontSize.regular.rawValue)) ?? .regular
@ -189,7 +198,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
encoder.encodeObject(self.chatWallpaper, forKey: "w") encoder.encodeObject(self.chatWallpaper, forKey: "w")
encoder.encodeInt32(self.chatWallpaperMode.rawValue, forKey: "m") encoder.encodeInt32(self.chatWallpaperOptions.rawValue, forKey: "o")
encoder.encodeObject(self.theme, forKey: "t") encoder.encodeObject(self.theme, forKey: "t")
if let themeAccentColor = self.themeAccentColor { if let themeAccentColor = self.themeAccentColor {
encoder.encodeInt32(themeAccentColor, forKey: "themeAccentColor") encoder.encodeInt32(themeAccentColor, forKey: "themeAccentColor")
@ -210,7 +219,7 @@ public struct PresentationThemeSettings: PreferencesEntry {
} }
public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool { public static func ==(lhs: PresentationThemeSettings, rhs: PresentationThemeSettings) -> Bool {
return lhs.chatWallpaper == rhs.chatWallpaper && lhs.chatWallpaperMode == rhs.chatWallpaperMode && lhs.theme == rhs.theme && lhs.themeAccentColor == rhs.themeAccentColor && lhs.fontSize == rhs.fontSize && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting && lhs.disableAnimations == rhs.disableAnimations return lhs.chatWallpaper == rhs.chatWallpaper && lhs.chatWallpaperOptions == rhs.chatWallpaperOptions && lhs.theme == rhs.theme && lhs.themeAccentColor == rhs.themeAccentColor && lhs.fontSize == rhs.fontSize && lhs.automaticThemeSwitchSetting == rhs.automaticThemeSwitchSetting && lhs.disableAnimations == rhs.disableAnimations
} }
} }

View File

@ -47,7 +47,7 @@ final class RadialCheckContentNode: RadialStatusContentNode {
self.isLayerBacked = true self.isLayerBacked = true
} }
func animateProgress() { func animateProgress(delay: Double) {
self.animationCompletionTimer?.invalidate() self.animationCompletionTimer?.invalidate()
self.animationCompletionTimer = nil self.animationCompletionTimer = nil
let animation = POPBasicAnimation() let animation = POPBasicAnimation()
@ -64,6 +64,7 @@ final class RadialCheckContentNode: RadialStatusContentNode {
animation.toValue = 1.0 as NSNumber animation.toValue = 1.0 as NSNumber
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.duration = 0.25 animation.duration = 0.25
animation.beginTime = delay
animation.completionBlock = { [weak self] _, _ in animation.completionBlock = { [weak self] _, _ in
if let strongSelf = self { if let strongSelf = self {
strongSelf.animationCompletionTimer?.invalidate() strongSelf.animationCompletionTimer?.invalidate()
@ -163,10 +164,10 @@ final class RadialCheckContentNode: RadialStatusContentNode {
self.layer.animateScale(from: 1.0, to: 0.6, duration: duration, removeOnCompletion: false) self.layer.animateScale(from: 1.0, to: 0.6, duration: duration, removeOnCompletion: false)
} }
override func animateIn(from: RadialStatusNodeState) { override func animateIn(from: RadialStatusNodeState, delay: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration, delay: delay)
self.layer.animateScale(from: 0.7, to: 1.0, duration: duration) self.layer.animateScale(from: 0.7, to: 1.0, duration: duration, delay: delay)
self.animateProgress() self.animateProgress(delay: delay)
} }
} }

View File

@ -294,8 +294,8 @@ final class RadialCloudProgressContentNode: RadialStatusContentNode {
self.cancelNode.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false) self.cancelNode.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
} }
override func animateIn(from: RadialStatusNodeState) { override func animateIn(from: RadialStatusNodeState, delay: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
self.cancelNode.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15) self.cancelNode.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, delay: delay)
} }
} }

View File

@ -116,11 +116,8 @@ final class RadialDownloadContentNode: RadialStatusContentNode {
let diameter = min(bounds.size.width, bounds.size.height) let diameter = min(bounds.size.width, bounds.size.height)
let factor = diameter / 50.0 let factor = diameter / 50.0
var lineWidth: CGFloat = 2.0 let lineWidth: CGFloat = max(1.6, 2.25 * factor)
if diameter < 24.0 {
lineWidth = 1.3
}
self.leftLine.lineWidth = lineWidth self.leftLine.lineWidth = lineWidth
self.rightLine.lineWidth = lineWidth self.rightLine.lineWidth = lineWidth
self.arrowBody.lineWidth = lineWidth self.arrowBody.lineWidth = lineWidth
@ -142,34 +139,35 @@ final class RadialDownloadContentNode: RadialStatusContentNode {
private let duration: Double = 0.2 private let duration: Double = 0.2
override func prepareAnimateOut(completion: @escaping () -> Void) { override func prepareAnimateOut(completion: @escaping (Double) -> Void) {
let bounds = self.bounds let bounds = self.bounds
let diameter = min(bounds.size.width, bounds.size.height) let diameter = min(bounds.size.width, bounds.size.height)
let factor = diameter / 50.0 let factor = diameter / 50.0
var bodyPath = UIBezierPath() var bodyPath = UIBezierPath()
if let path = try? svgPath("M1.20125335,62.2095675 C1.78718228,62.9863141 2.3877868,63.7395876 3.00158591,64.4690754 C22.1087455,87.1775489 54.0019347,86.8368674 54.0066002,54.0178571 L54.0066002,0.625 ", scale: CGPoint(x: 0.333333 * factor, y: 0.333333 * factor), offset: CGPoint(x: 7.0 * factor, y: (17.0 - UIScreenPixel) * factor)) {
if let path = try? svgPath("M1.10890748,47.3077093 C2.74202161,51.7201715 4.79761832,55.7299828 7.15775768,59.3122505 C25.4413606,87.0634763 62.001605,89.1563513 62.0066002,54.0178571 L62.0066002,0.625 ", scale: CGPoint(x: 0.333333 * factor, y: 0.333333 * factor), offset: CGPoint(x: (4.0 + UIScreenPixel) * factor, y: (17.0 - UIScreenPixel) * factor)) {
bodyPath = path bodyPath = path
} }
self.arrowBody.path = bodyPath.cgPath self.arrowBody.path = bodyPath.cgPath
self.arrowBody.strokeStart = 0.62 self.arrowBody.strokeStart = 0.65
self.leftLine.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) self.leftLine.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.rightLine.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false) self.rightLine.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
self.leftLine.animateAlpha(from: 1.0, to: 0.0, duration: 0.23, delay: 0.07, removeOnCompletion: false) { finished in self.leftLine.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, delay: 0.07, removeOnCompletion: false) { finished in
completion() completion(0.0)
} }
self.rightLine.animateAlpha(from: 1.0, to: 0.0, duration: 0.23, delay: 0.07, removeOnCompletion: false) self.rightLine.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, delay: 0.07, removeOnCompletion: false)
} }
override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) { override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
self.arrowBody.animateStrokeStart(from: 0.62, to: 0.0, duration: 0.5, removeOnCompletion: false, completion: { _ in self.arrowBody.animateStrokeStart(from: 0.65, to: 0.0, duration: 0.5, removeOnCompletion: false, completion: { _ in
completion() completion()
}) })
self.arrowBody.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.5, removeOnCompletion: false, completion: nil) self.arrowBody.animateStrokeEnd(from: 1.0, to: 0.0, duration: 0.5, removeOnCompletion: false, completion: nil)
self.arrowBody.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, delay: 0.4, removeOnCompletion: false) self.arrowBody.animateAlpha(from: 1.0, to: 0.0, duration: 0.01, delay: 0.4, removeOnCompletion: false)
} }
override func prepareAnimateIn(from: RadialStatusNodeState?) { override func prepareAnimateIn(from: RadialStatusNodeState?) {
@ -178,28 +176,28 @@ final class RadialDownloadContentNode: RadialStatusContentNode {
let factor = diameter / 50.0 let factor = diameter / 50.0
var bodyPath = UIBezierPath() var bodyPath = UIBezierPath()
if let path = try? svgPath("M1.20125335,62.2095675 C1.78718228,62.9863141 2.3877868,63.7395876 3.00158591,64.4690754 C22.1087455,87.1775489 54.0019347,86.8368674 54.0066002,54.0178571 L54.0066002,0.625 ", scale: CGPoint(x: -0.333333 * factor, y: 0.333333 * factor), offset: CGPoint(x: 43.0 * factor, y: (17.0 - UIScreenPixel) * factor)) { if let path = try? svgPath("M1.10890748,47.3077093 C2.74202161,51.7201715 4.79761832,55.7299828 7.15775768,59.3122505 C25.4413606,87.0634763 62.001605,89.1563513 62.0066002,54.0178571 L62.0066002,0.625 ", scale: CGPoint(x: -0.333333 * factor, y: 0.333333 * factor), offset: CGPoint(x: (46.0 - UIScreenPixel) * factor, y: (17.0 - UIScreenPixel) * factor)) {
bodyPath = path bodyPath = path
} }
self.arrowBody.path = bodyPath.cgPath self.arrowBody.path = bodyPath.cgPath
self.arrowBody.strokeStart = 0.62 self.arrowBody.strokeStart = 0.65
} }
override func animateIn(from: RadialStatusNodeState) { override func animateIn(from: RadialStatusNodeState, delay: Double) {
if case .progress = from { if case .progress = from {
self.arrowBody.animateStrokeStart(from: 0.62, to: 0.62, duration: 0.25, removeOnCompletion: false, completion: nil) self.arrowBody.animateStrokeStart(from: 0.65, to: 0.65, duration: 0.25, delay: delay, removeOnCompletion: false, completion: nil)
self.arrowBody.animateStrokeEnd(from: 0.62, to: 1.0, duration: 0.25, removeOnCompletion: false, completion: nil) self.arrowBody.animateStrokeEnd(from: 0.65, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false, completion: nil)
self.leftLine.animateStrokeEnd(from: 0.0, to: 1.0, duration: 0.25, delay: 0.0, removeOnCompletion: false) self.leftLine.animateStrokeEnd(from: 0.0, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false)
self.rightLine.animateStrokeEnd(from: 0.0, to: 1.0, duration: 0.25, delay: 0.0, removeOnCompletion: false) self.rightLine.animateStrokeEnd(from: 0.0, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false)
self.arrowBody.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.0, removeOnCompletion: false) self.arrowBody.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false)
self.leftLine.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.0, removeOnCompletion: false) self.leftLine.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false)
self.rightLine.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.0, removeOnCompletion: false) self.rightLine.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: delay, removeOnCompletion: false)
} else { } else {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration, delay: delay)
self.layer.animateScale(from: 0.7, to: 1.0, duration: duration) self.layer.animateScale(from: 0.7, to: 1.0, duration: duration, delay: delay)
} }
} }
} }

View File

@ -152,14 +152,16 @@ private final class RadialProgressContentSpinnerNode: ASDisplayNode {
super.willEnterHierarchy() super.willEnterHierarchy()
let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") let basicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
basicAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
basicAnimation.duration = 1.5 basicAnimation.duration = 1.5
let fromValue = Float.pi + 0.33 var fromValue = Float.pi + 0.58
if let presentation = self.layer.presentation(), let value = (presentation.value(forKeyPath: "transform.rotation.z") as? NSNumber)?.floatValue {
fromValue = value
}
basicAnimation.fromValue = NSNumber(value: fromValue) basicAnimation.fromValue = NSNumber(value: fromValue)
basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0) basicAnimation.toValue = NSNumber(value: fromValue + Float.pi * 2.0)
basicAnimation.repeatCount = Float.infinity basicAnimation.repeatCount = Float.infinity
basicAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) basicAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
basicAnimation.beginTime = 0.0 //1.0 basicAnimation.beginTime = 0.0
self.layer.add(basicAnimation, forKey: "progressRotation") self.layer.add(basicAnimation, forKey: "progressRotation")
} }
@ -274,14 +276,6 @@ final class RadialProgressContentNode: RadialStatusContentNode {
} }
} }
override func enqueueReadyForTransition(_ f: @escaping () -> Void) {
if self.spinnerNode.isAnimatingProgress && self.progress == 1.0 {
self.enqueuedReadyForTransition = f
} else {
f()
}
}
override func layout() { override func layout() {
super.layout() super.layout()
@ -291,10 +285,9 @@ final class RadialProgressContentNode: RadialStatusContentNode {
self.cancelNode.frame = bounds self.cancelNode.frame = bounds
} }
override func prepareAnimateOut(completion: @escaping () -> Void) { override func prepareAnimateOut(completion: @escaping (Double) -> Void) {
self.cancelNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.15, removeOnCompletion: false, completion: { _ in self.cancelNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.15, removeOnCompletion: false, completion: { _ in })
completion() completion(0.0)
})
} }
override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) { override func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
@ -308,11 +301,11 @@ final class RadialProgressContentNode: RadialStatusContentNode {
self.spinnerNode.progress = self.progress self.spinnerNode.progress = self.progress
} }
override func animateIn(from: RadialStatusNodeState) { override func animateIn(from: RadialStatusNodeState, delay: Double) {
if case .download = from { if case .download = from {
} else { } else {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay)
} }
self.cancelNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2) self.cancelNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.2, delay: delay)
} }
} }

View File

@ -9,8 +9,8 @@ class RadialStatusContentNode: ASDisplayNode {
private let duration: Double = 0.2 private let duration: Double = 0.2
func prepareAnimateOut(completion: @escaping () -> Void) { func prepareAnimateOut(completion: @escaping (Double) -> Void) {
completion() completion(0.0)
} }
func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) { func animateOut(to: RadialStatusNodeState, completion: @escaping () -> Void) {
@ -23,8 +23,8 @@ class RadialStatusContentNode: ASDisplayNode {
func prepareAnimateIn(from: RadialStatusNodeState?) { func prepareAnimateIn(from: RadialStatusNodeState?) {
} }
func animateIn(from: RadialStatusNodeState) { func animateIn(from: RadialStatusNodeState, delay: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration, delay: delay)
self.layer.animateScale(from: 0.2, to: 1.0, duration: duration) self.layer.animateScale(from: 0.2, to: 1.0, duration: duration, delay: delay)
} }
} }

View File

@ -173,23 +173,18 @@ public final class RadialStatusNode: ASControlNode {
} }
} }
}) })
previousContentNode.prepareAnimateOut(completion: { previousContentNode.prepareAnimateOut(completion: { delay in
if let contentNode = strongSelf.contentNode { if let contentNode = strongSelf.contentNode {
strongSelf.addSubnode(contentNode) strongSelf.addSubnode(contentNode)
contentNode.frame = strongSelf.bounds contentNode.frame = strongSelf.bounds
contentNode.prepareAnimateIn(from: fromState) contentNode.prepareAnimateIn(from: fromState)
if strongSelf.isNodeLoaded { if strongSelf.isNodeLoaded {
contentNode.layout() contentNode.layout()
contentNode.animateIn(from: fromState) contentNode.animateIn(from: fromState, delay: delay)
} }
} }
if backgroundColor != nil {
strongSelf.transitionToBackgroundColor(backgroundColor, previousContentNode: previousContentNode, animated: animated, completion: completion)
}
})
if backgroundColor == nil {
strongSelf.transitionToBackgroundColor(backgroundColor, previousContentNode: previousContentNode, animated: animated, completion: completion) strongSelf.transitionToBackgroundColor(backgroundColor, previousContentNode: previousContentNode, animated: animated, completion: completion)
} })
} else { } else {
previousContentNode.removeFromSupernode() previousContentNode.removeFromSupernode()
strongSelf.contentNode = strongSelf.nextContentNode strongSelf.contentNode = strongSelf.nextContentNode

View File

@ -96,8 +96,8 @@ final class RadialStatusSecretTimeoutContentNode: RadialStatusContentNode {
}) })
} }
override func animateIn(from: RadialStatusNodeState) { override func animateIn(from: RadialStatusNodeState, delay: Double) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15) self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
} }
override func willEnterHierarchy() { override func willEnterHierarchy() {

View File

@ -388,7 +388,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
} }
if self.theme != theme { if self.theme != theme {
self.backgroundNode.backgroundColor = theme.background self.backgroundNode.backgroundColor = theme.background
if fieldStyle != .modern { if self.fieldStyle != .modern {
self.separatorNode.backgroundColor = theme.separator self.separatorNode.backgroundColor = theme.separator
} }
self.textBackgroundNode.image = generateBackground(foregroundColor: theme.inputFill, diameter: self.fieldStyle.cornerDiameter) self.textBackgroundNode.image = generateBackground(foregroundColor: theme.inputFill, diameter: self.fieldStyle.cornerDiameter)

View File

@ -100,7 +100,6 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource))) convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource)))
} }
let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0) let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0)
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .standalone(resource: file.file.resource)))
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, fileReference: .standalone(media: file.file), representations: convertedRepresentations, autoFetchFullSize: true)) self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, fileReference: .standalone(media: file.file), representations: convertedRepresentations, autoFetchFullSize: true))
let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets())) let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
apply() apply()
@ -116,13 +115,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: largestImageRepresentation(representations)!.dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets())) let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: largestImageRepresentation(representations)!.dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
apply() apply()
case let .file(file): case let .file(file):
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource)))
}
let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0) let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0)
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .standalone(resource: file.file.resource)))
self.imageNode.setSignal(chatAvatarGalleryPhoto(account: account, fileReference: .standalone(media: file.file), representations: convertedRepresentations, autoFetchFullSize: true))
let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets())) let apply = self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: dimensions.aspectFilled(size), boundingSize: size, intrinsicInsets: UIEdgeInsets()))
apply() apply()
} }

View File

@ -112,9 +112,9 @@ private final class SystemVideoContentNode: ASDisplayNode, UniversalVideoContent
} }
self.player.addObserver(self, forKeyPath: "rate", options: [], context: nil) self.player.addObserver(self, forKeyPath: "rate", options: [], context: nil)
playerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil) self.playerItem.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil) self.playerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
playerItem.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil) self.playerItem.addObserver(self, forKeyPath: "playbackBufferFull", options: .new, context: nil)
self._bufferingStatus.set(.single(nil)) self._bufferingStatus.set(.single(nil))
} }

View File

@ -76,20 +76,18 @@ public final class TelegramRootController: NavigationController {
self.rootTabController = tabBarController self.rootTabController = tabBarController
self.pushViewController(tabBarController, animated: false) self.pushViewController(tabBarController, animated: false)
///TESTBED // guard let controller = self.viewControllers.last as? ViewController else {
// return
guard let controller = self.viewControllers.last as? ViewController else { // }
return //
} // DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.15) {
// //(controller.navigationController as? NavigationController)?.pushViewController(ThemeGridController(account: self.account))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.15) { //
//(controller.navigationController as? NavigationController)?.pushViewController(ThemeGridController(account: self.account))
// let wrapperNode = ASDisplayNode() // let wrapperNode = ASDisplayNode()
// let bounds = controller.displayNode.bounds // let bounds = controller.displayNode.bounds
// wrapperNode.frame = bounds // wrapperNode.frame = bounds
// wrapperNode.backgroundColor = .gray // wrapperNode.backgroundColor = .gray
// //controller.displayNode.addSubnode(wrapperNode) // controller.displayNode.addSubnode(wrapperNode)
// //
// let radialStatusSize: CGFloat = 50.0 // let radialStatusSize: CGFloat = 50.0
// let statusNode = RadialStatusNode(backgroundNodeColor: UIColor(rgb: 0x000000, alpha: 0.6)) // let statusNode = RadialStatusNode(backgroundNodeColor: UIColor(rgb: 0x000000, alpha: 0.6))
@ -107,16 +105,21 @@ public final class TelegramRootController: NavigationController {
// smth = false // smth = false
// //statusNode.transitionToState(.play(color), animated: true, completion: {}) // //statusNode.transitionToState(.play(color), animated: true, completion: {})
// statusNode.transitionToState(.download(.white), animated: true, completion: {}) // statusNode.transitionToState(.download(.white), animated: true, completion: {})
// //statusNode.transitionToState(.none, animated: true, completion: {}) //// statusNode.transitionToState(.progress(color: color, lineWidth: nil, value: 1.0, cancelEnabled: true), animated: true, completion: {})
//// statusNode.transitionToState(.none, animated: true, completion: {
//// DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.85) {
//// statusNode.transitionToState(.download(.white), animated: true, completion: {})
//// }
//// })
// } else { // } else {
// smth = true // smth = true
// statusNode.transitionToState(.progress(color: color, lineWidth: nil, value: 0.3, cancelEnabled: true), animated: true, completion: {}) // statusNode.transitionToState(.progress(color: color, lineWidth: nil, value: 0.1, cancelEnabled: true), animated: true, completion: {})
// } // }
// } // }
// } // }
// button.addTarget(self, action: #selector(self.mock), forControlEvents: .touchUpInside) // button.addTarget(self, action: #selector(self.mock), forControlEvents: .touchUpInside)
// statusNode.transitionToState(.download(.white), animated: false, completion: {}) // statusNode.transitionToState(.download(.white), animated: false, completion: {})
} // }
} }
@objc func mock() { @objc func mock() {

View File

@ -220,7 +220,7 @@ class ThemeGalleryController: ViewController {
wallpaper = value wallpaper = value
} }
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperMode: .still, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: [], theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}) |> deliverOnMainQueue).start(completed: { }) |> deliverOnMainQueue).start(completed: {
self?.dismiss(forceAway: true) self?.dismiss(forceAway: true)
}) })

View File

@ -103,6 +103,8 @@ final class ThemeGridController: ViewController {
override func loadDisplayNode() { override func loadDisplayNode() {
self.displayNode = ThemeGridControllerNode(account: self.account, presentationData: self.presentationData, presentPreviewController: { [weak self] source in self.displayNode = ThemeGridControllerNode(account: self.account, presentationData: self.presentationData, presentPreviewController: { [weak self] source in
if let strongSelf = self { if let strongSelf = self {
//let controller = WallpaperGalleryController(account: strongSelf.account, source: source)
//self?.present(controller, in: .window(.root), with: nil, blockInteraction: true)
let controller = WallpaperListPreviewController(account: strongSelf.account, source: source) let controller = WallpaperListPreviewController(account: strongSelf.account, source: source)
controller.apply = { [weak self, weak controller] wallpaper, mode, cropRect in controller.apply = { [weak self, weak controller] wallpaper, mode, cropRect in
if let strongSelf = self { if let strongSelf = self {
@ -236,7 +238,7 @@ final class ThemeGridController: ViewController {
self.displayNodeDidLoad() self.displayNodeDidLoad()
} }
private func uploadCustomWallpaper(_ wallpaper: WallpaperEntry, mode: PresentationWallpaperMode, cropRect: CGRect?) { private func uploadCustomWallpaper(_ wallpaper: WallpaperEntry, mode: WallpaperPresentationOptions, cropRect: CGRect?) {
let imageSignal: Signal<UIImage, NoError> let imageSignal: Signal<UIImage, NoError>
switch wallpaper { switch wallpaper {
case .wallpaper: case .wallpaper:
@ -305,7 +307,7 @@ final class ThemeGridController: ViewController {
let account = self.account let account = self.account
let updateWallpaper: (TelegramWallpaper) -> Void = { wallpaper in let updateWallpaper: (TelegramWallpaper) -> Void = { wallpaper in
let _ = (updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in let _ = (updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperMode: mode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: mode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
})).start() })).start()
} }
@ -315,7 +317,7 @@ final class ThemeGridController: ViewController {
let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in let _ = uploadWallpaper(account: account, resource: resource).start(next: { status in
if case let .complete(wallpaper) = status { if case let .complete(wallpaper) = status {
if case .blurred = mode, case let .file(_, _, _, _, file, _) = wallpaper { if mode.contains(.blur), case let .file(_, _, _, _, file, _) = wallpaper {
let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: { let _ = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
updateWallpaper(wallpaper) updateWallpaper(wallpaper)
}) })
@ -326,7 +328,7 @@ final class ThemeGridController: ViewController {
}) })
} }
if case .blurred = mode { if mode.contains(.blur) {
let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: { let _ = account.postbox.mediaBox.cachedResourceRepresentation(resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true).start(completed: {
completion() completion()
}) })

View File

@ -121,7 +121,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
private var presentationData: PresentationData private var presentationData: PresentationData
private var controllerInteraction: ThemeGridControllerInteraction? private var controllerInteraction: ThemeGridControllerInteraction?
private let presentPreviewController: (WallpaperListPreviewSource) -> Void private let presentPreviewController: (WallpaperListSource) -> Void
private let presentGallery: () -> Void private let presentGallery: () -> Void
private let presentColors: () -> Void private let presentColors: () -> Void
private let emptyStateUpdated: (Bool) -> Void private let emptyStateUpdated: (Bool) -> Void
@ -161,7 +161,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
private var disposable: Disposable? private var disposable: Disposable?
init(account: Account, presentationData: PresentationData, presentPreviewController: @escaping (WallpaperListPreviewSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, popViewController: @escaping () -> Void) { init(account: Account, presentationData: PresentationData, presentPreviewController: @escaping (WallpaperListSource) -> Void, presentGallery: @escaping () -> Void, presentColors: @escaping () -> Void, emptyStateUpdated: @escaping (Bool) -> Void, deleteWallpapers: @escaping ([TelegramWallpaper], @escaping () -> Void) -> Void, shareWallpapers: @escaping ([TelegramWallpaper]) -> Void, popViewController: @escaping () -> Void) {
self.account = account self.account = account
self.presentationData = presentationData self.presentationData = presentationData
self.presentPreviewController = presentPreviewController self.presentPreviewController = presentPreviewController
@ -217,7 +217,7 @@ final class ThemeGridControllerNode: ASDisplayNode {
if let entries = entries, !entries.isEmpty { if let entries = entries, !entries.isEmpty {
let wallpapers = entries.map { $0.wallpaper } let wallpapers = entries.map { $0.wallpaper }
var mode: PresentationWallpaperMode? var mode: WallpaperPresentationOptions?
if wallpaper == strongSelf.presentationData.chatWallpaper { if wallpaper == strongSelf.presentationData.chatWallpaper {
mode = strongSelf.presentationData.chatWallpaperMode mode = strongSelf.presentationData.chatWallpaperMode
} }

View File

@ -13,11 +13,11 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem {
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
let fontSize: PresentationFontSize let fontSize: PresentationFontSize
let wallpaper: TelegramWallpaper let wallpaper: TelegramWallpaper
let wallpaperMode: PresentationWallpaperMode let wallpaperMode: WallpaperPresentationOptions
let dateTimeFormat: PresentationDateTimeFormat let dateTimeFormat: PresentationDateTimeFormat
let nameDisplayOrder: PresentationPersonNameOrder let nameDisplayOrder: PresentationPersonNameOrder
init(account: Account, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, wallpaperMode: PresentationWallpaperMode, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) { init(account: Account, theme: PresentationTheme, componentTheme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, fontSize: PresentationFontSize, wallpaper: TelegramWallpaper, wallpaperMode: WallpaperPresentationOptions, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) {
self.account = account self.account = account
self.theme = theme self.theme = theme
self.componentTheme = componentTheme self.componentTheme = componentTheme
@ -139,7 +139,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
}) })
case let .image(representations): case let .image(representations):
if let largest = largestImageRepresentation(representations) { if let largest = largestImageRepresentation(representations) {
if case .blurred = item.wallpaperMode { if item.wallpaperMode.contains(.blur) {
var image: UIImage? var image: UIImage?
let _ = item.account.postbox.mediaBox.cachedResourceRepresentation(largest.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in let _ = item.account.postbox.mediaBox.cachedResourceRepresentation(largest.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in
if data.complete { if data.complete {
@ -153,7 +153,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
} }
} }
case let .file(file): case let .file(file):
if case .blurred = item.wallpaperMode { if item.wallpaperMode.contains(.blur) {
var image: UIImage? var image: UIImage?
let _ = item.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in let _ = item.account.postbox.mediaBox.cachedResourceRepresentation(file.file.resource, representation: CachedBlurredWallpaperRepresentation(), complete: true, fetch: true, attemptSynchronously: true).start(next: { data in
if data.complete { if data.complete {

View File

@ -35,7 +35,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
case fontSizeHeader(PresentationTheme, String) case fontSizeHeader(PresentationTheme, String)
case fontSize(PresentationTheme, PresentationFontSize) case fontSize(PresentationTheme, PresentationFontSize)
case chatPreviewHeader(PresentationTheme, String) case chatPreviewHeader(PresentationTheme, String)
case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, PresentationWallpaperMode, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder) case chatPreview(PresentationTheme, PresentationTheme, TelegramWallpaper, WallpaperPresentationOptions, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder)
case wallpaper(PresentationTheme, String) case wallpaper(PresentationTheme, String)
case accentColor(PresentationTheme, String, Int32) case accentColor(PresentationTheme, String, Int32)
case autoNightTheme(PresentationTheme, String, String) case autoNightTheme(PresentationTheme, String, String)
@ -210,7 +210,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
} }
} }
private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, wallpaperMode: PresentationWallpaperMode, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> [ThemeSettingsControllerEntry] { private func themeSettingsControllerEntries(presentationData: PresentationData, theme: PresentationTheme, themeAccentColor: Int32?, autoNightSettings: AutomaticThemeSwitchSetting, strings: PresentationStrings, wallpaper: TelegramWallpaper, wallpaperMode: WallpaperPresentationOptions, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, disableAnimations: Bool) -> [ThemeSettingsControllerEntry] {
var entries: [ThemeSettingsControllerEntry] = [] var entries: [ThemeSettingsControllerEntry] = []
entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize)) entries.append(.fontSizeHeader(presentationData.theme, strings.Appearance_TextSize))
@ -270,25 +270,25 @@ public func themeSettingsController(account: Account) -> ViewController {
wallpaper = .color(0x18222D) wallpaper = .color(0x18222D)
theme = .builtin(.nightAccent) theme = .builtin(.nightAccent)
} }
return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperMode: .still, theme: theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: [], theme: theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start() }).start()
}, selectFontSize: { size in }, selectFontSize: { size in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperMode: current.chatWallpaperMode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: size, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperOptions: current.chatWallpaperOptions, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: size, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start() }).start()
}, openWallpaperSettings: { }, openWallpaperSettings: {
pushControllerImpl?(ThemeGridController(account: account)) pushControllerImpl?(ThemeGridController(account: account))
}, openAccentColor: { color in }, openAccentColor: { color in
presentControllerImpl?(ThemeAccentColorActionSheet(account: account, currentValue: color, applyValue: { color in presentControllerImpl?(ThemeAccentColorActionSheet(account: account, currentValue: color, applyValue: { color in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperMode: current.chatWallpaperMode, theme: current.theme, themeAccentColor: color, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperOptions: current.chatWallpaperOptions, theme: current.theme, themeAccentColor: color, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}).start() }).start()
})) }))
}, openAutoNightTheme: { }, openAutoNightTheme: {
pushControllerImpl?(themeAutoNightSettingsController(account: account)) pushControllerImpl?(themeAutoNightSettingsController(account: account))
}, disableAnimations: { disabled in }, disableAnimations: { disabled in
let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in let _ = updatePresentationThemeSettingsInteractively(postbox: account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperMode: current.chatWallpaperMode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: disabled) return PresentationThemeSettings(chatWallpaper: current.chatWallpaper, chatWallpaperOptions: current.chatWallpaperOptions, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: disabled)
}).start() }).start()
}) })
@ -304,7 +304,7 @@ public func themeSettingsController(account: Account) -> ViewController {
let theme: PresentationTheme let theme: PresentationTheme
let fontSize: PresentationFontSize let fontSize: PresentationFontSize
let wallpaper: TelegramWallpaper let wallpaper: TelegramWallpaper
let wallpaperMode: PresentationWallpaperMode let wallpaperMode: WallpaperPresentationOptions
let strings: PresentationStrings let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat let dateTimeFormat: PresentationDateTimeFormat
let disableAnimations: Bool let disableAnimations: Bool
@ -324,7 +324,7 @@ public func themeSettingsController(account: Account) -> ViewController {
} }
} }
wallpaper = settings.chatWallpaper wallpaper = settings.chatWallpaper
wallpaperMode = settings.chatWallpaperMode wallpaperMode = settings.chatWallpaperOptions
fontSize = settings.fontSize fontSize = settings.fontSize
if let localizationSettings = preferences.values[localizationSettingsKey] as? LocalizationSettings { if let localizationSettings = preferences.values[localizationSettingsKey] as? LocalizationSettings {

View File

@ -291,11 +291,19 @@ final class WallpaperColorPickerNode: ASDisplayNode {
return return
} }
let location = recognizer.location(in: recognizer.view)
let transition = recognizer.translation(in: recognizer.view) let transition = recognizer.translation(in: recognizer.view)
let newHue = max(0.0, min(1.0, self.colorHSV.0 + transition.x / size.width)) if recognizer.state == .began {
let newSaturation = max(0.0, min(1.0, self.colorHSV.1 - transition.y / (size.height - 66.0))) let newHue = max(0.0, min(1.0, location.x / size.width))
self.colorHSV.0 = newHue let newSaturation = max(0.0, min(1.0, (1.0 - location.y / (size.height - 66.0))))
self.colorHSV.1 = newSaturation self.colorHSV.0 = newHue
self.colorHSV.1 = newSaturation
} else {
let newHue = max(0.0, min(1.0, self.colorHSV.0 + transition.x / size.width))
let newSaturation = max(0.0, min(1.0, self.colorHSV.1 - transition.y / (size.height - 66.0)))
self.colorHSV.0 = newHue
self.colorHSV.1 = newSaturation
}
switch recognizer.state { switch recognizer.state {
case .began: case .began:

View File

@ -0,0 +1,302 @@
import Foundation
import Display
import QuickLook
import Postbox
import SwiftSignalKit
import AsyncDisplayKit
import TelegramCore
import Photos
enum WallpaperListType {
case wallpapers(WallpaperPresentationOptions?)
case colors
}
enum WallpaperListSource {
case list(wallpapers: [TelegramWallpaper], central: TelegramWallpaper, type: WallpaperListType)
case wallpaper(TelegramWallpaper)
case slug(String, TelegramMediaFile?)
case asset(PHAsset, UIImage?)
case contextResult(ChatContextResult)
case customColor(Int32?)
}
enum WallpaperGalleryEntry: Equatable {
case wallpaper(TelegramWallpaper)
case asset(PHAsset, UIImage?)
case contextResult(ChatContextResult)
public static func ==(lhs: WallpaperGalleryEntry, rhs: WallpaperGalleryEntry) -> Bool {
switch lhs {
case let .wallpaper(wallpaper):
if case .wallpaper(wallpaper) = rhs {
return true
} else {
return false
}
case let .asset(lhsAsset, _):
if case let .asset(rhsAsset, _) = rhs, lhsAsset.localIdentifier == rhsAsset.localIdentifier {
return true
} else {
return false
}
case let .contextResult(lhsResult):
if case let .contextResult(rhsResult) = rhs, lhsResult.id == rhsResult.id {
return true
} else {
return false
}
}
}
}
class WallpaperGalleryController: ViewController {
private var galleryNode: GalleryControllerNode {
return self.displayNode as! GalleryControllerNode
}
private let account: Account
private let source: WallpaperListSource
var apply: ((WallpaperEntry, WallpaperPresentationOptions, CGRect?) -> Void)?
private let _ready = Promise<Bool>()
override var ready: Promise<Bool> {
return self._ready
}
private var didSetReady = false
private let disposable = MetaDisposable()
private var presentationData: PresentationData
private var presentationDataDisposable: Disposable?
private var entries: [WallpaperGalleryEntry] = []
private var centralEntryIndex: Int?
private let centralItemControlsColor = Promise<UIColor>()
private let centralItemStatus = Promise<MediaResourceStatus>()
private let centralItemAttributesDisposable = DisposableSet();
private var validLayout: (ContainerViewLayout, CGFloat)?
private var toolbarNode: ThemeGalleryToolbarNode?
init(account: Account, source: WallpaperListSource) {
self.account = account
self.source = source
self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
self.title = self.presentationData.strings.Wallpaper_Title
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
switch source {
case let .list(wallpapers, central, type):
self.entries = wallpapers.map { .wallpaper($0) }
self.centralEntryIndex = wallpapers.index(of: central)!
//if case let .wallpapers(wallpaperMode) = type, let mode = wallpaperMode {
// self.segmentedControl.selectedSegmentIndex = Int(clamping: mode.rawValue)
//}
case let .slug(slug, file):
if let file = file {
self.entries = [.wallpaper(.file(id: 0, accessHash: 0, isCreator: false, slug: slug, file: file, color: nil))]
self.centralEntryIndex = 0
}
case let .wallpaper(wallpaper):
self.entries = [.wallpaper(wallpaper)]
self.centralEntryIndex = 0
case let .asset(asset, thumbnailImage):
self.entries = [.asset(asset, thumbnailImage)]
self.centralEntryIndex = 0
case let .contextResult(result):
self.entries = [.contextResult(result)]
self.centralEntryIndex = 0
case let .customColor(color):
let initialColor = color ?? 0x000000
self.entries = [.wallpaper(.color(initialColor))]
self.centralEntryIndex = 0
}
// let initialEntries: [ThemeGalleryEntry] = wallpapers.map { ThemeGalleryEntry.wallpaper($0) }
// let entriesSignal: Signal<[ThemeGalleryEntry], NoError> = .single(initialEntries)
//
// self.disposable.set((entriesSignal |> deliverOnMainQueue).start(next: { [weak self] entries in
// if let strongSelf = self {
// strongSelf.entries = entries
// strongSelf.centralEntryIndex = wallpapers.index(of: centralWallpaper)!
// if strongSelf.isViewLoaded {
// strongSelf.galleryNode.pager.replaceItems(strongSelf.entries.map({ ThemeGalleryItem(account: account, entry: $0) }), centralItemIndex: strongSelf.centralEntryIndex, keepFirst: true)
//
// let ready = strongSelf.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak strongSelf] _ in
// strongSelf?.didSetReady = true
// }
// strongSelf._ready.set(ready |> map { true })
// }
// }
// }))
self.presentationDataDisposable = (account.telegramApplicationContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
let previousTheme = strongSelf.presentationData.theme
let previousStrings = strongSelf.presentationData.strings
strongSelf.presentationData = presentationData
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
strongSelf.updateThemeAndStrings()
}
}
})
//self.centralItemAttributesDisposable.add(self.centralItemTitleView.get().start(next: { [weak self] titleView in
// self?.navigationItem.titleView = titleView
//}))
// self.centralItemAttributesDisposable.add(self.centralItemFooterContentNode.get().start(next: { [weak self] footerContentNode in
// self?.galleryNode.updatePresentationState({
// $0.withUpdatedFooterContentNode(footerContentNode)
// }, transition: .immediate)
// }))
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.disposable.dispose()
self.presentationDataDisposable?.dispose()
self.centralItemAttributesDisposable.dispose()
}
private func updateThemeAndStrings() {
self.title = self.presentationData.strings.Wallpaper_Title
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style
self.toolbarNode?.updateThemeAndStrings(theme: self.presentationData.theme, strings: self.presentationData.strings)
}
@objc func donePressed() {
self.dismiss(forceAway: false)
}
private func dismiss(forceAway: Bool) {
let completion = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
//self.galleryNode.modalAnimateOut(completion: completion)
}
override func loadDisplayNode() {
let controllerInteraction = GalleryControllerInteraction(presentController: { [weak self] controller, arguments in
if let strongSelf = self {
strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
}
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { controller, ready in
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction, pageGap: 0.0)
self.displayNodeDidLoad()
self.galleryNode.statusBar = self.statusBar
self.galleryNode.navigationBar = self.navigationBar
self.galleryNode.transitionDataForCentralItem = { [weak self] in
// if let strongSelf = self {
// if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? ThemePreviewControllerPresentationArguments {
// if let transitionArguments = presentationArguments.transitionArguments(strongSelf.entries[centralItemNode.index]) {
// return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
// }
// }
// }
return nil
}
self.galleryNode.dismiss = { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
}
self.galleryNode.pager.centralItemIndexUpdated = { [weak self] index in
if let strongSelf = self {
if let index = index {
if let node = strongSelf.galleryNode.pager.centralItemNode() {
//strongSelf.centralItemTitle.set(node.title())
}
}
}
}
self.galleryNode.backgroundNode.backgroundColor = nil
self.galleryNode.backgroundNode.isOpaque = false
self.galleryNode.isBackgroundExtendedOverNavigationBar = true
let presentationData = self.account.telegramApplicationContext.currentPresentationData.with { $0 }
let toolbarNode = ThemeGalleryToolbarNode(theme: presentationData.theme, strings: presentationData.strings)
self.toolbarNode = toolbarNode
self.galleryNode.addSubnode(toolbarNode)
self.galleryNode.toolbarNode = toolbarNode
toolbarNode.cancel = { [weak self] in
//self?.dismiss(forceAway: true)
}
toolbarNode.done = { [weak self] in
// if let strongSelf = self {
// if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode() {
// if !strongSelf.entries.isEmpty {
// let wallpaper: TelegramWallpaper
// switch strongSelf.entries[centralItemNode.index] {
// case let .wallpaper(value):
// wallpaper = value
// }
// let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
// return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: [], theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
// }) |> deliverOnMainQueue).start(completed: {
// self?.dismiss(forceAway: true)
// })
// }
// }
// }
}
let ready = self.galleryNode.pager.ready() |> timeout(2.0, queue: Queue.mainQueue(), alternate: .single(Void())) |> afterNext { [weak self] _ in
self?.didSetReady = true
}
self._ready.set(ready |> map { true })
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.galleryNode.modalAnimateIn()
}
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.galleryNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.galleryNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
transition.updateFrame(node: self.toolbarNode!, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - 49.0 - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width, height: 49.0 + layout.intrinsicInsets.bottom)))
self.toolbarNode!.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
let replace = self.validLayout == nil
self.validLayout = (layout, 0.0)
if replace {
self.galleryNode.pager.replaceItems(self.entries.map({ WallpaperGalleryItem(account: self.account, entry: $0) }), centralItemIndex: self.centralEntryIndex)
}
}
}
private extension GalleryControllerNode {
func modalAnimateIn(completion: (() -> Void)? = nil) {
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
}
func modalAnimateOut(completion: (() -> Void)? = nil) {
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { _ in
completion?()
})
}
}

View File

@ -0,0 +1,369 @@
import Foundation
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import LegacyComponents
class WallpaperGalleryItem: GalleryItem {
let account: Account
let entry: WallpaperGalleryEntry
init(account: Account, entry: WallpaperGalleryEntry) {
self.account = account
self.entry = entry
}
func node() -> GalleryItemNode {
let node = WallpaperGalleryItemNode(account: self.account)
node.setEntry(self.entry)
return node
}
func updateNode(node: GalleryItemNode) {
if let node = node as? WallpaperGalleryItemNode {
node.setEntry(self.entry)
}
}
func thumbnailItem() -> (Int64, GalleryThumbnailItem)? {
return nil
}
}
let progressDiameter: CGFloat = 50.0
final class WallpaperGalleryItemNode: GalleryItemNode {
private let account: Account
private var entry: WallpaperGalleryEntry?
private var contentSize: CGSize?
let wrapperNode: ASDisplayNode
let imageNode: TransformImageNode
private let statusNode: RadialStatusNode
private let blurredNode: BlurredImageNode
let cropNode: WallpaperCropNode
fileprivate let _ready = Promise<Void>()
private let fetchDisposable = MetaDisposable()
private let statusDisposable = MetaDisposable()
let controlsColor = Promise<UIColor>(.white)
let status = Promise<MediaResourceStatus>(.Local)
init(account: Account) {
self.account = account
self.wrapperNode = ASDisplayNode()
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = .subsequentUpdates
self.cropNode = WallpaperCropNode()
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
self.statusNode.isUserInteractionEnabled = false
self.blurredNode = BlurredImageNode()
super.init()
self.clipsToBounds = true
self.backgroundColor = .black
self.imageNode.imageUpdated = { [weak self] _ in
self?._ready.set(.single(Void()))
}
self.imageNode.view.contentMode = .scaleAspectFill
self.imageNode.clipsToBounds = true
self.addSubnode(self.wrapperNode)
self.addSubnode(self.statusNode)
}
deinit {
self.fetchDisposable.dispose()
self.statusDisposable.dispose()
}
var cropRect: CGRect? {
guard let entry = self.entry else {
return nil
}
switch entry {
case .asset, .contextResult:
return self.cropNode.cropRect
default:
return nil
}
}
override func ready() -> Signal<Void, NoError> {
return self._ready.get()
}
fileprivate func setEntry(_ entry: WallpaperGalleryEntry) {
if self.entry != entry {
self.entry = entry
let signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>
let fetchSignal: Signal<FetchResourceSourceType, FetchResourceError>
let statusSignal: Signal<MediaResourceStatus, NoError>
let displaySize: CGSize
let contentSize: CGSize
switch entry {
case let .wallpaper(wallpaper):
switch wallpaper {
case .builtin:
displaySize = CGSize(width: 640.0, height: 1136.0)
contentSize = displaySize
signal = settingsBuiltinWallpaperImage(account: account)
fetchSignal = .complete()
statusSignal = .single(.Local)
case let .color(color):
displaySize = CGSize(width: 1.0, height: 1.0)
contentSize = displaySize
signal = .never()
fetchSignal = .complete()
statusSignal = .single(.Local)
self.backgroundColor = UIColor(rgb: UInt32(bitPattern: color))
case let .file(file):
let dimensions = file.file.dimensions ?? CGSize(width: 100.0, height: 100.0)
contentSize = dimensions
displaySize = dimensions.dividedByScreenScale().integralFloor
var convertedRepresentations: [ImageRepresentationWithReference] = []
for representation in file.file.previewRepresentations {
convertedRepresentations.append(ImageRepresentationWithReference(representation: representation, reference: .standalone(resource: representation.resource)))
}
convertedRepresentations.append(ImageRepresentationWithReference(representation: .init(dimensions: dimensions, resource: file.file.resource), reference: .standalone(resource: file.file.resource)))
signal = chatMessageImageFile(account: account, fileReference: .standalone(media: file.file), thumbnail: false)
fetchSignal = fetchedMediaResource(postbox: account.postbox, reference: convertedRepresentations[convertedRepresentations.count - 1].reference)
statusSignal = account.postbox.mediaBox.resourceStatus(file.file.resource)
case let .image(representations):
if let largestSize = largestImageRepresentation(representations) {
contentSize = largestSize.dimensions
displaySize = largestSize.dimensions.dividedByScreenScale().integralFloor
let convertedRepresentations: [ImageRepresentationWithReference] = representations.map({ ImageRepresentationWithReference(representation: $0, reference: .wallpaper(resource: $0.resource)) })
signal = chatAvatarGalleryPhoto(account: account, representations: convertedRepresentations)
if let largestIndex = convertedRepresentations.index(where: { $0.representation == largestSize }) {
fetchSignal = fetchedMediaResource(postbox: account.postbox, reference: convertedRepresentations[largestIndex].reference)
} else {
fetchSignal = .complete()
}
statusSignal = account.postbox.mediaBox.resourceStatus(largestSize.resource)
} else {
displaySize = CGSize(width: 1.0, height: 1.0)
contentSize = displaySize
signal = .never()
fetchSignal = .complete()
statusSignal = .single(.Local)
}
}
self.cropNode.removeFromSupernode()
case let .asset(asset, _):
let dimensions = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
contentSize = dimensions
displaySize = dimensions.dividedByScreenScale().integralFloor
signal = photoWallpaper(postbox: account.postbox, photoLibraryResource: PhotoLibraryMediaResource(localIdentifier: asset.localIdentifier, uniqueId: arc4random64()))
fetchSignal = .complete()
statusSignal = .single(.Local)
self.wrapperNode.addSubnode(self.cropNode)
case let .contextResult(result):
var imageDimensions: CGSize?
var imageResource: TelegramMediaResource?
var thumbnailDimensions: CGSize?
var thumbnailResource: TelegramMediaResource?
switch result {
case let .externalReference(_, _, _, _, _, _, content, thumbnail, _):
if let content = content {
imageResource = content.resource
}
if let thumbnail = thumbnail {
thumbnailResource = thumbnail.resource
thumbnailDimensions = thumbnail.dimensions
}
if let dimensions = content?.dimensions {
imageDimensions = dimensions
}
case let .internalReference(_, _, _, _, _, image, _, _):
if let image = image {
if let imageRepresentation = imageRepresentationLargerThan(image.representations, size: CGSize(width: 1000.0, height: 800.0)) {
imageDimensions = imageRepresentation.dimensions
imageResource = imageRepresentation.resource
}
if let thumbnailRepresentation = imageRepresentationLargerThan(image.representations, size: CGSize(width: 200.0, height: 100.0)) {
thumbnailDimensions = thumbnailRepresentation.dimensions
thumbnailResource = thumbnailRepresentation.resource
}
}
}
if let imageResource = imageResource, let imageDimensions = imageDimensions {
contentSize = imageDimensions
displaySize = imageDimensions.dividedByScreenScale().integralFloor
var representations: [TelegramMediaImageRepresentation] = []
if let thumbnailResource = thumbnailResource, let thumbnailDimensions = thumbnailDimensions {
representations.append(TelegramMediaImageRepresentation(dimensions: thumbnailDimensions, resource: thumbnailResource))
}
representations.append(TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: imageResource))
let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: representations, immediateThumbnailData: nil, reference: nil, partialReference: nil)
signal = chatMessagePhoto(postbox: account.postbox, photoReference: .standalone(media: tmpImage))
fetchSignal = fetchedMediaResource(postbox: account.postbox, reference: .media(media: .standalone(media: tmpImage), resource: imageResource))
statusSignal = account.postbox.mediaBox.resourceStatus(imageResource)
} else {
displaySize = CGSize(width: 1.0, height: 1.0)
contentSize = displaySize
signal = .never()
fetchSignal = .complete()
statusSignal = .single(.Local)
}
self.wrapperNode.addSubnode(self.cropNode)
}
self.contentSize = contentSize
if self.cropNode.supernode == nil {
self.imageNode.contentMode = .scaleAspectFill
self.wrapperNode.addSubnode(self.imageNode)
} else {
self.imageNode.contentMode = .scaleToFill
}
let imagePromise = Promise<UIImage?>()
self.imageNode.setSignal(signal, dispatchOnDisplayLink: false)
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
self.imageNode.imageUpdated = { [weak self] image in
if let strongSelf = self {
var image = image
if let scaledImage = image {
if scaledImage.size.width > 2048.0 || scaledImage.size.height > 2048.0 {
image = TGScaleImageToPixelSize(image, scaledImage.size.fitted(CGSize(width: 2048.0, height: 2048.0)))
}
}
strongSelf.blurredNode.image = image
imagePromise.set(.single(image))
}
}
self.fetchDisposable.set(fetchSignal.start())
let statusForegroundColor = UIColor.white
self.statusDisposable.set((statusSignal
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self {
let state: RadialStatusNodeState
switch status {
case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027)
state = .progress(color: statusForegroundColor, lineWidth: nil, value: CGFloat(adjustedProgress), cancelEnabled: false)
case .Local:
state = .none
case .Remote:
state = .progress(color: statusForegroundColor, lineWidth: nil, value: 0.027, cancelEnabled: false)
}
strongSelf.statusNode.transitionToState(state, completion: {})
}
}))
let controlsColorSignal: Signal<UIColor, NoError>
if case let .wallpaper(wallpaper) = entry {
controlsColorSignal = chatBackgroundContrastColor(wallpaper: wallpaper, postbox: account.postbox)
} else {
controlsColorSignal = backgroundContrastColor(for: imagePromise.get())
}
self.controlsColor.set(.single(.white) |> then(controlsColorSignal))
self.status.set(statusSignal)
}
}
func setParallaxEnabled(_ enabled: Bool) {
if enabled {
let amount = 24.0
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -amount
horizontal.maximumRelativeValue = amount
let vertical = UIInterpolatingMotionEffect(keyPath: "center.y", type: .tiltAlongVerticalAxis)
vertical.minimumRelativeValue = -amount
vertical.maximumRelativeValue = amount
let group = UIMotionEffectGroup()
group.motionEffects = [horizontal, vertical]
self.wrapperNode.view.addMotionEffect(group)
} else {
for effect in self.imageNode.view.motionEffects {
self.wrapperNode.view.removeMotionEffect(effect)
}
}
}
func setBlurEnabled(_ enabled: Bool, animated: Bool) {
let blurRadius: CGFloat = 45.0
if enabled {
if self.blurredNode.supernode == nil {
if self.cropNode.supernode != nil {
self.blurredNode.frame = self.imageNode.bounds
self.imageNode.addSubnode(self.blurredNode)
} else {
self.blurredNode.frame = self.imageNode.frame
self.addSubnode(self.blurredNode)
}
}
if animated {
self.blurredNode.blurView.blurRadius = 0.0
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions(rawValue: 7 << 16), animations: {
self.blurredNode.blurView.blurRadius = blurRadius
}, completion: nil)
} else {
self.blurredNode.blurView.blurRadius = blurRadius
}
} else {
if self.blurredNode.supernode != nil {
if animated {
UIView.animate(withDuration: 0.3, delay: 0.0, options: UIViewAnimationOptions(rawValue: 7 << 16), animations: {
self.blurredNode.blurView.blurRadius = 0.0
}, completion: { finished in
if finished {
self.blurredNode.removeFromSupernode()
}
})
} else {
self.blurredNode.removeFromSupernode()
}
}
}
}
override func visibilityUpdated(isVisible: Bool) {
super.visibilityUpdated(isVisible: isVisible)
}
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
self.wrapperNode.frame = CGRect(origin: CGPoint(), size: layout.size)
if self.cropNode.supernode == nil {
self.imageNode.frame = self.wrapperNode.bounds
self.blurredNode.frame = self.imageNode.frame
} else {
self.cropNode.frame = self.wrapperNode.bounds
self.cropNode.containerLayoutUpdated(layout, transition: transition)
if self.cropNode.supernode != nil, let contentSize = self.contentSize, self.cropNode.zoomableContent == nil {
let fittedSize = TGScaleToFit(self.cropNode.bounds.size, contentSize)
self.cropNode.zoomableContent = (contentSize, self.imageNode)
self.cropNode.zoom(to: CGRect(x: (contentSize.width - fittedSize.width) / 2.0, y: (contentSize.height - fittedSize.height) / 2.0, width: fittedSize.width, height: fittedSize.height))
}
self.blurredNode.frame = self.imageNode.bounds
}
self.statusNode.frame = CGRect(x: layout.safeInsets.left + floorToScreenPixels((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - progressDiameter) / 2.0), y: floorToScreenPixels((layout.size.height - progressDiameter) / 2.0), width: progressDiameter, height: progressDiameter)
}
}

View File

@ -6,20 +6,6 @@ import TelegramCore
import SwiftSignalKit import SwiftSignalKit
import Photos import Photos
enum WallpaperListType {
case wallpapers(PresentationWallpaperMode?)
case colors
}
enum WallpaperListPreviewSource {
case list(wallpapers: [TelegramWallpaper], central: TelegramWallpaper, type: WallpaperListType)
case wallpaper(TelegramWallpaper)
case slug(String, TelegramMediaFile?)
case asset(PHAsset, UIImage?)
case contextResult(ChatContextResult)
case customColor(Int32?)
}
final class WallpaperListPreviewController: ViewController { final class WallpaperListPreviewController: ViewController {
private var controllerNode: WallpaperListPreviewControllerNode { private var controllerNode: WallpaperListPreviewControllerNode {
return self.displayNode as! WallpaperListPreviewControllerNode return self.displayNode as! WallpaperListPreviewControllerNode
@ -31,7 +17,7 @@ final class WallpaperListPreviewController: ViewController {
} }
private let account: Account private let account: Account
private let source: WallpaperListPreviewSource private let source: WallpaperListSource
private var presentationData: PresentationData private var presentationData: PresentationData
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
@ -41,9 +27,9 @@ final class WallpaperListPreviewController: ViewController {
private var didPlayPresentationAnimation = false private var didPlayPresentationAnimation = false
var apply: ((WallpaperEntry, PresentationWallpaperMode, CGRect?) -> Void)? var apply: ((WallpaperEntry, WallpaperPresentationOptions, CGRect?) -> Void)?
init(account: Account, source: WallpaperListPreviewSource) { init(account: Account, source: WallpaperListSource) {
self.account = account self.account = account
self.source = source self.source = source
@ -121,7 +107,7 @@ final class WallpaperListPreviewController: ViewController {
case let .wallpaper(wallpaper): case let .wallpaper(wallpaper):
let completion: () -> Void = { let completion: () -> Void = {
let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in let _ = (updatePresentationThemeSettingsInteractively(postbox: strongSelf.account.postbox, { current in
return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperMode: mode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations) return PresentationThemeSettings(chatWallpaper: wallpaper, chatWallpaperOptions: mode, theme: current.theme, themeAccentColor: current.themeAccentColor, fontSize: current.fontSize, automaticThemeSwitchSetting: current.automaticThemeSwitchSetting, disableAnimations: current.disableAnimations)
}) })
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
self?.dismiss() self?.dismiss()
@ -133,7 +119,7 @@ final class WallpaperListPreviewController: ViewController {
let _ = installWallpaper(account: strongSelf.account, wallpaper: wallpaper).start() let _ = installWallpaper(account: strongSelf.account, wallpaper: wallpaper).start()
} }
if case .blurred = mode { if mode.contains(.blur) {
var resource: MediaResource? var resource: MediaResource?
switch wallpaper { switch wallpaper {
case let .file(file): case let .file(file):

View File

@ -195,7 +195,7 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
self.imageNode.contentMode = .scaleAspectFill self.imageNode.contentMode = .scaleAspectFill
self.wrapperNode.addSubnode(self.imageNode) self.wrapperNode.addSubnode(self.imageNode)
} }
self.wrapperNode.addSubnode(self.statusNode) self.addSubnode(self.statusNode)
let imagePromise = Promise<UIImage?>() let imagePromise = Promise<UIImage?>()
self.imageNode.setSignal(signal, dispatchOnDisplayLink: false) self.imageNode.setSignal(signal, dispatchOnDisplayLink: false)
@ -258,7 +258,7 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
func setParallaxEnabled(_ enabled: Bool) { func setParallaxEnabled(_ enabled: Bool) {
if enabled { if enabled {
let amount = 16.0 let amount = 24.0
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis) let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = -amount horizontal.minimumRelativeValue = -amount
@ -342,9 +342,9 @@ private final class WallpaperBackgroundNode: ASDisplayNode {
final class WallpaperListPreviewControllerNode: ViewControllerTracingNode { final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
private let account: Account private let account: Account
private var presentationData: PresentationData private var presentationData: PresentationData
private let source: WallpaperListPreviewSource private let source: WallpaperListSource
private let dismiss: () -> Void private let dismiss: () -> Void
private let apply: (WallpaperEntry, PresentationWallpaperMode, CGRect?) -> Void private let apply: (WallpaperEntry, WallpaperPresentationOptions, CGRect?) -> Void
private var validLayout: (ContainerViewLayout, CGFloat)? private var validLayout: (ContainerViewLayout, CGFloat)?
@ -380,7 +380,7 @@ final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
} }
private var visibleBackgroundNodesOffset: CGFloat = 0.0 private var visibleBackgroundNodesOffset: CGFloat = 0.0
init(account: Account, presentationData: PresentationData, source: WallpaperListPreviewSource, dismiss: @escaping () -> Void, apply: @escaping (WallpaperEntry, PresentationWallpaperMode, CGRect?) -> Void) { init(account: Account, presentationData: PresentationData, source: WallpaperListSource, dismiss: @escaping () -> Void, apply: @escaping (WallpaperEntry, WallpaperPresentationOptions, CGRect?) -> Void) {
self.account = account self.account = account
self.presentationData = presentationData self.presentationData = presentationData
self.source = source self.source = source
@ -843,15 +843,13 @@ final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
} }
@objc private func indexChanged() { @objc private func indexChanged() {
guard let mode = PresentationWallpaperMode(rawValue: Int32(self.segmentedControl.selectedSegmentIndex)) else { let index = self.segmentedControl.selectedSegmentIndex
return
}
if let node = self.centralNode() { if let node = self.centralNode() {
if mode == .perspective { if index == 1 {
node.setParallaxEnabled(true) node.setParallaxEnabled(true)
node.setBlurEnabled(false, animated: true) node.setBlurEnabled(false, animated: true)
} else if mode == .blurred { } else if index == 2 {
node.setParallaxEnabled(false) node.setParallaxEnabled(false)
node.setBlurEnabled(true, animated: true) node.setBlurEnabled(true, animated: true)
} else { } else {
@ -867,16 +865,16 @@ final class WallpaperListPreviewControllerNode: ViewControllerTracingNode {
@objc private func applyPressed() { @objc private func applyPressed() {
if let wallpaper = self.centralWallpaper { if let wallpaper = self.centralWallpaper {
let mode: PresentationWallpaperMode var options: WallpaperPresentationOptions = []
switch self.segmentedControl.selectedSegmentIndex { switch self.segmentedControl.selectedSegmentIndex {
case 1: case 1:
mode = .perspective options.insert(.motion)
case 2: case 2:
mode = .blurred options.insert(.blur)
default: default:
mode = .still break
} }
self.apply(wallpaper, mode, self.centralNode()?.cropRect) self.apply(wallpaper, options, self.centralNode()?.cropRect)
} }
} }
} }