mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Theme preview crossfade fixes
This commit is contained in:
parent
d44cee406c
commit
f696edf0a4
@ -191,6 +191,8 @@ public final class GradientBackgroundNode: ASDisplayNode {
|
||||
self.parentNode = parentNode
|
||||
|
||||
super.init()
|
||||
|
||||
self.displaysAsynchronously = false
|
||||
|
||||
self.index = parentNode.cloneNodes.add(Weak<CloneNode>(self))
|
||||
self.image = parentNode.dimmedImage
|
||||
|
@ -1270,6 +1270,7 @@ public final class PresentationTheme: Equatable {
|
||||
public let inAppNotification: PresentationThemeInAppNotification
|
||||
public let chart: PresentationThemeChart
|
||||
public let preview: Bool
|
||||
public var forceSync: Bool = false
|
||||
|
||||
public let resourceCache: PresentationsResourceCache = PresentationsResourceCache()
|
||||
|
||||
|
@ -3964,7 +3964,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
let customTheme = useDarkAppearance ? theme.darkTheme : theme.theme
|
||||
if let settings = customTheme.settings, let theme = makePresentationTheme(settings: settings) {
|
||||
theme.forceSync = true
|
||||
presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
|
||||
|
||||
Queue.mainQueue().after(1.0, {
|
||||
theme.forceSync = false
|
||||
})
|
||||
}
|
||||
} else if let darkAppearancePreview = darkAppearancePreview {
|
||||
useDarkAppearance = darkAppearancePreview
|
||||
@ -3988,7 +3993,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if let themeSpecificWallpaper = themeSpecificWallpaper {
|
||||
lightWallpaper = themeSpecificWallpaper
|
||||
} else {
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor) ?? defaultPresentationTheme
|
||||
let theme = makePresentationTheme(mediaBox: accountManager.mediaBox, themeReference: themeSettings.theme, accentColor: currentColors?.color, bubbleColors: currentColors?.customBubbleColors ?? [], wallpaper: currentColors?.wallpaper, baseColor: currentColors?.baseColor, preview: true) ?? defaultPresentationTheme
|
||||
lightWallpaper = theme.chat.defaultWallpaper
|
||||
}
|
||||
|
||||
@ -4022,8 +4027,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
if darkAppearancePreview {
|
||||
darkTheme.forceSync = true
|
||||
Queue.mainQueue().after(1.0, {
|
||||
darkTheme.forceSync = false
|
||||
})
|
||||
presentationData = presentationData.withUpdated(theme: darkTheme).withUpdated(chatWallpaper: darkWallpaper)
|
||||
} else {
|
||||
lightTheme.forceSync = true
|
||||
Queue.mainQueue().after(1.0, {
|
||||
lightTheme.forceSync = false
|
||||
})
|
||||
presentationData = presentationData.withUpdated(theme: lightTheme).withUpdated(chatWallpaper: lightWallpaper)
|
||||
}
|
||||
}
|
||||
@ -4040,7 +4053,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData))
|
||||
|
||||
if !isFirstTime && (previousThemeEmoticon?.0 != themeEmoticon || previousThemeEmoticon?.1 != useDarkAppearance) {
|
||||
strongSelf.presentCrossfadeSnapshot(delay: 0.2)
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
}
|
||||
}
|
||||
strongSelf.presentationReady.set(.single(true))
|
||||
@ -13389,14 +13402,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private var crossfading = false
|
||||
private func presentCrossfadeSnapshot(delay: Double) {
|
||||
private func presentCrossfadeSnapshot() {
|
||||
guard !self.crossfading, let snapshotView = self.view.snapshotView(afterScreenUpdates: false) else {
|
||||
return
|
||||
}
|
||||
self.crossfading = true
|
||||
self.view.addSubview(snapshotView)
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak self, weak snapshotView] _ in
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak self, weak snapshotView] _ in
|
||||
self?.crossfading = false
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
@ -13454,7 +13467,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer?.compactDisplayTitle ?? "", previewTheme: { [weak self] emoticon, dark in
|
||||
if let strongSelf = self {
|
||||
strongSelf.presentCrossfadeSnapshot(delay: 0.2)
|
||||
strongSelf.presentCrossfadeSnapshot()
|
||||
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))
|
||||
}
|
||||
}, completion: { [weak self] emoticon in
|
||||
|
@ -1122,6 +1122,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion)
|
||||
var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, transition: rawTransition)
|
||||
|
||||
disableAnimations = true
|
||||
mappedTransition.options.insert(.LowLatency)
|
||||
mappedTransition.options.insert(.PreferSynchronousDrawing)
|
||||
if disableAnimations {
|
||||
mappedTransition.options.remove(.AnimateInsertion)
|
||||
mappedTransition.options.remove(.AnimateAlpha)
|
||||
|
@ -2312,6 +2312,9 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
backgroundType = .incoming(mergeType)
|
||||
}
|
||||
let hasWallpaper = item.presentationData.theme.wallpaper.hasWallpaper
|
||||
if item.presentationData.theme.theme.forceSync {
|
||||
transition = .immediate
|
||||
}
|
||||
strongSelf.backgroundNode.setType(type: backgroundType, highlighted: strongSelf.highlightedState, graphics: graphics, maskMode: strongSelf.backgroundMaskMode, hasWallpaper: hasWallpaper, transition: transition, backgroundNode: presentationContext.backgroundNode)
|
||||
strongSelf.backgroundWallpaperNode.setType(type: backgroundType, theme: item.presentationData.theme, essentialGraphics: graphics, maskMode: strongSelf.backgroundMaskMode, backgroundNode: presentationContext.backgroundNode)
|
||||
strongSelf.shadowNode.setType(type: backgroundType, hasWallpaper: hasWallpaper, graphics: graphics)
|
||||
@ -2364,7 +2367,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
strongSelf.clippingNode.addSubnode(nameNode)
|
||||
}
|
||||
nameNode.frame = CGRect(origin: CGPoint(x: contentOrigin.x + layoutConstants.text.bubbleInsets.left, y: layoutConstants.bubble.contentInsets.top + nameNodeOriginY), size: nameNodeSizeApply.0)
|
||||
nameNode.displaysAsynchronously = !item.presentationData.isPreview
|
||||
nameNode.displaysAsynchronously = !item.presentationData.isPreview && !item.presentationData.theme.theme.forceSync
|
||||
|
||||
if let credibilityIconImage = currentCredibilityIconImage {
|
||||
let credibilityIconNode: ASImageNode
|
||||
|
@ -381,7 +381,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
strongSelf.textNode.displaysAsynchronously = !item.presentationData.isPreview
|
||||
strongSelf.textNode.displaysAsynchronously = !item.presentationData.isPreview && !item.presentationData.theme.theme.forceSync
|
||||
let _ = textApply()
|
||||
|
||||
if let statusApply = statusApply, let adjustedStatusFrame = adjustedStatusFrame {
|
||||
|
@ -283,9 +283,11 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
|
||||
self.textNode = TextNode()
|
||||
self.textNode.isUserInteractionEnabled = false
|
||||
self.textNode.displaysAsynchronously = false
|
||||
|
||||
self.emojiNode = TextNode()
|
||||
self.emojiNode.isUserInteractionEnabled = false
|
||||
self.emojiNode.displaysAsynchronously = false
|
||||
|
||||
self.emojiImageNode = TransformImageNode()
|
||||
|
||||
@ -495,7 +497,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
snapshotView.frame = self.containerNode.view.frame
|
||||
self.view.insertSubview(snapshotView, aboveSubview: self.containerNode.view)
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
@ -521,6 +523,9 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
|
||||
}
|
||||
|
||||
final class ChatThemeScreen: ViewController {
|
||||
static let themeCrossfadeDuration: Double = 0.3
|
||||
static let themeCrossfadeDelay: Double = 0.25
|
||||
|
||||
private var controllerNode: ChatThemeScreenNode {
|
||||
return self.displayNode as! ChatThemeScreenNode
|
||||
}
|
||||
@ -839,7 +844,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
let action: (String?) -> Void = { [weak self] emoticon in
|
||||
if let strongSelf = self, strongSelf.selectedEmoticon != emoticon {
|
||||
strongSelf.animateCrossfade(animateIcon: false)
|
||||
strongSelf.animateCrossfade(animateIcon: true)
|
||||
|
||||
strongSelf.previewTheme?(emoticon, strongSelf.isDarkAppearance)
|
||||
strongSelf.selectedEmoticon = emoticon
|
||||
@ -973,7 +978,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
animationNode.isUserInteractionEnabled = false
|
||||
animationNode.frame = previousAnimationNode.frame
|
||||
previousAnimationNode.supernode?.insertSubnode(animationNode, belowSubnode: previousAnimationNode)
|
||||
previousAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
previousAnimationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, removeOnCompletion: false)
|
||||
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
} else {
|
||||
@ -1009,6 +1014,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
}
|
||||
|
||||
@objc func switchThemePressed() {
|
||||
self.switchThemeButton.isUserInteractionEnabled = false
|
||||
Queue.mainQueue().after(0.5) {
|
||||
self.switchThemeButton.isUserInteractionEnabled = true
|
||||
}
|
||||
|
||||
self.animateCrossfade(animateIcon: false)
|
||||
self.animationNode.setAnimation(name: self.isDarkAppearance ? "anim_sun_reverse" : "anim_sun", colors: iconColors(theme: self.presentationData.theme))
|
||||
self.animationNode.playOnce()
|
||||
@ -1024,21 +1034,19 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
}
|
||||
}
|
||||
|
||||
private func animateCrossfade(animateIcon: Bool = true) {
|
||||
let delay: Double = 0.2
|
||||
|
||||
private func animateCrossfade(animateIcon: Bool) {
|
||||
if animateIcon, let snapshotView = self.animationNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = self.animationNode.frame
|
||||
self.animationNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.animationNode.view)
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(delay) {
|
||||
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay) {
|
||||
if let effectView = self.effectNode.view as? UIVisualEffectView {
|
||||
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseInOut) {
|
||||
UIView.animate(withDuration: ChatThemeScreen.themeCrossfadeDuration, delay: 0.0, options: .curveLinear) {
|
||||
effectView.effect = UIBlurEffect(style: self.presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark)
|
||||
} completion: { _ in
|
||||
}
|
||||
@ -1046,14 +1054,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
|
||||
let previousColor = self.contentBackgroundNode.backgroundColor ?? .clear
|
||||
self.contentBackgroundNode.backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor
|
||||
self.contentBackgroundNode.layer.animate(from: previousColor.cgColor, to: (self.contentBackgroundNode.backgroundColor ?? .clear).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.3)
|
||||
self.contentBackgroundNode.layer.animate(from: previousColor.cgColor, to: (self.contentBackgroundNode.backgroundColor ?? .clear).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: ChatThemeScreen.themeCrossfadeDuration)
|
||||
}
|
||||
|
||||
if let snapshotView = self.contentContainerNode.view.snapshotView(afterScreenUpdates: false) {
|
||||
snapshotView.frame = self.contentContainerNode.frame
|
||||
self.contentContainerNode.view.superview?.insertSubview(snapshotView, aboveSubview: self.contentContainerNode.view)
|
||||
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: ChatThemeScreen.themeCrossfadeDuration, delay: ChatThemeScreen.themeCrossfadeDelay, timingFunction: CAMediaTimingFunctionName.linear.rawValue, removeOnCompletion: false, completion: { [weak snapshotView] _ in
|
||||
snapshotView?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
|
@ -3484,16 +3484,19 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
|
||||
var mainItemsImpl: (() -> Signal<[ContextMenuItem], NoError>)?
|
||||
mainItemsImpl = {
|
||||
mainItemsImpl = { [weak self] in
|
||||
var items: [ContextMenuItem] = []
|
||||
guard let strongSelf = self else {
|
||||
return .single(items)
|
||||
}
|
||||
|
||||
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: false, videoCallsEnabled: self.videoCallsEnabled, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false))
|
||||
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: self.headerNode.isAvatarExpanded, videoCallsEnabled: self.videoCallsEnabled, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false))
|
||||
let allHeaderButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: false, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false))
|
||||
let headerButtons = Set(peerInfoHeaderButtons(peer: peer, cachedData: data.cachedData, isOpenedFromChat: strongSelf.isOpenedFromChat, isExpanded: strongSelf.headerNode.isAvatarExpanded, videoCallsEnabled: strongSelf.videoCallsEnabled, isSecretChat: strongSelf.peerId.namespace == Namespaces.Peer.SecretChat, isContact: strongSelf.data?.isContact ?? false))
|
||||
|
||||
let filteredButtons = allHeaderButtons.subtracting(headerButtons)
|
||||
|
||||
var canChangeColors = false
|
||||
if peer is TelegramUser, self.data?.encryptionKeyFingerprint == nil {
|
||||
if peer is TelegramUser, strongSelf.data?.encryptionKeyFingerprint == nil {
|
||||
canChangeColors = true
|
||||
}
|
||||
|
||||
@ -3633,7 +3636,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
})))
|
||||
}
|
||||
|
||||
if self.peerId.namespace == Namespaces.Peer.CloudUser && user.botInfo == nil && !user.flags.contains(.isSupport) {
|
||||
if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser && user.botInfo == nil && !user.flags.contains(.isSupport) {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_StartSecretChat, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Timer"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
@ -3653,7 +3656,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
})))
|
||||
}
|
||||
}
|
||||
} else if self.peerId.namespace == Namespaces.Peer.SecretChat && data.isContact {
|
||||
} else if strongSelf.peerId.namespace == Namespaces.Peer.SecretChat && data.isContact {
|
||||
if let cachedData = data.cachedData as? CachedUserData, cachedData.isBlocked {
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_BlockUser, icon: { theme in
|
||||
@ -3666,7 +3669,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
if let cachedData = self.data?.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) {
|
||||
if let cachedData = strongSelf.data?.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.ChannelInfo_Stats, icon: { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Statistics"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { [weak self] _, f in
|
||||
|
@ -65,6 +65,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
self.bubbleType = bubbleType
|
||||
|
||||
self.contentNode = ASImageNode()
|
||||
self.contentNode.displaysAsynchronously = false
|
||||
self.contentNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init()
|
||||
@ -165,6 +166,7 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
|
||||
if needsWallpaperBackground {
|
||||
if self.cleanWallpaperNode == nil {
|
||||
let cleanWallpaperNode = ASImageNode()
|
||||
cleanWallpaperNode.displaysAsynchronously = false
|
||||
self.cleanWallpaperNode = cleanWallpaperNode
|
||||
cleanWallpaperNode.frame = self.bounds
|
||||
self.insertSubnode(cleanWallpaperNode, at: 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user