diff --git a/submodules/ContactListUI/Sources/ContactContextMenus.swift b/submodules/ContactListUI/Sources/ContactContextMenus.swift index 982d46e5ef..f772241d12 100644 --- a/submodules/ContactListUI/Sources/ContactContextMenus.swift +++ b/submodules/ContactListUI/Sources/ContactContextMenus.swift @@ -102,7 +102,7 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con context: context, account: context.account, sharedContext: context.sharedContext, - text: .markdown(text: "Stories from \(peer.compactDisplayTitle) will now be shown in Chats, not Contacts."), + text: .markdown(text: "Stories from **\(peer.compactDisplayTitle)** will now be shown in Chats, not Contacts."), icon: .peer(peer: peer, isStory: true), action: TooltipScreen.Action( title: "Undo", diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index 778b4d537f..ee826080c4 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -17,6 +17,7 @@ import AsyncDisplayKit import AttachmentUI import simd import VolumeButtons +import TooltipUI func hasFirstResponder(_ view: UIView) -> Bool { if view.isFirstResponder { @@ -827,7 +828,7 @@ private final class StoryContainerScreenComponent: Component { guard let self, let environment = self.environment else { return } - if c is UndoOverlayController { + if c is UndoOverlayController || c is TooltipScreen { environment.controller()?.present(c, in: .current) } else { environment.controller()?.present(c, in: .window(.root), with: a) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index 0d30b1f100..62ab7b7a73 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -31,6 +31,7 @@ import SaveToCameraRoll import BundleIconComponent import PeerListItemComponent import PremiumUI +import AttachmentUI public final class StoryItemSetContainerComponent: Component { public final class ExternalState { @@ -755,7 +756,7 @@ public final class StoryItemSetContainerComponent: Component { } if let navigationController = component.controller()?.navigationController as? NavigationController { let topViewController = navigationController.topViewController - if !(topViewController is StoryContainerScreen) && !(topViewController is MediaEditorScreen) && !(topViewController is ShareWithPeersScreen) { + if !(topViewController is StoryContainerScreen) && !(topViewController is MediaEditorScreen) && !(topViewController is ShareWithPeersScreen) && !(topViewController is AttachmentController) { return true } } @@ -3164,6 +3165,34 @@ public final class StoryItemSetContainerComponent: Component { } let _ = component.context.engine.peers.updatePeerStoriesHidden(id: component.slice.peer.id, isHidden: !isHidden) + + let text = isHidden ? "Stories from **\(component.slice.peer.compactDisplayTitle)** will now be shown in Chats, not Contacts." : "Stories from **\(component.slice.peer.compactDisplayTitle)** will now be shown in Contacts, not Chats." + let tooltipScreen = TooltipScreen( + context: component.context, + account: component.context.account, + sharedContext: component.context.sharedContext, + text: .markdown(text: text), + style: .customBlur(UIColor(rgb: 0x1c1c1c)), + icon: .peer(peer: component.slice.peer, isStory: true), + action: TooltipScreen.Action( + title: "Undo", + action: { + component.context.engine.peers.updatePeerStoriesHidden(id: component.slice.peer.id, isHidden: isHidden) + } + ), + location: .bottom, + shouldDismissOnTouch: { _ in return .dismiss(consume: false) } + ) + tooltipScreen.willBecomeDismissed = { [weak self] _ in + guard let self else { + return + } + self.sendMessageContext.tooltipScreen = nil + self.updateIsProgressPaused() + } + self.sendMessageContext.tooltipScreen = tooltipScreen + self.updateIsProgressPaused() + component.controller()?.present(tooltipScreen, in: .current) }))) items.append(.action(ContextMenuActionItem(text: "Report", icon: { theme in diff --git a/submodules/TooltipUI/Sources/TooltipScreen.swift b/submodules/TooltipUI/Sources/TooltipScreen.swift index 86d94718dd..fd43331cb2 100644 --- a/submodules/TooltipUI/Sources/TooltipScreen.swift +++ b/submodules/TooltipUI/Sources/TooltipScreen.swift @@ -157,7 +157,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode { action: TooltipScreen.Action? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, - inset: CGFloat = 13.0, + inset: CGFloat = 12.0, cornerRadius: CGFloat? = nil, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) { @@ -229,18 +229,31 @@ private final class TooltipScreenNode: ViewControllerTracingNode { self.arrowContainer = ASDisplayNode() - let fontSize: CGFloat + var hasArrow = true if case .top = location { + hasArrow = false + } else if case .bottom = location { + hasArrow = false + } + + let fontSize: CGFloat + if !hasArrow { let backgroundColor: UIColor - if theme.overallDarkAppearance { - backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor + var enableSaturation = true + if case let .customBlur(color) = style { + backgroundColor = color + enableSaturation = false } else { - backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6) + if theme.overallDarkAppearance { + backgroundColor = theme.rootController.navigationBar.blurredBackgroundColor + } else { + backgroundColor = UIColor(rgb: 0x000000, alpha: 0.6) + } } - self.effectNode = NavigationBackgroundNode(color: backgroundColor) + self.effectNode = NavigationBackgroundNode(color: backgroundColor, enableSaturation: enableSaturation) self.backgroundMaskNode.addSubnode(self.backgroundClipNode) self.backgroundClipNode.clipsToBounds = true - if case let .point(_, arrowPosition) = location, case .right = arrowPosition { + if case .bottom = location { self.backgroundClipNode.cornerRadius = 8.5 } else { self.backgroundClipNode.cornerRadius = 14.0 @@ -248,7 +261,6 @@ private final class TooltipScreenNode: ViewControllerTracingNode { if #available(iOS 13.0, *) { self.backgroundClipNode.layer.cornerCurve = .continuous } - fontSize = 14.0 } else if case let .gradient(leftColor, rightColor) = style { self.gradientNode = ASDisplayNode() @@ -545,12 +557,12 @@ private final class TooltipScreenNode: ViewControllerTracingNode { switch self.tooltipStyle { case .default, .gradient, .customBlur: backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0 - if self.actionButtonNode != nil { - backgroundHeight += 2.0 - } case .light: backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0) } + if self.actionButtonNode != nil { + backgroundHeight += 4.0 + } var invertArrow = false switch self.location { @@ -587,6 +599,9 @@ private final class TooltipScreenNode: ViewControllerTracingNode { case .top: let backgroundWidth = containerWidth backgroundFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - backgroundWidth) / 2.0), y: layout.insets(options: [.statusBar]).top + 13.0), size: CGSize(width: backgroundWidth, height: backgroundHeight)) + case .bottom: + let backgroundWidth = containerWidth + backgroundFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - backgroundWidth) / 2.0), y: layout.size.height - layout.insets(options: []).bottom - 12.0 - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight)) } transition.updateFrame(node: self.containerNode, frame: backgroundFrame) @@ -756,11 +771,18 @@ private final class TooltipScreenNode: ViewControllerTracingNode { func animateIn() { switch self.location { - case .top: - self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + case .top, .bottom: + self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.containerNode.layer.animateScale(from: 0.96, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) - if let _ = self.validLayout { - self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: -13.0 - self.backgroundContainerNode.frame.height), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) + + if let _ = self.validLayout, case .top = self.location { + let offset: CGFloat + if case .top = self.location { + offset = -13.0 - self.backgroundContainerNode.frame.height + } else { + offset = 13.0 + self.backgroundContainerNode.frame.height + } + self.containerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true) } case let .point(_, arrowPosition): self.containerNode.layer.animateSpring(from: NSNumber(value: Float(0.01)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.4, damping: 105.0) @@ -795,13 +817,19 @@ private final class TooltipScreenNode: ViewControllerTracingNode { func animateOut(completion: @escaping () -> Void) { switch self.location { - case .top: - self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in + case .top, .bottom: + self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false, completion: { _ in completion() }) self.containerNode.layer.animateScale(from: 1.0, to: 0.96, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - if let _ = self.validLayout { - self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -13.0 - self.backgroundContainerNode.frame.height), duration: 0.3, removeOnCompletion: false, additive: true) + if let _ = self.validLayout, case .top = self.location { + let offset: CGFloat + if case .top = self.location { + offset = -13.0 - self.backgroundContainerNode.frame.height + } else { + offset = 13.0 + self.backgroundContainerNode.frame.height + } + self.containerNode.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: offset), duration: 0.3, removeOnCompletion: false, additive: true) } case let .point(_, arrowPosition): self.containerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in @@ -875,6 +903,7 @@ public final class TooltipScreen: ViewController { public enum Location { case point(CGRect, ArrowPosition) case top + case bottom } public enum DisplayDuration { @@ -942,7 +971,7 @@ public final class TooltipScreen: ViewController { action: TooltipScreen.Action? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, - inset: CGFloat = 13.0, + inset: CGFloat = 12.0, cornerRadius: CGFloat? = nil, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index 3387014347..20d8699e14 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -1374,6 +1374,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { } 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) + + self.panelNode.layer.animateScale(from: 0.96, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + self.panelWrapperNode.layer.animateScale(from: 0.96, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) } if let iconCheckNode = self.iconCheckNode, self.iconNode != nil { @@ -1403,6 +1406,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.panelWrapperNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, delay: 0.0, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) { _ in completion() } + self.panelNode.layer.animateScale(from: 1.0, to: 0.96, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) + self.panelWrapperNode.layer.animateScale(from: 1.0, to: 0.96, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) } func animateOutWithReplacement(completion: @escaping () -> Void) {