diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift index 94f20e431e..92033d4a8e 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryController.swift @@ -246,7 +246,7 @@ public final class AuthorizationSequencePhoneEntryController: ViewController, MF } } - func dismissConfirmation() { + public func dismissConfirmation() { self.confirmationController?.dismissAnimated() self.confirmationController = nil } diff --git a/submodules/Display/Source/Navigation/NavigationController.swift b/submodules/Display/Source/Navigation/NavigationController.swift index 23ee1bcdfb..88dffb0d48 100644 --- a/submodules/Display/Source/Navigation/NavigationController.swift +++ b/submodules/Display/Source/Navigation/NavigationController.swift @@ -1354,10 +1354,24 @@ open class NavigationController: UINavigationController, ContainableController, public func replaceControllersAndPush(controllers: [UIViewController], controller: ViewController, animated: Bool, options: NavigationAnimationOptions = [], ready: ValuePromise? = nil, completion: @escaping () -> Void = {}) { ready?.set(true) - var controllers = controllers - controllers.append(controller) - self.setViewControllers(controllers, animated: animated) - completion() + let action = { [weak self] in + guard let self else { + return + } + var controllers = controllers + controllers.append(controller) + self.setViewControllers(controllers, animated: animated) + completion() + } + if let rootContainer = self.rootContainer, case let .split(container) = rootContainer, let topController = container.detailControllers.last { + if topController.attemptNavigation({ + action() + }) { + action() + } + } else { + action() + } } public func replaceControllers(controllers: [UIViewController], animated: Bool, options: NavigationAnimationOptions = [], ready: ValuePromise? = nil, completion: @escaping () -> Void = {}) { diff --git a/submodules/Display/Source/TextNode.swift b/submodules/Display/Source/TextNode.swift index e7cbc85bbd..9af6b7612f 100644 --- a/submodules/Display/Source/TextNode.swift +++ b/submodules/Display/Source/TextNode.swift @@ -1654,7 +1654,7 @@ open class TextNode: ASDisplayNode { return (layout, { node.cachedLayout = layout if updated { - if layout.size.width.isZero && layout.size.height.isZero { + if layout.size.width.isZero || layout.size.height.isZero { node.contents = nil } node.setNeedsDisplay() diff --git a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewPeerContentNode.swift b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewPeerContentNode.swift index 4a3de05c54..c4d827f983 100644 --- a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewPeerContentNode.swift +++ b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewPeerContentNode.swift @@ -183,6 +183,10 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer self.contentOffsetUpdated = f } + func updateTheme(_ theme: PresentationTheme) { + + } + func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let showPeers = !self.peerNodes.isEmpty && !isLandscape var nodeHeight: CGFloat = (!showPeers ? 236.0 : 320.0) @@ -283,7 +287,7 @@ public enum ShareLoadingState { public final class JoinLinkPreviewLoadingContainerNode: ASDisplayNode, ShareContentContainerNode { private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? - private let theme: PresentationTheme + private var theme: PresentationTheme private let activityIndicator: ActivityIndicator public init(theme: PresentationTheme) { @@ -308,6 +312,11 @@ public final class JoinLinkPreviewLoadingContainerNode: ASDisplayNode, ShareCont self.contentOffsetUpdated = f } + public func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + self.activityIndicator.type = .custom(theme.actionSheet.controlAccentColor, 22.0, 2.0, false) + } + public func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let nodeHeight: CGFloat = 125.0 diff --git a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift index 73556a8b07..13ebb8e9bd 100644 --- a/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift +++ b/submodules/LanguageLinkPreviewUI/Sources/LanguageLinkPreviewContentNode.swift @@ -82,6 +82,10 @@ final class LanguageLinkPreviewContentNode: ASDisplayNode, ShareContentContainer self.contentOffsetUpdated = f } + func updateTheme(_ theme: PresentationTheme) { + + } + func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let insets = UIEdgeInsets(top: 12.0, left: 10.0, bottom: 12.0 + bottomInset, right: 10.0) let titleSpacing: CGFloat = 12.0 diff --git a/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift b/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift index 03cc8821bb..cc28b6c698 100644 --- a/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift +++ b/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift @@ -110,7 +110,9 @@ class EmojiHeaderComponent: Component { } self.statusView.isHidden = false - containerView = containerView.subviews[1].subviews[1] + if containerView.subviews.count > 1 && containerView.subviews[1].subviews.count > 1 { + containerView = containerView.subviews[1].subviews[1] + } let initialPosition = self.statusView.center let targetPosition = self.statusView.superview!.convert(self.statusView.center, to: containerView) diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift index 33a3606a51..9583f3f2fd 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextBackgroundNode.swift @@ -166,7 +166,7 @@ final class ReactionContextBackgroundNode: ASDisplayNode { backgroundMaskNodeFrame = backgroundMaskNodeFrame.offsetBy(dx: 0.0, dy: (updatedHeight - backgroundMaskNodeFrame.height) * 0.5) } - transition.updateCornerRadius(layer: self.backgroundClippingLayer, cornerRadius: 46.0 / 2.0) + transition.updateCornerRadius(layer: self.backgroundClippingLayer, cornerRadius: min(46.0 / 2.0, backgroundFrame.height / 2.0)) let largeCircleFrame: CGRect let smallCircleFrame: CGRect diff --git a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift index f2e7a8904c..d2ff3e60cc 100644 --- a/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift +++ b/submodules/ReactionSelectionNode/Sources/ReactionContextNode.swift @@ -2276,6 +2276,9 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate { } } if let closestItem = closestItem, let closestItemNode = self.visibleItemNodes[closestItem.index] as? ReactionNode { + if let expandItemView = self.expandItemView, expandItemView.frame.insetBy(dx: -20.0, dy: -20.0).contains(scrollPoint) { + return nil + } return closestItemNode.item } return nil diff --git a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift index 741dc7edc0..b2eef15752 100644 --- a/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift +++ b/submodules/SettingsUI/Sources/ChangePhoneNumberController.swift @@ -137,6 +137,7 @@ public func ChangePhoneNumberController(context: AccountContext) -> ViewControll actions.append(TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})) } + controller?.dismissConfirmation() controller?.present(textAlertController(context: context, title: nil, text: text, actions: actions), in: .window(.root)) })) } diff --git a/submodules/ShareController/Sources/ShareContentContainerNode.swift b/submodules/ShareController/Sources/ShareContentContainerNode.swift index b28cf023b4..507514063c 100644 --- a/submodules/ShareController/Sources/ShareContentContainerNode.swift +++ b/submodules/ShareController/Sources/ShareContentContainerNode.swift @@ -3,6 +3,7 @@ import UIKit import Display import Postbox import TelegramCore +import TelegramPresentationData public protocol ShareContentContainerNode: AnyObject { func activate() @@ -10,5 +11,6 @@ public protocol ShareContentContainerNode: AnyObject { func setEnsurePeerVisibleOnLayout(_ peerId: EnginePeer.Id?) func setContentOffsetUpdated(_ f: ((CGFloat, ContainedViewLayoutTransition) -> Void)?) func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) + func updateTheme(_ theme: PresentationTheme) func updateSelectedPeers(animated: Bool) } diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index 7ca7100b83..29c2df3ac3 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -524,6 +524,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate self.actionButtonNode.badgeBackgroundColor = presentationData.theme.actionSheet.controlAccentColor self.actionButtonNode.badgeTextColor = presentationData.theme.actionSheet.opaqueItemBackgroundColor + + self.contentNode?.updateTheme(presentationData.theme) } func setActionNodesHidden(_ hidden: Bool, inputField: Bool = false, actions: Bool = false, animated: Bool = true) { diff --git a/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift b/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift index 4e7a4c4b7e..0b93022e03 100644 --- a/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift +++ b/submodules/ShareController/Sources/ShareControllerPeerGridItem.swift @@ -45,7 +45,7 @@ final class ShareControllerGridSection: GridSection { func isEqual(to: GridSection) -> Bool { if let to = to as? ShareControllerGridSection { - return self.title == to.title + return self.title == to.title && self.theme === to.theme } else { return false } @@ -185,7 +185,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode { } func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EngineRenderedPeer?, presence: EnginePeer.Presence?, topicId: Int64?, threadData: MessageHistoryThreadData?, search: Bool, synchronousLoad: Bool, force: Bool) { - if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.3 != peer || self.currentState!.5 != presence || self.currentState!.6 != topicId { + if force || self.currentState == nil || self.currentState!.0 !== context || self.currentState!.2 !== theme || self.currentState!.3 != peer || self.currentState!.5 != presence || self.currentState!.6 != topicId { let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) diff --git a/submodules/ShareController/Sources/ShareControllerRecentPeersGridItem.swift b/submodules/ShareController/Sources/ShareControllerRecentPeersGridItem.swift index f1cf0a0bb8..c1ee78c826 100644 --- a/submodules/ShareController/Sources/ShareControllerRecentPeersGridItem.swift +++ b/submodules/ShareController/Sources/ShareControllerRecentPeersGridItem.swift @@ -54,7 +54,7 @@ final class ShareControllerRecentPeersGridItemNode: GridItemNode { } func setup(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings) { - if self.currentState == nil || self.currentState!.0 !== context { + if self.currentState == nil || self.currentState!.0 !== context || self.currentState!.1 !== theme { let peersNode: ChatListSearchRecentPeersNode if let currentPeersNode = self.peersNode { peersNode = currentPeersNode diff --git a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift index 2dee5340a4..f3145f0398 100644 --- a/submodules/ShareController/Sources/ShareLoadingContainerNode.swift +++ b/submodules/ShareController/Sources/ShareLoadingContainerNode.swift @@ -27,7 +27,7 @@ protocol ShareLoadingContainer: ASDisplayNode { public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? - private let theme: PresentationTheme + private var theme: PresentationTheme private let activityIndicator: ActivityIndicator private let statusNode: RadialStatusNode private let doneStatusNode: RadialStatusNode @@ -78,6 +78,10 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain self.contentOffsetUpdated = f } + public func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + } + public func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let nodeHeight: CGFloat = 125.0 @@ -98,7 +102,7 @@ public final class ShareLoadingContainerNode: ASDisplayNode, ShareContentContain public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareContentContainerNode, ShareLoadingContainer { private var contentOffsetUpdated: ((CGFloat, ContainedViewLayoutTransition) -> Void)? - private let theme: PresentationTheme + private var theme: PresentationTheme private let strings: PresentationStrings private let animationNode: AnimatedStickerNode @@ -271,6 +275,10 @@ public final class ShareProlongedLoadingContainerNode: ASDisplayNode, ShareConte self.animationStatusDisposable.dispose() } + public func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + } + public func activate() { } diff --git a/submodules/ShareController/Sources/SharePeersContainerNode.swift b/submodules/ShareController/Sources/SharePeersContainerNode.swift index f21342381a..663f389ea8 100644 --- a/submodules/ShareController/Sources/SharePeersContainerNode.swift +++ b/submodules/ShareController/Sources/SharePeersContainerNode.swift @@ -65,6 +65,9 @@ private struct SharePeerEntry: Comparable, Identifiable { if lhs.threadData != rhs.threadData { return false } + if lhs.theme !== rhs.theme { + return false + } return true } @@ -100,7 +103,8 @@ private func preparedGridEntryTransition(context: AccountContext, from fromEntri final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { private let sharedContext: SharedAccountContext private let context: AccountContext - private let theme: PresentationTheme + private var theme: PresentationTheme + private let themePromise: Promise private let strings: PresentationStrings private let nameDisplayOrder: PresentationPersonNameOrder private let controllerInteraction: ShareControllerInteraction @@ -153,6 +157,8 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.sharedContext = sharedContext self.context = context self.theme = theme + self.themePromise = Promise() + self.themePromise.set(.single(theme)) self.strings = strings self.nameDisplayOrder = nameDisplayOrder self.controllerInteraction = controllerInteraction @@ -164,8 +170,8 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.peersValue.set(.single(peers)) - let items: Signal<[SharePeerEntry], NoError> = combineLatest(self.peersValue.get(), self.foundPeers.get(), self.tick.get()) - |> map { [weak controllerInteraction] initialPeers, foundPeers, _ -> [SharePeerEntry] in + let items: Signal<[SharePeerEntry], NoError> = combineLatest(self.peersValue.get(), self.foundPeers.get(), self.tick.get(), self.themePromise.get()) + |> map { [weak controllerInteraction] initialPeers, foundPeers, _, theme -> [SharePeerEntry] in var entries: [SharePeerEntry] = [] var index: Int32 = 0 @@ -303,6 +309,13 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.disposable.dispose() } + func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + self.themePromise.set(.single(theme)) + self.contentTitleNode.attributedText = NSAttributedString(string: self.strings.ShareMenu_ShareTo, font: Font.medium(20.0), textColor: self.theme.actionSheet.primaryTextColor) + self.updateSelectedPeers(animated: false) + } + private func enqueueTransition(_ transition: ShareGridTransaction, firstTime: Bool) { self.enqueuedTransitions.append((transition, firstTime)) diff --git a/submodules/ShareController/Sources/ShareSearchBarNode.swift b/submodules/ShareController/Sources/ShareSearchBarNode.swift index 4a8fd9ae96..a9f7644042 100644 --- a/submodules/ShareController/Sources/ShareSearchBarNode.swift +++ b/submodules/ShareController/Sources/ShareSearchBarNode.swift @@ -42,12 +42,10 @@ final class ShareSearchBarNode: ASDisplayNode, UITextFieldDelegate { self.textInputNode = TextFieldNode() self.textInputNode.fixOffset = false let textColor: UIColor = theme.actionSheet.inputTextColor - let keyboardAppearance: UIKeyboardAppearance = UIKeyboardAppearance.default self.textInputNode.textField.font = Font.regular(16.0) self.textInputNode.textField.textColor = textColor self.textInputNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(16.0), NSAttributedString.Key.foregroundColor: textColor] self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0) - self.textInputNode.textField.keyboardAppearance = keyboardAppearance self.textInputNode.textField.attributedPlaceholder = NSAttributedString(string: placeholder, font: Font.regular(16.0), textColor: theme.actionSheet.inputPlaceholderColor) self.textInputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance self.textInputNode.textField.tintColor = theme.actionSheet.controlAccentColor @@ -88,6 +86,19 @@ final class ShareSearchBarNode: ASDisplayNode, UITextFieldDelegate { transition.updateFrame(node: self.textInputNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY + UIScreenPixel), size: CGSize(width: backgroundFrame.size.width - inputInsets.left - inputInsets.right, height: backgroundFrame.size.height))) } + func updateTheme(_ theme: PresentationTheme) { + self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 16.0, color: theme.actionSheet.inputBackgroundColor) + self.searchIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Share/SearchBarSearchIcon"), color: theme.actionSheet.inputPlaceholderColor) + self.clearButton.setImage(generateClearIcon(color: theme.actionSheet.inputClearButtonColor), for: []) + + let textColor: UIColor = theme.actionSheet.inputTextColor + self.textInputNode.textField.textColor = textColor + self.textInputNode.textField.typingAttributes = [NSAttributedString.Key.font: Font.regular(16.0), NSAttributedString.Key.foregroundColor: textColor] + self.textInputNode.textField.attributedPlaceholder = NSAttributedString(string: self.textInputNode.textField.attributedPlaceholder?.string ?? "", font: Font.regular(16.0), textColor: theme.actionSheet.inputPlaceholderColor) + self.textInputNode.textField.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance + self.textInputNode.textField.tintColor = theme.actionSheet.controlAccentColor + } + func activateInput() { self.textInputNode.textField.becomeFirstResponder() } diff --git a/submodules/ShareController/Sources/ShareSearchContainerNode.swift b/submodules/ShareController/Sources/ShareSearchContainerNode.swift index d940693d57..f229d67ce0 100644 --- a/submodules/ShareController/Sources/ShareSearchContainerNode.swift +++ b/submodules/ShareController/Sources/ShareSearchContainerNode.swift @@ -121,6 +121,9 @@ private struct ShareSearchPeerEntry: Comparable, Identifiable { if lhs.peer != rhs.peer { return false } + if lhs.theme !== rhs.theme { + return false + } return true } @@ -164,6 +167,8 @@ private func preparedRecentEntryTransition(context: AccountContext, from fromEnt final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { private let sharedContext: SharedAccountContext private let context: AccountContext + private var theme: PresentationTheme + private let themePromise: Promise private let strings: PresentationStrings private let controllerInteraction: ShareControllerInteraction @@ -196,6 +201,9 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { init(sharedContext: SharedAccountContext, context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: ShareControllerInteraction, recentPeers recentPeerList: [RenderedPeer]) { self.sharedContext = sharedContext self.context = context + self.theme = theme + self.themePromise = Promise() + self.themePromise.set(.single(theme)) self.strings = strings self.controllerInteraction = controllerInteraction @@ -237,8 +245,8 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { self.cancelButtonNode.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) - let foundItems = self.searchQuery.get() - |> mapToSignal { query -> Signal<([ShareSearchPeerEntry]?, Bool), NoError> in + let foundItems = combineLatest(self.searchQuery.get(), self.themePromise.get()) + |> mapToSignal { query, theme -> Signal<([ShareSearchPeerEntry]?, Bool), NoError> in if !query.isEmpty { let accountPeer = context.account.postbox.loadedPeerWithId(context.account.peerId) |> take(1) let foundLocalPeers = context.account.postbox.searchPeers(query: query.lowercased()) @@ -354,8 +362,8 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { } |> distinctUntilChanged - let recentItems: Signal<[ShareSearchRecentEntry], NoError> = hasRecentPeers - |> map { hasRecentPeers -> [ShareSearchRecentEntry] in + let recentItems: Signal<[ShareSearchRecentEntry], NoError> = combineLatest(hasRecentPeers, self.themePromise.get()) + |> map { hasRecentPeers, theme -> [ShareSearchRecentEntry] in var recentItemList: [ShareSearchRecentEntry] = [] if hasRecentPeers { recentItemList.append(.topPeers(theme, strings)) @@ -404,6 +412,14 @@ final class ShareSearchContainerNode: ASDisplayNode, ShareContentContainerNode { self.searchNode.deactivateInput() } + func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + self.themePromise.set(.single(theme)) + self.searchNode.updateTheme(theme) + self.contentSeparatorNode.backgroundColor = theme.actionSheet.opaqueItemSeparatorColor + self.cancelButtonNode.setTitle(self.strings.Common_Cancel, with: cancelFont, with: self.theme.actionSheet.controlAccentColor, for: []) + } + private func calculateMetrics(size: CGSize) -> (topInset: CGFloat, itemWidth: CGFloat) { let itemCount: Int if self.contentGridNode.isHidden { diff --git a/submodules/ShareController/Sources/ShareTopicsContainerNode.swift b/submodules/ShareController/Sources/ShareTopicsContainerNode.swift index a417ebb502..f4f6f076fc 100644 --- a/submodules/ShareController/Sources/ShareTopicsContainerNode.swift +++ b/submodules/ShareController/Sources/ShareTopicsContainerNode.swift @@ -42,6 +42,9 @@ private struct ShareTopicEntry: Comparable, Identifiable { if lhs.threadData != rhs.threadData { return false } + if lhs.theme !== rhs.theme { + return false + } return true } @@ -157,7 +160,8 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode { private let sharedContext: SharedAccountContext private let context: AccountContext - private let theme: PresentationTheme + private var theme: PresentationTheme + private let themePromise: Promise private let strings: PresentationStrings private let controllerInteraction: ShareControllerInteraction @@ -184,6 +188,8 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode { self.sharedContext = sharedContext self.context = context self.theme = theme + self.themePromise = Promise() + self.themePromise.set(.single(theme)) self.strings = strings self.controllerInteraction = controllerInteraction @@ -192,8 +198,8 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode { return $0.items }) - let items: Signal<[ShareTopicEntry], NoError> = self.topicsValue.get() - |> map { topics -> [ShareTopicEntry] in + let items: Signal<[ShareTopicEntry], NoError> = (combineLatest(self.topicsValue.get(), self.themePromise.get())) + |> map { topics, theme -> [ShareTopicEntry] in var entries: [ShareTopicEntry] = [] var index: Int32 = 0 @@ -269,7 +275,7 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode { } } } - + private func dequeueTransition() { if let (transition, _) = self.enqueuedTransitions.first { self.enqueuedTransitions.remove(at: 0) @@ -368,6 +374,13 @@ final class ShareTopicsContainerNode: ASDisplayNode, ShareContentContainerNode { } } + public func updateTheme(_ theme: PresentationTheme) { + self.theme = theme + self.themePromise.set(.single(theme)) + self.contentTitleNode.attributedText = NSAttributedString(string: self.contentTitleNode.attributedText?.string ?? "", font: Font.medium(20.0), textColor: self.theme.actionSheet.primaryTextColor) + self.contentSubtitleNode.attributedText = NSAttributedString(string: self.contentSubtitleNode.attributedText?.string ?? "", font: subtitleFont, textColor: self.theme.actionSheet.secondaryTextColor) + } + func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let firstLayout = self.validLayout == nil self.validLayout = (size, bottomInset) diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift index e563b4acc8..55646590ff 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift @@ -690,6 +690,11 @@ final class VoiceChatPreviewContentNode: ASDisplayNode, ShareContentContainerNod self.contentOffsetUpdated = f } + func updateTheme(_ theme: PresentationTheme) { + self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor) + self.countNode.attributedText = NSAttributedString(string: self.countNode.attributedText?.string ?? "", font: Font.regular(16.0), textColor: theme.actionSheet.secondaryTextColor) + } + func updateLayout(size: CGSize, isLandscape: Bool, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { let sideInset: CGFloat = 16.0 let titleSize = self.titleNode.updateLayout(CGSize(width: size.width - sideInset * 2.0, height: size.height)) diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index 8b690c0a92..6d085c2171 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -895,9 +895,60 @@ private final class GroupHeaderLayer: UIView { } } + var clearSize: CGSize = .zero + var clearWidth: CGFloat = 0.0 + if hasClear { + var updateImage = themeUpdated + + let clearIconLayer: SimpleLayer + if let current = self.clearIconLayer { + clearIconLayer = current + } else { + updateImage = true + clearIconLayer = SimpleLayer() + self.clearIconLayer = clearIconLayer + self.layer.addSublayer(clearIconLayer) + } + let tintClearIconLayer: SimpleLayer + if let current = self.tintClearIconLayer { + tintClearIconLayer = current + } else { + updateImage = true + tintClearIconLayer = SimpleLayer() + self.tintClearIconLayer = tintClearIconLayer + self.tintContentLayer.addSublayer(tintClearIconLayer) + } + + tintClearIconLayer.isHidden = !needsVibrancy + + clearSize = clearIconLayer.bounds.size + if updateImage, let image = PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: theme.chat.inputMediaPanel.panelContentVibrantOverlayColor) { + clearSize = image.size + clearIconLayer.contents = image.cgImage + } + if updateImage, let image = PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: .white) { + tintClearIconLayer.contents = image.cgImage + } + + tintClearIconLayer.frame = clearIconLayer.frame + clearWidth = 4.0 + clearSize.width + } else { + if let clearIconLayer = self.clearIconLayer { + self.clearIconLayer = nil + clearIconLayer.removeFromSuperlayer() + } + if let tintClearIconLayer = self.tintClearIconLayer { + self.tintClearIconLayer = nil + tintClearIconLayer.removeFromSuperlayer() + } + } + var textConstrainedWidth = constrainedSize.width - titleHorizontalOffset - 10.0 if let actionButtonSize = actionButtonSize { - textConstrainedWidth -= actionButtonSize.width - 8.0 + textConstrainedWidth -= actionButtonSize.width - 10.0 + } + if clearWidth > 0.0 { + textConstrainedWidth -= clearWidth + 8.0 } let textSize: CGSize @@ -915,13 +966,14 @@ private final class GroupHeaderLayer: UIView { } let string = NSAttributedString(string: stringValue, font: font, textColor: color) let whiteString = NSAttributedString(string: stringValue, font: font, textColor: .white) - let stringBounds = string.boundingRect(with: CGSize(width: textConstrainedWidth, height: 100.0), options: .usesLineFragmentOrigin, context: nil) + let stringBounds = string.boundingRect(with: CGSize(width: textConstrainedWidth, height: 18.0), options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine], context: nil) textSize = CGSize(width: ceil(stringBounds.width), height: ceil(stringBounds.height)) self.textLayer.contents = generateImage(textSize, opaque: false, scale: 0.0, rotatedContext: { size, context in context.clear(CGRect(origin: CGPoint(), size: size)) UIGraphicsPushContext(context) - string.draw(in: stringBounds) + //string.draw(in: stringBounds) + string.draw(with: stringBounds, options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine], context: nil) UIGraphicsPopContext() })?.cgImage @@ -929,7 +981,8 @@ private final class GroupHeaderLayer: UIView { context.clear(CGRect(origin: CGPoint(), size: size)) UIGraphicsPushContext(context) - whiteString.draw(in: stringBounds) + //whiteString.draw(in: stringBounds) + whiteString.draw(with: stringBounds, options: [.usesLineFragmentOrigin, .truncatesLastVisibleLine], context: nil) UIGraphicsPopContext() })?.cgImage @@ -1062,54 +1115,7 @@ private final class GroupHeaderLayer: UIView { } } - var clearWidth: CGFloat = 0.0 - if hasClear { - var updateImage = themeUpdated - - let clearIconLayer: SimpleLayer - if let current = self.clearIconLayer { - clearIconLayer = current - } else { - updateImage = true - clearIconLayer = SimpleLayer() - self.clearIconLayer = clearIconLayer - self.layer.addSublayer(clearIconLayer) - } - let tintClearIconLayer: SimpleLayer - if let current = self.tintClearIconLayer { - tintClearIconLayer = current - } else { - updateImage = true - tintClearIconLayer = SimpleLayer() - self.tintClearIconLayer = tintClearIconLayer - self.tintContentLayer.addSublayer(tintClearIconLayer) - } - - tintClearIconLayer.isHidden = !needsVibrancy - - var clearSize = clearIconLayer.bounds.size - if updateImage, let image = PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: theme.chat.inputMediaPanel.panelContentVibrantOverlayColor) { - clearSize = image.size - clearIconLayer.contents = image.cgImage - } - if updateImage, let image = PresentationResourcesChat.chatInputMediaPanelGridDismissImage(theme, color: .white) { - tintClearIconLayer.contents = image.cgImage - } - - clearIconLayer.frame = CGRect(origin: CGPoint(x: constrainedSize.width - clearSize.width, y: floorToScreenPixels((textSize.height - clearSize.height) / 2.0)), size: clearSize) - - tintClearIconLayer.frame = clearIconLayer.frame - clearWidth = 4.0 + clearSize.width - } else { - if let clearIconLayer = self.clearIconLayer { - self.clearIconLayer = nil - clearIconLayer.removeFromSuperlayer() - } - if let tintClearIconLayer = self.tintClearIconLayer { - self.tintClearIconLayer = nil - tintClearIconLayer.removeFromSuperlayer() - } - } + self.clearIconLayer?.frame = CGRect(origin: CGPoint(x: constrainedSize.width - clearSize.width, y: floorToScreenPixels((textSize.height - clearSize.height) / 2.0)), size: clearSize) var size: CGSize size = CGSize(width: constrainedSize.width, height: constrainedSize.height) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 174b076b53..432736e36b 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -14576,33 +14576,50 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let peerId = self.chatLocation.peerId else { return } + + var isScheduledMessages = false + if case .scheduledMessages = self.presentationInterfaceState.subject { + isScheduledMessages = true + } - let replyMessageId = self.presentationInterfaceState.interfaceState.replyMessageId - - if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting) { - self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in - if let strongSelf = self { - strongSelf.chatDisplayNode.collapseInput() - - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in - var state = state - state = state.updatedInterfaceState { interfaceState in - var interfaceState = interfaceState - interfaceState = interfaceState.withUpdatedReplyMessageId(nil) - interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) - interfaceState = interfaceState.withUpdatedComposeDisableUrlPreview(nil) - return interfaceState - } - state = state.updatedInputMode { current in - if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil { - return .media(mode: mode, expanded: nil, focused: focused) + let sendMessage: (Int32?) -> Void = { [weak self] scheduleTime in + guard let self else { + return + } + let replyMessageId = self.presentationInterfaceState.interfaceState.replyMessageId + if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageId, hideVia: hideVia, silentPosting: silentPosting) { + self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in + if let strongSelf = self { + strongSelf.chatDisplayNode.collapseInput() + + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in + var state = state + state = state.updatedInterfaceState { interfaceState in + var interfaceState = interfaceState + interfaceState = interfaceState.withUpdatedReplyMessageId(nil) + interfaceState = interfaceState.withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) + interfaceState = interfaceState.withUpdatedComposeDisableUrlPreview(nil) + return interfaceState } - return current - } - return state - }) - } - }, nil) + state = state.updatedInputMode { current in + if case let .media(mode, maybeExpanded, focused) = current, maybeExpanded != nil { + return .media(mode: mode, expanded: nil, focused: focused) + } + return current + } + return state + }) + } + }, nil) + } + } + + if isScheduledMessages { + self.presentScheduleTimePicker(style: .default, dismissByTapOutside: false, completion: { time in + sendMessage(time) + }) + } else { + sendMessage(nil) } } @@ -14750,6 +14767,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.updateRecordedMediaDeleted(true) self.audioRecorder.set(.single(nil)) case .preview: + self.audioRecorder.set(.single(nil)) self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInputTextPanelState { panelState in return panelState.withUpdatedMediaRecordingState(.waitingForPreview) @@ -14779,7 +14797,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } }) - self.audioRecorder.set(.single(nil)) case .send: self.chatDisplayNode.updateRecordedMediaDeleted(false) let _ = (audioRecorderValue.takenRecordedData() diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift index 50d791ef28..8aa2b1dab7 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextQueries.swift @@ -473,15 +473,30 @@ func searchQuerySuggestionResultStateForChatInterfacePresentationState(_ chatPre signal = .single({ _ in return nil }) } } - - let participants = searchPeerMembers(context: context, peerId: peer.id, chatLocation: chatPresentationInterfaceState.chatLocation, query: query, scope: .memberSuggestion) - |> map { peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in + + let participants = combineLatest( + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId)), + searchPeerMembers(context: context, peerId: peer.id, chatLocation: chatPresentationInterfaceState.chatLocation, query: query, scope: .memberSuggestion) + ) + |> map { accountPeer, peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in let filteredPeers = peers var sortedPeers: [EnginePeer] = [] sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in let result = lhs.indexName.stringRepresentation(lastNameFirst: true).compare(rhs.indexName.stringRepresentation(lastNameFirst: true)) return result == .orderedAscending })) + if let accountPeer { + var hasOwnPeer = false + for peer in sortedPeers { + if peer.id == accountPeer.id { + hasOwnPeer = true + break + } + } + if !hasOwnPeer { + sortedPeers.append(accountPeer) + } + } return { _ in return .mentions(sortedPeers) } } diff --git a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift index 5851b5bc98..37bfbae403 100644 --- a/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageTextBubbleContentNode.swift @@ -401,7 +401,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { reactionPeers: dateReactionsAndPeers.peers, displayAllReactionPeers: item.message.id.peerId.namespace == Namespaces.Peer.CloudUser, replyCount: dateReplies, - isPinned: item.message.tags.contains(.pinned) && !item.associatedData.isInPinnedListMode && isReplyThread, + isPinned: item.message.tags.contains(.pinned) && (!item.associatedData.isInPinnedListMode || isReplyThread), hasAutoremove: item.message.isSelfExpiring, canViewReactionList: canViewMessageReactionList(message: item.message), animationCache: item.controllerInteraction.presentationContext.animationCache, diff --git a/submodules/TelegramUI/Sources/ChatScheduleTimeControllerNode.swift b/submodules/TelegramUI/Sources/ChatScheduleTimeControllerNode.swift index d6f0206005..0a7936716d 100644 --- a/submodules/TelegramUI/Sources/ChatScheduleTimeControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatScheduleTimeControllerNode.swift @@ -388,8 +388,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel let titleHeight: CGFloat = 54.0 var contentHeight = titleHeight + bottomInset + 52.0 + 17.0 let pickerHeight: CGFloat = min(216.0, layout.size.height - contentHeight) - contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + pickerHeight + buttonOffset - + if let inputHeight = layout.inputHeight, inputHeight > 0.0, case .compact = layout.metrics.widthClass { + contentHeight = titleHeight + 52.0 + 17.0 + pickerHeight + inputHeight + buttonOffset = 0.0 + } else { + contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + pickerHeight + buttonOffset + } let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 0.0) let sideInset = floor((layout.size.width - width) / 2.0) @@ -419,7 +423,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 16.0 - buttonOffset, width: contentFrame.width, height: doneButtonHeight)) let onlineButtonHeight = self.onlineButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition) - transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - insets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight)) + transition.updateFrame(node: self.onlineButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - cleanInsets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight)) self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight)) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index e86b38b41b..63e5c64bdd 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1064,6 +1064,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { let textFieldWaitsForTouchUp: Bool if case .regular = metrics.widthClass, bottomInset.isZero { textFieldWaitsForTouchUp = true + } else if !textInputNode.textView.text.isEmpty { + textFieldWaitsForTouchUp = true } else { textFieldWaitsForTouchUp = false } @@ -1700,7 +1702,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { hideInfo = true } case .waitingForPreview: - break + Queue.mainQueue().after(0.3, { + self.actionButtons.micButton.audioRecorder = nil + }) } }