From b45776888eff125c022f7d97d1055db5eb332400 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Mon, 29 Apr 2019 18:03:54 +0400 Subject: [PATCH] Fix animations --- TelegramUI/AvatarNode.swift | 26 +++++- TelegramUI/ChatListController.swift | 94 +++++++++++++--------- TelegramUI/ChatListViewTransition.swift | 2 +- TelegramUI/UndoOverlayController.swift | 13 +-- TelegramUI/UndoOverlayControllerNode.swift | 20 ++++- 5 files changed, 108 insertions(+), 47 deletions(-) diff --git a/TelegramUI/AvatarNode.swift b/TelegramUI/AvatarNode.swift index 11a90a98f2..49f0e12da8 100644 --- a/TelegramUI/AvatarNode.swift +++ b/TelegramUI/AvatarNode.swift @@ -212,10 +212,32 @@ public final class AvatarNode: ASDisplayNode { let animationBackgroundNode = ASImageNode() animationBackgroundNode.frame = self.imageNode.frame - animationBackgroundNode.image = generateFilledCircleImage(diameter: self.imageNode.frame.width, color: theme.chatList.neutralAvatarColor) + var animationColor = theme.chatList.neutralAvatarColor + if let overrideImage = self.overrideImage { + switch overrideImage { + case let .archivedChatsIcon(hiddenByDefault) where !hiddenByDefault: + animationColor = UIColor(rgb: 0x2a9ef1).mixedWith(UIColor(rgb: 0x72d5fd), alpha: 0.5) + animationBackgroundNode.image = generateImage(CGSize(width: self.imageNode.frame.width, height: self.imageNode.frame.width), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + context.beginPath() + context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: + size.height)) + context.clip() + let colorsArray = gradientColors[5] + var locations: [CGFloat] = [1.0, 0.0] + + let colorSpace = CGColorSpaceCreateDeviceRGB() + let gradient = CGGradient(colorsSpace: colorSpace, colors: colorsArray, locations: &locations)! + + context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions()) + }) + default: + animationBackgroundNode.image = generateFilledCircleImage(diameter: self.imageNode.frame.width, color: theme.chatList.neutralAvatarColor) + } + } self.addSubnode(animationBackgroundNode) - let animationNode = AnimationNode(animation: name, keysToColor: keysToColor, color: theme.chatList.neutralAvatarColor, scale: scale) + let animationNode = AnimationNode(animation: name, keysToColor: keysToColor, color: animationColor, scale: scale) animationNode.completion = { [weak animationBackgroundNode, weak self] in self?.imageNode.isHidden = false animationBackgroundNode?.removeFromSupernode() diff --git a/TelegramUI/ChatListController.swift b/TelegramUI/ChatListController.swift index 342a415a24..8fecb266e8 100644 --- a/TelegramUI/ChatListController.swift +++ b/TelegramUI/ChatListController.swift @@ -424,8 +424,16 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie state.peerIdWithRevealedOptions = nil return state } + var hadCurrent = false + strongSelf.window?.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + hadCurrent = true + controller.dismissWithReplacementAnimation() + } + }) + if value { - strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenText, undo: true), elevatedLayout: strongSelf.groupId == .root, action: { [weak self] shouldCommit in + strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenText, undo: true), elevatedLayout: strongSelf.groupId == .root, animateInAsReplacement: hadCurrent, action: { [weak self] shouldCommit in guard let strongSelf = self else { return } @@ -443,7 +451,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } }), in: .window(.root)) } else { - strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedText, undo: false), elevatedLayout: strongSelf.groupId == .root, action: { _ in + strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedText, undo: false), elevatedLayout: strongSelf.groupId == .root, animateInAsReplacement: hadCurrent, action: { _ in }), in: .window(.root)) } }) @@ -533,7 +541,16 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie state.pendingClearHistoryPeerIds.insert(peer.peerId) return state }) - strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .removedChat(text: strongSelf.presentationData.strings.Undo_ChatCleared), elevatedLayout: strongSelf.groupId == .root, action: { shouldCommit in + + var hadCurrent = false + strongSelf.window?.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + hadCurrent = true + controller.dismissWithReplacementAnimation() + } + }) + + strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .removedChat(text: strongSelf.presentationData.strings.Undo_ChatCleared), elevatedLayout: strongSelf.groupId == .root, animateInAsReplacement: hadCurrent, action: { shouldCommit in guard let strongSelf = self else { return } @@ -1451,44 +1468,40 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } } - var foundExisting = false + var hadCurrent = false strongSelf.window?.forEachController({ controller in if let controller = controller as? UndoOverlayController { - if case .archivedChat = controller.content { - foundExisting = true - controller.renewWithCurrentContent(action: action) - } + hadCurrent = true + controller.dismissWithReplacementAnimation() } }) - if !foundExisting { - let title: String - let text: String - let undo: Bool - switch previousHintCount { - case 0: - title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle - text = strongSelf.presentationData.strings.ChatList_UndoArchiveText1 - undo = false - case 1: - title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle - text = strongSelf.presentationData.strings.ChatList_UndoArchiveText2 - undo = false - case 2: - title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle - text = strongSelf.presentationData.strings.ChatList_UndoArchiveText3 - undo = false - case 3: - title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle - text = strongSelf.presentationData.strings.ChatList_UndoArchiveText4 - undo = false - default: - title = "" - text = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle - undo = true - } - strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .archivedChat(title: title, text: text, undo: undo), elevatedLayout: strongSelf.groupId == .root, action: action), in: .window(.root)) + let title: String + let text: String + let undo: Bool + switch previousHintCount { + case 0: + title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle + text = strongSelf.presentationData.strings.ChatList_UndoArchiveText1 + undo = false + case 1: + title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle + text = strongSelf.presentationData.strings.ChatList_UndoArchiveText2 + undo = false + case 2: + title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle + text = strongSelf.presentationData.strings.ChatList_UndoArchiveText3 + undo = false + case 3: + title = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle + text = strongSelf.presentationData.strings.ChatList_UndoArchiveText4 + undo = false + default: + title = "" + text = strongSelf.presentationData.strings.ChatList_UndoArchiveTitle + undo = true } + strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .archivedChat(title: title, text: text, undo: undo), elevatedLayout: strongSelf.groupId == .root, animateInAsReplacement: hadCurrent, action: action), in: .window(.root)) strongSelf.chatListDisplayNode.playArchiveAnimation() }) @@ -1543,7 +1556,16 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie statusText = self.presentationData.strings.Undo_ChatDeleted } } - self.present(UndoOverlayController(context: self.context, content: .removedChat(text: statusText), elevatedLayout: self.groupId == .root, action: { [weak self] shouldCommit in + + var hadCurrent = false + self.window?.forEachController({ controller in + if let controller = controller as? UndoOverlayController { + hadCurrent = true + controller.dismissWithReplacementAnimation() + } + }) + + self.present(UndoOverlayController(context: self.context, content: .removedChat(text: statusText), elevatedLayout: self.groupId == .root, animateInAsReplacement: hadCurrent, action: { [weak self] shouldCommit in guard let strongSelf = self else { return } diff --git a/TelegramUI/ChatListViewTransition.swift b/TelegramUI/ChatListViewTransition.swift index 6f0c7c0ed5..8055a1bce9 100644 --- a/TelegramUI/ChatListViewTransition.swift +++ b/TelegramUI/ChatListViewTransition.swift @@ -95,7 +95,7 @@ func preparedChatListNodeViewTransition(from fromView: ChatListNodeView?, to toV } } - if let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp, abs(maxTimestamp - minTimestamp) > 60 * 60 { + if false, let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp, abs(maxTimestamp - minTimestamp) > 60 * 60 { let _ = options.insert(.AnimateCrossfade) } else { let _ = options.insert(.AnimateAlpha) diff --git a/TelegramUI/UndoOverlayController.swift b/TelegramUI/UndoOverlayController.swift index b2454af2e9..86c64de1a5 100644 --- a/TelegramUI/UndoOverlayController.swift +++ b/TelegramUI/UndoOverlayController.swift @@ -13,15 +13,17 @@ final class UndoOverlayController: ViewController { private let presentationData: PresentationData let content: UndoOverlayContent private let elevatedLayout: Bool + private let animateInAsReplacement: Bool private var action: (Bool) -> Void private var didPlayPresentationAnimation = false - init(context: AccountContext, content: UndoOverlayContent, elevatedLayout: Bool, action: @escaping (Bool) -> Void) { + init(context: AccountContext, content: UndoOverlayContent, elevatedLayout: Bool, animateInAsReplacement: Bool = false, action: @escaping (Bool) -> Void) { self.context = context self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.content = content self.elevatedLayout = elevatedLayout + self.animateInAsReplacement = animateInAsReplacement self.action = action super.init(navigationBarPresentationData: nil) @@ -47,9 +49,10 @@ final class UndoOverlayController: ViewController { self.dismiss() } - func renewWithCurrentContent(action: @escaping (Bool) -> Void) { - self.action = action - (self.displayNode as! UndoOverlayControllerNode).renewWithCurrentContent() + func dismissWithReplacementAnimation() { + (self.displayNode as! UndoOverlayControllerNode).animateOutWithReplacement(completion: { [weak self] in + self?.presentingViewController?.dismiss(animated: false, completion: nil) + }) } override func viewDidAppear(_ animated: Bool) { @@ -57,7 +60,7 @@ final class UndoOverlayController: ViewController { if !self.didPlayPresentationAnimation { self.didPlayPresentationAnimation = true - (self.displayNode as! UndoOverlayControllerNode).animateIn() + (self.displayNode as! UndoOverlayControllerNode).animateIn(asReplacement: self.animateInAsReplacement) } } diff --git a/TelegramUI/UndoOverlayControllerNode.swift b/TelegramUI/UndoOverlayControllerNode.swift index bb52459f1c..d89184b845 100644 --- a/TelegramUI/UndoOverlayControllerNode.swift +++ b/TelegramUI/UndoOverlayControllerNode.swift @@ -254,9 +254,15 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { } } - func animateIn() { - self.panelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) - self.panelWrapperNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + func animateIn(asReplacement: Bool) { + if asReplacement { + let offset = self.bounds.width + self.panelWrapperNode.layer.animatePosition(from: CGPoint(x: offset, y: 0.0), to: CGPoint(), duration: 0.35, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: nil) + self.panelNode.layer.animatePosition(from: CGPoint(x: offset, y: 0.0), to: CGPoint(), duration: 0.35, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: nil) + } else { + self.panelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + self.panelWrapperNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) + } if let iconCheckNode = self.iconCheckNode, self.iconNode != nil { Queue.mainQueue().after(0.2, { [weak iconCheckNode] in @@ -274,6 +280,14 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { } } + func animateOutWithReplacement(completion: @escaping () -> Void) { + let offset = -self.bounds.width + self.panelWrapperNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: offset, y: 0.0), duration: 0.35, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { _ in + completion() + }) + self.panelNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: offset, y: 0.0), duration: 0.35, delay: 0.0, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: nil) + } + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { if !self.panelNode.frame.insetBy(dx: -60.0, dy: 0.0).contains(point) { return nil