diff --git a/Telegram/BUILD b/Telegram/BUILD index af18262d33..7220af61dc 100644 --- a/Telegram/BUILD +++ b/Telegram/BUILD @@ -309,6 +309,8 @@ alternate_icon_folders = [ "PremiumTurbo", ] +composer_icon_folders = ["Telegram"] + [ filegroup( name = "{}".format(name), @@ -318,6 +320,15 @@ alternate_icon_folders = [ ) for name in alternate_icon_folders ] +[ + filegroup( + name = "{}_icon".format(name), + srcs = glob([ + "Telegram-iOS/{}.icon/**/*".format(name), + ]), + ) for name in composer_icon_folders +] + filegroup( name = "LaunchScreen", srcs = glob([ @@ -1699,12 +1710,13 @@ ios_application( ":RequiredDeviceCapabilitiesPlist", ":UrlTypesInfoPlist", ], + app_icons = [ ":{}_icon".format(name) for name in composer_icon_folders ], alternate_icons = [ ":{}".format(name) for name in alternate_icon_folders ], resources = [ ":LaunchScreen", - ":DefaultAppIcon", + #":DefaultAppIcon", ], frameworks = [ ":MtProtoKitFramework", diff --git a/Telegram/Telegram-iOS/Telegram.icon/Assets/Oval.svg b/Telegram/Telegram-iOS/Telegram.icon/Assets/Oval.svg new file mode 100644 index 0000000000..c3e47858d3 --- /dev/null +++ b/Telegram/Telegram-iOS/Telegram.icon/Assets/Oval.svg @@ -0,0 +1,7 @@ + + + Oval + + + + \ No newline at end of file diff --git a/Telegram/Telegram-iOS/Telegram.icon/Assets/Plane.svg b/Telegram/Telegram-iOS/Telegram.icon/Assets/Plane.svg new file mode 100644 index 0000000000..e475bcfde7 --- /dev/null +++ b/Telegram/Telegram-iOS/Telegram.icon/Assets/Plane.svg @@ -0,0 +1,7 @@ + + + Plane + + + + \ No newline at end of file diff --git a/Telegram/Telegram-iOS/Telegram.icon/icon.json b/Telegram/Telegram-iOS/Telegram.icon/icon.json new file mode 100644 index 0000000000..b1143f6343 --- /dev/null +++ b/Telegram/Telegram-iOS/Telegram.icon/icon.json @@ -0,0 +1,122 @@ +{ + "fill" : "system-light", + "groups" : [ + { + "blend-mode" : "normal", + "blur-material" : 1, + "layers" : [ + { + "blend-mode-specializations" : [ + { + "value" : "normal" + }, + { + "appearance" : "dark", + "value" : "normal" + } + ], + "fill-specializations" : [ + { + "appearance" : "dark", + "value" : "automatic" + } + ], + "glass" : true, + "image-name" : "Plane.svg", + "name" : "Plane", + "position-specializations" : [ + { + "idiom" : "watchOS", + "value" : { + "scale" : 1.35, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ] + }, + { + "blend-mode-specializations" : [ + { + "value" : "normal" + }, + { + "appearance" : "dark", + "value" : "normal" + } + ], + "fill-specializations" : [ + { + "value" : { + "linear-gradient" : [ + "display-p3:0.21569,0.68627,0.89020,1.00000", + "srgb:0.11373,0.57647,0.82353,1.00000" + ] + } + }, + { + "appearance" : "dark", + "value" : { + "automatic-gradient" : "srgb:0.00000,0.47843,1.00000,1.00000" + } + } + ], + "glass" : true, + "hidden-specializations" : [ + { + "value" : false + }, + { + "idiom" : "watchOS", + "value" : false + } + ], + "image-name" : "Oval.svg", + "name" : "Oval", + "position-specializations" : [ + { + "idiom" : "watchOS", + "value" : { + "scale" : 2, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ] + } + ], + "lighting" : "combined", + "position-specializations" : [ + { + "idiom" : "watchOS", + "value" : { + "scale" : 1, + "translation-in-points" : [ + 0, + 0 + ] + } + } + ], + "shadow" : { + "kind" : "layer-color", + "opacity" : 1 + }, + "specular" : true, + "translucency" : { + "enabled" : false, + "value" : 1 + } + } + ], + "supported-platforms" : { + "circles" : [ + "watchOS" + ], + "squares" : "shared" + } +} \ No newline at end of file diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 932ddc3e51..29050a4419 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -15077,3 +15077,14 @@ Error: %8$@"; "Conversation.SuggestedBirthdate.View" = "View"; "PeerInfo.ChangeProfileColor" = "Change Profile Color"; + +"PUSH_MESSAGE_TODO" = "%1$@|sent you a todo-list %2$@"; +"PUSH_CHANNEL_MESSAGE_TODO" = "%1$@|posted a todo-list %2$@"; +"PUSH_CHANNEL_MESSAGE_TODO_DONE" = "%1$@|toggled %2$@ tasks"; +"PUSH_CHANNEL_MESSAGE_TODO_APPEND" = "%1$@|added %2$@ tasks"; +"PUSH_CHAT_MESSAGE_TODO" = "%2$@|%1$@ sent a todo-list %3$@"; +"PUSH_CHAT_MESSAGE_TODO_DONE" = "%2$@|%1$@ toggled %3$@ tasks"; +"PUSH_CHAT_MESSAGE_TODO_APPEND" = "%2$@|%1$@ added %3$@ tasks"; +"PUSH_PINNED_TODO" = "%1$@|pinned a todo-list %2$@"; +"PUSH_REACT_TODO" = "%1$@|reacted %2$@ to your todo %3$@"; +"PUSH_CHAT_REACT_TODO" = "%2$@|%1$@ reacted %3$@ to your todo %4$@"; diff --git a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift index 261ccc1b6d..cfcd09a668 100644 --- a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift +++ b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift @@ -700,6 +700,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS let hadLayout = self.validLayout != nil let previousAdditionalSideInsets = self.validLayout?.3 self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) + + let leftInset = leftInset + 8.0 + let rightInset = rightInset + 8.0 var transition = transition if let previousAdditionalSideInsets = previousAdditionalSideInsets, previousAdditionalSideInsets.right != additionalSideInsets.right { @@ -933,9 +936,13 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS } private func updateFieldAndButtonsLayout(inputHasText: Bool, panelHeight: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { - guard let (width, leftInset, rightInset, additionalSideInsets, _, metrics, _) = self.validLayout else { + guard let (width, leftInsetValue, rightInsetValue, additionalSideInsets, _, metrics, _) = self.validLayout else { return 0.0 } + + let leftInset = leftInsetValue + 8.0 + let rightInset = rightInsetValue + 8.0 + var textFieldMinHeight: CGFloat = 33.0 if let presentationInterfaceState = self.presentationInterfaceState { textFieldMinHeight = calclulateTextFieldMinHeight(presentationInterfaceState, metrics: metrics) @@ -1280,6 +1287,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS if let (width, leftInset, rightInset, _, maxHeight, metrics, _) = self.validLayout { let composeButtonsOffset: CGFloat = 0.0 + let leftInset = leftInset + 8.0 + let rightInset = rightInset + 8.0 + let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset, maxHeight: maxHeight, metrics: metrics) let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics) var textFieldMinHeight: CGFloat = 33.0 @@ -1421,6 +1431,9 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS private func updateTextHeight(animated: Bool) -> CGFloat? { if let (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, _) = self.validLayout { + let leftInset = leftInset + 8.0 + let rightInset = rightInset + 8.0 + let (_, textFieldHeight) = self.calculateTextFieldMetrics(width: width - leftInset - rightInset - additionalSideInsets.right, maxHeight: maxHeight, metrics: metrics) let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight, metrics: metrics) if !self.bounds.size.height.isEqual(to: panelHeight) { diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 9eab22c3d7..933db76461 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -124,14 +124,16 @@ public enum ChatListItemContent { public var hideSeparator: Bool public var hideDate: Bool public var hidePeerStatus: Bool + public var isInTransparentContainer: Bool - public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool, hidePeerStatus: Bool) { + public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool, hidePeerStatus: Bool, isInTransparentContainer: Bool = false) { self.commandPrefix = commandPrefix self.searchQuery = searchQuery self.messageCount = messageCount self.hideSeparator = hideSeparator self.hideDate = hideDate self.hidePeerStatus = hidePeerStatus + self.isInTransparentContainer = isInTransparentContainer } } @@ -1966,6 +1968,11 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { reallyHighlighted = true } } + if case let .peer(peerData) = item.content, let customMessageListData = peerData.customMessageListData { + if customMessageListData.isInTransparentContainer { + reallyHighlighted = false + } + } } return reallyHighlighted } diff --git a/submodules/Display/Source/CAAnimationUtils.swift b/submodules/Display/Source/CAAnimationUtils.swift index 73cc4f6e26..11d512fa51 100644 --- a/submodules/Display/Source/CAAnimationUtils.swift +++ b/submodules/Display/Source/CAAnimationUtils.swift @@ -104,7 +104,34 @@ public extension CALayer { return animation } else if timingFunction == kCAMediaTimingFunctionSpring { - if duration == 0.5 { + if #available(iOS 26.0, *) { + let animation = make26SpringAnimationImpl(keyPath, duration) + animation.fromValue = from + animation.toValue = to + animation.isRemovedOnCompletion = removeOnCompletion + animation.fillMode = .forwards + if let completion { + animation.delegate = CALayerAnimationDelegate(animation: animation, completion: completion) + } + + let k = Float(UIView.animationDurationFactor()) + var speed: Float = 1.0 + if k != 0 && k != 1 { + speed = Float(1.0) / k + } + + animation.speed = speed * Float(animation.duration / duration) + animation.isAdditive = additive + + if !delay.isZero { + animation.beginTime = self.convertTime(CACurrentMediaTime(), from: nil) + delay * UIView.animationDurationFactor() + animation.fillMode = .both + } + + adjustFrameRate(animation: animation) + + return animation + } else if duration == 0.5 { let animation = makeSpringAnimation(keyPath) animation.fromValue = from animation.toValue = to diff --git a/submodules/Display/Source/UIKitUtils.swift b/submodules/Display/Source/UIKitUtils.swift index 0b109eb7d1..229b9b77f0 100644 --- a/submodules/Display/Source/UIKitUtils.swift +++ b/submodules/Display/Source/UIKitUtils.swift @@ -900,3 +900,54 @@ public extension CGPoint { return CGPoint(x: self.x + dx, y: self.y + dy) } } + +public extension UIView { + func setMonochromaticEffect(tintColor: UIColor?) { + var overrideUserInterfaceStyle: UIUserInterfaceStyle = .unspecified + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + if let tintColor { + if tintColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) { + if red == 0.0 && green == 0.0 && blue == 0.0 && alpha == 1.0 { + overrideUserInterfaceStyle = .light + } + } else { + if red == 1.0 && green == 1.0 && blue == 1.0 && alpha == 1.0 { + overrideUserInterfaceStyle = .dark + } + } + } + + if self.overrideUserInterfaceStyle != overrideUserInterfaceStyle { + self.overrideUserInterfaceStyle = overrideUserInterfaceStyle + setMonochromaticEffectImpl(self, overrideUserInterfaceStyle != .unspecified) + } + } + + func setMonochromaticEffectAndAlpha(tintColor: UIColor?, transition: ContainedViewLayoutTransition) { + var overrideUserInterfaceStyle: UIUserInterfaceStyle = .unspecified + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + if let tintColor { + if tintColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) { + if red == 0.0 && green == 0.0 && blue == 0.0 { + overrideUserInterfaceStyle = .light + } + } else { + if red == 1.0 && green == 1.0 && blue == 1.0 { + overrideUserInterfaceStyle = .dark + } + } + } + + if self.overrideUserInterfaceStyle != overrideUserInterfaceStyle { + self.overrideUserInterfaceStyle = overrideUserInterfaceStyle + setMonochromaticEffectImpl(self, overrideUserInterfaceStyle != .unspecified) + } + transition.updateAlpha(layer: self.layer, alpha: alpha) + } +} diff --git a/submodules/Display/Source/WindowContent.swift b/submodules/Display/Source/WindowContent.swift index e5270bdae2..9eab40c43a 100644 --- a/submodules/Display/Source/WindowContent.swift +++ b/submodules/Display/Source/WindowContent.swift @@ -604,7 +604,10 @@ public class Window1 { var duration: Double = (notification.userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber)?.doubleValue ?? 0.0 if duration > Double.ulpOfOne { - duration = 0.5 + if #available(iOS 26.0, *) { + } else { + duration = 0.5 + } } let curve: UInt = (notification.userInfo?[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber)?.uintValue ?? 7 diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift index cfca87664f..18a195c993 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift @@ -2232,7 +2232,7 @@ final class VideoChatScreenComponent: Component { color: .white )), background: AnyComponent( - GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014))) + GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014))) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), @@ -2254,7 +2254,7 @@ final class VideoChatScreenComponent: Component { image: closeButtonImage(dark: false) )), background: AnyComponent( - GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014))) + GlassBackgroundComponent(size: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), isDark: true, tintColor: .init(kind: .custom, color: UIColor(rgb: 0x101014))) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index 97f506b2a3..b38b9de3bd 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -663,14 +663,14 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000), panelSeparatorColor: UIColor(rgb: 0x545458, alpha: 0.55), panelControlAccentColor: UIColor(rgb: 0xffffff), - panelControlColor: UIColor(rgb: 0x808080), + panelControlColor: UIColor(rgb: 0xffffff), panelControlDisabledColor: UIColor(rgb: 0x808080, alpha: 0.5), panelControlDestructiveColor: UIColor(rgb: 0xff3b30), inputBackgroundColor: UIColor(rgb: 0x060606), inputStrokeColor: UIColor(rgb: 0xffffff, alpha: 0.1), inputPlaceholderColor: UIColor(rgb: 0x7b7b7b), inputTextColor: UIColor(rgb: 0xffffff), - inputControlColor: UIColor(rgb: 0x7b7b7b), + inputControlColor: UIColor(rgb: 0xffffff), actionControlFillColor: UIColor(rgb: 0xffffff), actionControlForegroundColor: UIColor(rgb: 0x000000), primaryTextColor: UIColor(rgb: 0xffffff), diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index a8848b51ae..5bfbee3634 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -943,17 +943,17 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff), panelSeparatorColor: UIColor(white: 1.0, alpha: 0.5), panelControlAccentColor: defaultDayAccentColor, - panelControlColor: UIColor(rgb: 0x858e99), + panelControlColor: UIColor(rgb: 0x000000, alpha: 1.0), panelControlDisabledColor: UIColor(rgb: 0x727b87, alpha: 0.5), panelControlDestructiveColor: UIColor(rgb: 0xff3b30), inputBackgroundColor: UIColor(rgb: 0xffffff), inputStrokeColor: UIColor(rgb: 0x000000, alpha: 0.1), - inputPlaceholderColor: UIColor(rgb: 0x202020, alpha: 0.4), + inputPlaceholderColor: UIColor(rgb: 0x000000, alpha: 0.4), inputTextColor: UIColor(rgb: 0x000000), - inputControlColor: UIColor(rgb: 0x202020, alpha: 0.6), + inputControlColor: UIColor(rgb: 0x000000, alpha: 1.0), actionControlFillColor: defaultDayAccentColor, actionControlForegroundColor: UIColor(rgb: 0xffffff), - primaryTextColor: UIColor(rgb: 0x000000, alpha: 0.9), + primaryTextColor: UIColor(rgb: 0x000000, alpha: 1.0), secondaryTextColor: UIColor(rgb: 0x202020, alpha: 0.6), mediaRecordingDotColor: UIColor(rgb: 0xed2521), mediaRecordingControl: inputPanelMediaRecordingControl diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift index fbb1e283bb..72528395d0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageActionBubbleContentNode/Sources/ChatMessageActionBubbleContentNode.swift @@ -57,6 +57,10 @@ public class ChatMessageActionBubbleContentNode: ChatMessageBubbleContentNode { private var cachedMaskBackgroundImage: (CGPoint, UIImage, [CGRect])? private var absoluteRect: (CGRect, CGSize)? + override public var disablesClipping: Bool { + return true + } + override public var visibility: ListViewItemNodeVisibility { didSet { if oldValue != self.visibility { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index 61f056323c..547b785ab5 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -3442,14 +3442,14 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI contentContainerNodeFrames: contentContainerNodeFrames.map { containerGroupId, containerFrame, currentItemSelection, currentContainerGroupOverlap in return (containerGroupId, containerFrame.offsetBy(dx: 0.0, dy: layoutInsets.top), currentItemSelection, currentContainerGroupOverlap) }, - mosaicStatusOrigin: mosaicStatusOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top), + mosaicStatusOrigin: mosaicStatusOrigin, mosaicStatusSizeAndApply: mosaicStatusSizeAndApply, - unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top), + unlockButtonPosition: unlockButtonPosition?.offsetBy(dx: 0.0, dy: layoutInsets.top), unlockButtonSizeAndApply: unlockButtonSizeApply, mediaInfoOrigin: mediaInfoOrigin?.offsetBy(dx: 0.0, dy: layoutInsets.top), mediaInfoSizeAndApply: mediaInfoSizeApply, needsShareButton: needsShareButton, - shareButtonOffset: shareButtonOffset?.offsetBy(dx: 0.0, dy: layoutInsets.top), + shareButtonOffset: shareButtonOffset, avatarOffset: avatarOffset, hidesHeaders: hidesHeaders, disablesComments: disablesComments, diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index 1a19cf132f..61b827f232 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -86,6 +86,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { private var currentProgressDisposable: Disposable? + override public var disablesClipping: Bool { + return true + } + override public var visibility: ListViewItemNodeVisibility { didSet { let wasVisible = oldValue != .none diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift index 14cd78cf46..89a2d43fb0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode/Sources/ChatMessageSelectionInputPanelNode.swift @@ -449,10 +449,10 @@ public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) var leftInset = leftInset - leftInset += 8.0 + leftInset += 16.0 var rightInset = rightInset - rightInset += 8.0 + rightInset += 16.0 let panelHeight = defaultHeight(metrics: metrics) diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift index 8f94a44ff8..d54bbcfe41 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputActionButtonsNode/Sources/ChatTextInputActionButtonsNode.swift @@ -197,6 +197,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag self.expandMediaInputButtonBackgroundView.contentView.addSubview(self.expandMediaInputButtonIcon) self.expandMediaInputButtonIcon.image = PresentationResourcesChat.chatInputPanelExpandButtonImage(presentationInterfaceState.theme) self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor + self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor) super.init() @@ -265,6 +266,7 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag public func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) { self.micButton.updateTheme(theme: theme) self.expandMediaInputButtonIcon.tintColor = theme.chat.inputPanel.inputControlColor + self.expandMediaInputButtonIcon.setMonochromaticEffect(tintColor: theme.chat.inputPanel.inputControlColor) } private var absoluteRect: (CGRect, CGSize)? @@ -352,8 +354,8 @@ public final class ChatTextInputActionButtonsNode: ASDisplayNode, ChatSendMessag self.expandMediaInputButtonBackgroundView.update(size: size, cornerRadius: size.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition)) if let image = self.expandMediaInputButtonIcon.image { let expandIconFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) * 0.5), y: floor((size.height - image.size.height) * 0.5)), size: image.size) - transition.updatePosition(layer: self.expandMediaInputButtonIcon.layer, position: expandIconFrame.center) - transition.updateBounds(layer: self.expandMediaInputButtonIcon.layer, bounds: CGRect(origin: CGPoint(), size: expandIconFrame.size)) + self.expandMediaInputButtonIcon.center = expandIconFrame.center + self.expandMediaInputButtonIcon.bounds = CGRect(origin: CGPoint(), size: expandIconFrame.size) transition.updateTransformScale(layer: self.expandMediaInputButtonIcon.layer, scale: CGPoint(x: 1.0, y: isMediaInputExpanded ? 1.0 : -1.0)) } diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift index 84218bb179..74bb336023 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/AccessoryItemIconButton.swift @@ -16,8 +16,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie private var theme: PresentationTheme private var strings: PresentationStrings private var width: CGFloat - private let iconImageView: UIImageView - private let tintMaskIconImageView: UIImageView + private let iconImageView: GlassBackgroundView.ContentImageView private var textView: ImmediateTextView? private var tintMaskTextView: ImmediateTextView? private var animationView: ComponentView? @@ -34,8 +33,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie self.theme = theme self.strings = strings - self.iconImageView = UIImageView() - self.tintMaskIconImageView = UIImageView() + self.iconImageView = GlassBackgroundView.ContentImageView() let (image, text, accessibilityLabel, alpha, _) = AccessoryItemIconButton.imageAndInsets(item: item, theme: theme, strings: strings) @@ -51,12 +49,11 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie self.iconImageView.isUserInteractionEnabled = false self.addSubview(self.iconImageView) - self.tintMask.addSubview(self.tintMaskIconImageView) + self.tintMask.addSubview(self.iconImageView.tintMask) switch item { case .input, .botInput, .silentPost: self.iconImageView.isHidden = true - self.tintMaskIconImageView.isHidden = self.iconImageView.isHidden self.animationView = ComponentView() self.tintMaskAnimationView = UIImageView() default: @@ -93,10 +90,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor self.iconImageView.alpha = alpha - self.tintMaskIconImageView.image = self.iconImageView.image - self.tintMaskIconImageView.tintColor = .black - self.tintMaskIconImageView.alpha = self.iconImageView.alpha - self.accessibilityLabel = accessibilityLabel self.highligthedChanged = { [weak self] highlighted in @@ -138,10 +131,6 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie self.iconImageView.tintColor = theme.chat.inputPanel.inputControlColor self.iconImageView.alpha = alpha - self.tintMaskIconImageView.image = self.iconImageView.image - self.tintMaskIconImageView.tintColor = .black - self.tintMaskIconImageView.alpha = self.iconImageView.alpha - self.accessibilityLabel = accessibilityLabel } @@ -205,12 +194,13 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie if let image = self.iconImageView.image { self.iconImageView.image = updatedImage - self.tintMaskIconImageView.image = updatedImage let bottomInset: CGFloat = 0.0 - let imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size) + var imageFrame = CGRect(origin: CGPoint(x: floor((size.width - image.size.width) / 2.0), y: floor((size.height - image.size.height) / 2.0) - bottomInset), size: image.size) + if case .scheduledMessages = item { + imageFrame.origin.y += 1.0 + } self.iconImageView.frame = imageFrame - self.tintMaskIconImageView.frame = imageFrame if let animationView = self.animationView { let width = AccessoryItemIconButton.calculateWidth(item: item, image: image, text: "", strings: self.strings) @@ -332,6 +322,7 @@ final class AccessoryItemIconButton: HighlightTrackingButton, GlassBackgroundVie self.tintMask.addSubview(tintMaskAnimationView) } } + view.setMonochromaticEffect(tintColor: self.theme.chat.inputPanel.inputControlColor) let animationFrameValue = CGRect(origin: CGPoint(x: animationFrame.minX + floor((animationFrame.width - animationSize.width) / 2.0), y: animationFrame.minY + floor((animationFrame.height - animationSize.height) / 2.0)), size: animationSize) view.frame = animationFrameValue if let tintMaskAnimationView = self.tintMaskAnimationView { diff --git a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift index 0c19ac9616..dcf2aef9bb 100644 --- a/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatTextInputPanelNode/Sources/ChatTextInputPanelNode.swift @@ -214,11 +214,9 @@ private func makeTextInputTheme(context: AccountContext, interfaceState: ChatPre public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, ChatInputTextNodeDelegate { public let clippingNode: ASDisplayNode public let textPlaceholderNode: ImmediateTextNodeWithEntities - public let tintMaskTextPlaceholderNode: ImmediateTextNodeWithEntities public var textLockIconNode: ASImageNode? public var contextPlaceholderNode: TextNode? - public var tintContextPlaceholderNode: TextNode? public var slowmodePlaceholderNode: ChatTextInputSlowmodePlaceholderNode? public let textInputContainerBackgroundView: GlassBackgroundView public let textInputContainer: ASDisplayNode @@ -521,20 +519,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.textPlaceholderNode.contentsScale = UIScreenScale self.textPlaceholderNode.maximumNumberOfLines = 1 self.textPlaceholderNode.isUserInteractionEnabled = false - - //TODO:release add tinted output instead - self.tintMaskTextPlaceholderNode = ImmediateTextNodeWithEntities() - self.tintMaskTextPlaceholderNode.arguments = TextNodeWithEntities.Arguments( - context: context, - cache: context.animationCache, - renderer: context.animationRenderer, - placeholderColor: .clear, - attemptSynchronous: true - ) - self.tintMaskTextPlaceholderNode.contentMode = .topLeft - self.tintMaskTextPlaceholderNode.contentsScale = UIScreenScale - self.tintMaskTextPlaceholderNode.maximumNumberOfLines = 1 - + self.menuButton = HighlightTrackingButtonNode() self.menuButton.clipsToBounds = true self.menuButton.cornerRadius = 16.0 @@ -566,7 +551,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.attachmentButton.isAccessibilityElement = true self.attachmentButtonBackground = GlassBackgroundView(frame: CGRect()) - self.attachmentButtonBackground.isUserInteractionEnabled = false self.attachmentButton.addSubview(self.attachmentButtonBackground) self.attachmentButtonIcon = GlassBackgroundView.ContentImageView() @@ -785,7 +769,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.clippingNode.addSubnode(self.textInputBackgroundNode) self.textInputContainerBackgroundView.contentView.addSubview(self.textPlaceholderNode.view) - self.textInputContainerBackgroundView.maskContentView.addSubview(self.tintMaskTextPlaceholderNode.view) self.menuButton.view.addSubview(self.menuButtonBackgroundView) self.menuButton.addSubnode(self.menuButtonClippingNode) @@ -1039,6 +1022,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } private func calculateTextFieldMetrics(width: CGFloat, maxHeight: CGFloat, metrics: LayoutMetrics) -> (accessoryButtonsWidth: CGFloat, textFieldHeight: CGFloat, isOverflow: Bool) { + let maxHeight = max(maxHeight, 40.0) + var textFieldInsets = self.textFieldInsets(metrics: metrics) if self.actionButtons.frame.width > 40.0 { textFieldInsets.right = self.actionButtons.frame.width - 2.0 @@ -1076,7 +1061,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg let unboundTextFieldHeight = max(textFieldMinHeight, ceil(measuredHeight)) - let maxNumberOfLines = min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22) + let maxNumberOfLines = max(1, min(12, (Int(fieldMaxHeight - 11.0) - 33) / 22)) let updatedMaxHeight = (CGFloat(maxNumberOfLines) * (22.0 + 2.0) + 10.0) @@ -1256,6 +1241,8 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg ) -> CGFloat { let previousAdditionalSideInsets = self.validLayout?.4 self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, maxOverlayHeight, metrics, isSecondary, isMediaInputExpanded) + + let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor var transition = transition var additionalOffset: CGFloat = 0.0 @@ -2423,21 +2410,16 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg if interfaceState.slowmodeState == nil || isScheduledMessages, let contextPlaceholder = interfaceState.inputTextPanelState.contextPlaceholder { let placeholderLayout = TextNode.asyncLayout(self.contextPlaceholderNode) - let tintPlaceholderLayout = TextNode.asyncLayout(self.tintContextPlaceholderNode) + let contextPlaceholder = NSMutableAttributedString(attributedString: contextPlaceholder) + contextPlaceholder.addAttribute(.foregroundColor, value: placeholderColor.withAlphaComponent(1.0), range: NSRange(location: 0, length: contextPlaceholder.length)) let (placeholderSize, placeholderApply) = placeholderLayout(TextNodeLayoutArguments(attributedString: contextPlaceholder, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - leftInset - rightInset - textFieldInsets.left - textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let tintContextPlaceholder = NSMutableAttributedString(attributedString: contextPlaceholder) tintContextPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(location: 0, length: tintContextPlaceholder.length)) - let (_, tintPlaceholderApply) = tintPlaceholderLayout(TextNodeLayoutArguments(attributedString: tintContextPlaceholder, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - leftInset - rightInset - textFieldInsets.left - textFieldInsets.right - self.textInputViewInternalInsets.left - self.textInputViewInternalInsets.right - accessoryButtonsWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let contextPlaceholderNode = placeholderApply() - let tintContextPlaceholderNode = tintPlaceholderApply() if let currentContextPlaceholderNode = self.contextPlaceholderNode, currentContextPlaceholderNode !== contextPlaceholderNode { self.contextPlaceholderNode = nil currentContextPlaceholderNode.removeFromSupernode() } - if let currentTintContextPlaceholderNode = self.tintContextPlaceholderNode, currentTintContextPlaceholderNode !== tintContextPlaceholderNode { - self.tintContextPlaceholderNode = nil - currentTintContextPlaceholderNode.removeFromSupernode() - } if self.contextPlaceholderNode !== contextPlaceholderNode { contextPlaceholderNode.displaysAsynchronously = false @@ -2445,12 +2427,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.contextPlaceholderNode = contextPlaceholderNode self.textInputContainerBackgroundView.contentView.insertSubview(contextPlaceholderNode.view, aboveSubview: self.textPlaceholderNode.view) } - if self.tintContextPlaceholderNode !== tintContextPlaceholderNode { - tintContextPlaceholderNode.displaysAsynchronously = false - tintContextPlaceholderNode.isUserInteractionEnabled = false - self.tintContextPlaceholderNode = tintContextPlaceholderNode - self.textInputContainerBackgroundView.maskContentView.insertSubview(tintContextPlaceholderNode.view, aboveSubview: self.tintMaskTextPlaceholderNode.view) - } let _ = placeholderApply() @@ -2460,21 +2436,14 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } else { placeholderTransition = .immediate } - placeholderTransition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size)) - contextPlaceholderNode.alpha = audioRecordingItemsAlpha - - placeholderTransition.updateFrame(node: tintContextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel), size: placeholderSize.size)) - tintContextPlaceholderNode.alpha = audioRecordingItemsAlpha + placeholderTransition.updateFrame(node: contextPlaceholderNode, frame: CGRect(origin: CGPoint(x: self.textInputViewInternalInsets.left, y: hideOffset.y + textFieldInsets.top + self.textInputViewInternalInsets.top + textInputViewRealInsets.top + UIScreenPixel + (accessoryPanel != nil ? 52.0 : 0.0)), size: placeholderSize.size)) + contextPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor) + contextPlaceholderNode.alpha = audioRecordingItemsAlpha * placeholderColor.alpha } else { if let contextPlaceholderNode = self.contextPlaceholderNode { self.contextPlaceholderNode = nil contextPlaceholderNode.removeFromSupernode() - self.textPlaceholderNode.alpha = 1.0 - self.tintMaskTextPlaceholderNode.alpha = 1.0 - } - if let tintContextPlaceholderNode = self.tintContextPlaceholderNode { - self.tintContextPlaceholderNode = nil - tintContextPlaceholderNode.removeFromSupernode() + self.textPlaceholderNode.alpha = 1.0 * placeholderColor.alpha } } @@ -2499,11 +2468,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg if (interfaceState.slowmodeState != nil && rightSlowModeInset.isZero && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil { self.textPlaceholderNode.isHidden = true - self.tintMaskTextPlaceholderNode.isHidden = true self.slowmodePlaceholderNode?.isHidden = inputHasText } else { self.textPlaceholderNode.isHidden = inputHasText - self.tintMaskTextPlaceholderNode.isHidden = inputHasText self.slowmodePlaceholderNode?.isHidden = true } @@ -2539,38 +2506,24 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg let textPlaceholderSize: CGSize let textPlaceholderMaxWidth: CGFloat = max(1.0, nextButtonTopRight.x - 12.0) - let placeholderColor: UIColor = interfaceState.theme.chat.inputPanel.inputPlaceholderColor - if #available(iOS 26.0, *) { - //placeholderColor = placeholderColor.withProminence(.tertiary) - } - //self.textPlaceholderNode.view.tintColor = .red - if (updatedPlaceholder != nil && self.currentPlaceholder != updatedPlaceholder) || themeUpdated { let currentPlaceholder = updatedPlaceholder ?? self.currentPlaceholder ?? "" self.currentPlaceholder = currentPlaceholder let baseFontSize = max(minInputFontSize, interfaceState.fontSize.baseDisplaySize) - let attributedPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: placeholderColor) + let attributedPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: placeholderColor.withAlphaComponent(1.0)) if placeholderHasStar, let range = attributedPlaceholder.string.range(of: "#") { attributedPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(interfaceState.theme)!, range: NSRange(range, in: attributedPlaceholder.string)) - attributedPlaceholder.addAttribute(.foregroundColor, value: placeholderColor, range: NSRange(range, in: attributedPlaceholder.string)) + attributedPlaceholder.addAttribute(.foregroundColor, value: placeholderColor.withAlphaComponent(1.0), range: NSRange(range, in: attributedPlaceholder.string)) attributedPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedPlaceholder.string)) } - let attributedTintMaskPlaceholder = NSMutableAttributedString(string: currentPlaceholder, font: Font.regular(baseFontSize), textColor: UIColor(white: 0.0, alpha: placeholderColor.alpha)) - if placeholderHasStar, let range = attributedPlaceholder.string.range(of: "#") { - attributedTintMaskPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(interfaceState.theme)!, range: NSRange(range, in: attributedPlaceholder.string)) - attributedTintMaskPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(range, in: attributedPlaceholder.string)) - attributedTintMaskPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedPlaceholder.string)) - } - self.textPlaceholderNode.attributedText = attributedPlaceholder - self.tintMaskTextPlaceholderNode.attributedText = attributedTintMaskPlaceholder + self.textPlaceholderNode.view.setMonochromaticEffect(tintColor: placeholderColor) self.textInputNode?.textView.accessibilityHint = currentPlaceholder let placeholderSize = self.textPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude)) - let _ = self.tintMaskTextPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude)) if transition.isAnimated, let snapshotLayer = self.textPlaceholderNode.layer.snapshotContentTree() { self.textPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.textPlaceholderNode.layer) @@ -2580,15 +2533,6 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg self.textPlaceholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18) } - let _ = self.tintMaskTextPlaceholderNode.updateLayout(CGSize(width: textPlaceholderMaxWidth, height: CGFloat.greatestFiniteMagnitude)) - if transition.isAnimated, let snapshotLayer = self.tintMaskTextPlaceholderNode.layer.snapshotContentTree() { - self.tintMaskTextPlaceholderNode.supernode?.layer.insertSublayer(snapshotLayer, above: self.tintMaskTextPlaceholderNode.layer) - snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.22, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in - snapshotLayer?.removeFromSuperlayer() - }) - self.tintMaskTextPlaceholderNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18) - } - textPlaceholderSize = placeholderSize } else { textPlaceholderSize = self.textPlaceholderNode.bounds.size @@ -2623,13 +2567,11 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg } } transition.updateFrame(node: self.textPlaceholderNode, frame: textPlaceholderFrame) - transition.updateFrame(node: self.tintMaskTextPlaceholderNode, frame: textPlaceholderFrame) - let textPlaceholderAlpha: CGFloat = audioRecordingItemsAlpha + let textPlaceholderAlpha: CGFloat = audioRecordingItemsAlpha * placeholderColor.alpha transition.updateAlpha(node: self.textPlaceholderNode, alpha: textPlaceholderAlpha) - transition.updateAlpha(node: self.tintMaskTextPlaceholderNode, alpha: textPlaceholderAlpha) - if let removeAccessoryButtons = removeAccessoryButtons { + if let removeAccessoryButtons { for button in removeAccessoryButtons { let buttonFrame = CGRect(origin: CGPoint(x: button.frame.origin.x + additionalOffset, y: textInputFrame.maxY - minimalInputHeight), size: button.frame.size) transition.updateFrame(layer: button.layer, frame: buttonFrame) @@ -2700,7 +2642,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg let attachmentButtonFrame = CGRect(origin: CGPoint(x: attachmentButtonX, y: textInputFrame.maxY - 40.0), size: CGSize(width: 40.0, height: 40.0)) self.attachmentButtonBackground.frame = CGRect(origin: CGPoint(), size: attachmentButtonFrame.size) - self.attachmentButtonBackground.update(size: attachmentButtonFrame.size, cornerRadius: attachmentButtonFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: isEditingMedia ? .init(kind: .custom, color: interfaceState.theme.chat.inputPanel.actionControlFillColor) : .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: ComponentTransition(transition)) + self.attachmentButtonBackground.update(size: attachmentButtonFrame.size, cornerRadius: attachmentButtonFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: isEditingMedia ? .init(kind: .custom, color: interfaceState.theme.chat.inputPanel.actionControlFillColor) : .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), isInteractive: true, transition: ComponentTransition(transition)) transition.updateFrame(layer: self.attachmentButton.layer, frame: attachmentButtonFrame) transition.updateFrame(node: self.attachmentButtonDisabledNode, frame: self.attachmentButton.frame) @@ -3667,11 +3609,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg if let interfaceState = self.presentationInterfaceState { if (interfaceState.slowmodeState != nil && !isScheduledMessages && interfaceState.editMessageState == nil) || interfaceState.inputTextPanelState.contextPlaceholder != nil { self.textPlaceholderNode.isHidden = true - self.tintMaskTextPlaceholderNode.isHidden = true self.slowmodePlaceholderNode?.isHidden = inputHasText } else { self.textPlaceholderNode.isHidden = inputHasText - self.tintMaskTextPlaceholderNode.isHidden = inputHasText self.slowmodePlaceholderNode?.isHidden = true } } @@ -4721,7 +4661,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForAccessoryButton(_ item: ChatTextInputAccessoryItem) -> CGRect? { for (buttonItem, buttonNode) in self.accessoryItemButtons { if buttonItem == item { - return buttonNode.frame + return self.view.convert(buttonNode.bounds.insetBy(dx: 0.0, dy: 6.0), from: buttonNode) } } return nil @@ -4744,9 +4684,9 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForInputActionButton() -> CGRect? { if !self.actionButtons.alpha.isZero { if self.actionButtons.micButton.alpha.isZero { - return self.actionButtons.frame.insetBy(dx: 0.0, dy: 6.0).offsetBy(dx: 4.0, dy: 0.0) + return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0) } else { - return self.actionButtons.frame.insetBy(dx: 0.0, dy: 6.0).offsetBy(dx: 2.0, dy: 0.0) + return self.actionButtons.frame.insetBy(dx: 0.0, dy: -4.0).offsetBy(dx: 0.0, dy: 0.0) } } return nil @@ -4755,7 +4695,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForStickersButton() -> CGRect? { for (item, button) in self.accessoryItemButtons { if case let .input(_, inputMode) = item, case .stickers = inputMode { - return button.frame.insetBy(dx: 0.0, dy: 6.0) + return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button) } } return nil @@ -4764,7 +4704,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForEmojiButton() -> CGRect? { for (item, button) in self.accessoryItemButtons { if case let .input(_, inputMode) = item, case .emoji = inputMode { - return button.frame.insetBy(dx: 0.0, dy: 6.0) + return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button) } } return nil @@ -4773,7 +4713,7 @@ public class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDeleg public func frameForGiftButton() -> CGRect? { for (item, button) in self.accessoryItemButtons { if case .gift = item { - return button.frame.insetBy(dx: 0.0, dy: 6.0) + return self.view.convert(button.bounds.insetBy(dx: 0.0, dy: 6.0), from: button) } } return nil diff --git a/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/ChatTextInputMediaRecordingButton.swift b/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/ChatTextInputMediaRecordingButton.swift index 7f1ab9ea04..4587bc4a00 100644 --- a/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/ChatTextInputMediaRecordingButton.swift +++ b/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/ChatTextInputMediaRecordingButton.swift @@ -420,11 +420,12 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM animationName = "anim_micToVideo" } + let animationTintColor = self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor let _ = self.animationView.update( transition: .immediate, component: AnyComponent(LottieComponent( content: LottieComponent.AppBundleContent(name: animationName), - color: self.useDarkTheme ? .white : self.theme.chat.inputPanel.inputControlColor + color: animationTintColor )), environment: {}, containerSize: animationFrame.size @@ -437,6 +438,7 @@ public final class ChatTextInputMediaRecordingButton: TGModernConversationInputM view.output = self.animationOutput self.updateShadow() } + view.setMonochromaticEffect(tintColor: animationTintColor) view.frame = animationFrame if previousMode != mode { diff --git a/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/LockView.swift b/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/LockView.swift index d2731acbe1..09731c4b75 100644 --- a/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/LockView.swift +++ b/submodules/TelegramUI/Components/ChatTextInputMediaRecordingButton/Sources/LockView.swift @@ -65,22 +65,12 @@ final class LockView: UIButton, TGModernConversationInputMicButtonLock { } func updateTheme(_ theme: PresentationTheme) { -// [ -// "Rectangle.Заливка 1": theme.chat.inputPanel.panelBackgroundColor, -// "Rectangle.Rectangle.Обводка 1": theme.chat.inputPanel.panelControlAccentColor, -// "Rectangle 2.Rectangle.Обводка 1": theme.chat.inputPanel.panelControlAccentColor, -// "Path.Path.Обводка 1": theme.chat.inputPanel.panelControlAccentColor, -// "Path 4.Path 4.Обводка 1": theme.chat.inputPanel.panelControlAccentColor -// ].forEach { key, value in -// idleView.setValueProvider(ColorValueProvider(value.lottieColorValue), keypath: AnimationKeypath(keypath: "\(key).Color")) -// } -// for keypath in idleView.allKeypaths(predicate: { $0.keys.last == "Color" }) { - idleView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlAccentColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath)) + idleView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath)) } for keypath in lockingView.allKeypaths(predicate: { $0.keys.last == "Color" }) { - lockingView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlAccentColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath)) + lockingView.setValueProvider(ColorValueProvider(theme.chat.inputPanel.panelControlColor.lottieColorValue), keypath: AnimationKeypath(keypath: keypath)) } // // [ diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index 88d6c0083e..de07391ffc 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -202,6 +202,14 @@ public class GlassBackgroundView: UIView { } } + override public var tintColor: UIColor? { + didSet { + if self.tintColor != oldValue { + self.setMonochromaticEffect(tintColor: self.tintColor) + } + } + } + override public init(frame: CGRect) { self.tintImageView = UIImageView() @@ -252,16 +260,19 @@ public class GlassBackgroundView: UIView { let cornerRadius: CGFloat let isDark: Bool let tintColor: TintColor + let isInteractive: Bool - init(cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor) { + init(cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, isInteractive: Bool) { self.cornerRadius = cornerRadius self.isDark = isDark self.tintColor = tintColor + self.isInteractive = isInteractive } } private let backgroundNode: NavigationBackgroundNode? private let nativeView: UIVisualEffectView? + private let nativeContainerView: UIVisualEffectView? private let foregroundView: UIImageView? private let shadowView: UIImageView? @@ -283,19 +294,23 @@ public class GlassBackgroundView: UIView { public override init(frame: CGRect) { if #available(iOS 26.0, *) { self.backgroundNode = nil - let glassEffect = UIGlassEffect(style: .clear) + + let glassEffect = UIGlassEffect(style: .regular) glassEffect.isInteractive = false let nativeView = UIVisualEffectView(effect: glassEffect) - nativeView.layer.cornerCurve = .circular self.nativeView = nativeView - nativeView.overrideUserInterfaceStyle = .light - nativeView.traitOverrides.userInterfaceStyle = .light - //self.foregroundView = UIImageView() + + let glassContainerEffect = UIGlassContainerEffect() + let nativeContainerView = UIVisualEffectView(effect: glassContainerEffect) + self.nativeContainerView = nativeContainerView + nativeContainerView.contentView.addSubview(nativeView) + self.foregroundView = nil - self.shadowView = UIImageView() + self.shadowView = nil } else { self.backgroundNode = NavigationBackgroundNode(color: .black, enableBlur: true, customBlurRadius: 5.0) self.nativeView = nil + self.nativeContainerView = nil self.foregroundView = UIImageView() self.shadowView = UIImageView() } @@ -316,8 +331,8 @@ public class GlassBackgroundView: UIView { if let shadowView = self.shadowView { self.addSubview(shadowView) } - if let nativeView = self.nativeView { - self.addSubview(nativeView) + if let nativeContainerView = self.nativeContainerView { + self.addSubview(nativeContainerView) } if let backgroundNode = self.backgroundNode { self.addSubview(backgroundNode.view) @@ -333,8 +348,17 @@ public class GlassBackgroundView: UIView { fatalError("init(coder:) has not been implemented") } - public func update(size: CGSize, cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, transition: ComponentTransition) { - if let nativeView = self.nativeView { + override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + /*if let nativeContainerView = self.nativeContainerView { + if let result = nativeContainerView.hitTest(self.convert(point, to: nativeContainerView), with: event) { + return result + } + }*/ + return nil + } + + public func update(size: CGSize, cornerRadius: CGFloat, isDark: Bool, tintColor: TintColor, isInteractive: Bool = false, transition: ComponentTransition) { + if let nativeContainerView = self.nativeContainerView, let nativeView = self.nativeView { let previousFrame = nativeView.frame if transition.animation.isImmediate { @@ -347,6 +371,8 @@ public class GlassBackgroundView: UIView { } nativeView.layer.animateFrame(from: previousFrame, to: CGRect(origin: CGPoint(), size: size), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring) } + + transition.setFrame(view: nativeContainerView, frame: CGRect(origin: CGPoint(), size: size)) } if let backgroundNode = self.backgroundNode { backgroundNode.updateColor(color: .clear, forceKeepBlur: tintColor.color.alpha != 1.0, transition: transition.containedViewLayoutTransition) @@ -356,7 +382,7 @@ public class GlassBackgroundView: UIView { let shadowInset: CGFloat = 32.0 - let params = Params(cornerRadius: cornerRadius, isDark: isDark, tintColor: tintColor) + let params = Params(cornerRadius: cornerRadius, isDark: isDark, tintColor: tintColor, isInteractive: isInteractive) if self.params != params { self.params = params @@ -378,18 +404,21 @@ public class GlassBackgroundView: UIView { if let foregroundView = self.foregroundView { foregroundView.image = GlassBackgroundView.generateLegacyGlassImage(size: CGSize(width: cornerRadius * 2.0, height: cornerRadius * 2.0), inset: shadowInset, isDark: isDark, fillColor: tintColor.color) } else { - if let nativeView { + if let nativeContainerView = self.nativeContainerView, let nativeView { if #available(iOS 26.0, *) { - let glassEffect = UIGlassEffect(style: .clear) + let glassEffect = UIGlassEffect(style: .regular) switch tintColor.kind { case .panel: - glassEffect.tintColor = tintColor.color.withMultipliedAlpha(1.2) + glassEffect.tintColor = nil case .custom: glassEffect.tintColor = tintColor.color } - glassEffect.isInteractive = false + glassEffect.isInteractive = params.isInteractive nativeView.effect = glassEffect + let _ = nativeContainerView + //nativeContainerView.overrideUserInterfaceStyle = .light// isDark ? .dark : .light + self.overrideUserInterfaceStyle = isDark ? .dark : .light } } } @@ -407,6 +436,27 @@ public class GlassBackgroundView: UIView { } } +public final class GlassBackgroundContainerView: UIView { + private final class ContentView: UIView { + + } + + private let contentViewImpl: ContentView + public var contentView: UIView { + return self.contentViewImpl + } + + public override init(frame: CGRect) { + self.contentViewImpl = ContentView() + + super.init(frame: frame) + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + public final class VariableBlurView: UIVisualEffectView { public let maxBlurRadius: CGFloat @@ -536,8 +586,7 @@ public extension GlassBackgroundView { return result } - // Your requested closure: - let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor) -> Void = { isOuter, position, blur, spread, shadowColor in + let addShadow: (Bool, CGPoint, CGFloat, CGFloat, UIColor, Bool) -> Void = { isOuter, position, blur, spread, shadowColor, isMultiply in var blur = blur blur += abs(spread) @@ -571,132 +620,70 @@ public extension GlassBackgroundView { context.fillPath() context.setBlendMode(.normal) } else { - context.beginTransparencyLayer(auxiliaryInfo: nil) - context.saveGState() - defer { - context.restoreGState() - context.endTransparencyLayer() + if let image = generateImage(size, rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + let spreadRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize).insetBy(dx: -0.25, dy: -0.25) + let spreadPath = UIBezierPath( + roundedRect: spreadRect, + cornerRadius: min(spreadRect.width, spreadRect.height) * 0.5 + ).cgPath + + context.setShadow(offset: CGSize(width: position.x, height: position.y), blur: blur, color: shadowColor.cgColor) + context.setFillColor(UIColor.black.withAlphaComponent(1.0).cgColor) + let enclosingRect = spreadRect.insetBy(dx: -10000.0, dy: -10000.0) + context.addPath(UIBezierPath(rect: enclosingRect).cgPath) + context.addPath(spreadPath) + context.fillPath(using: .evenOdd) + + let cleanRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize) + let cleanPath = UIBezierPath( + roundedRect: cleanRect, + cornerRadius: min(cleanRect.width, cleanRect.height) * 0.5 + ).cgPath + context.setBlendMode(.copy) + context.setFillColor(UIColor.clear.cgColor) + context.addPath(UIBezierPath(rect: enclosingRect).cgPath) + context.addPath(cleanPath) + context.fillPath(using: .evenOdd) + context.setBlendMode(.normal) + }) { + UIGraphicsPushContext(context) + image.draw(in: CGRect(origin: .zero, size: size), blendMode: isMultiply ? .destinationOut : .normal, alpha: 1.0) + UIGraphicsPopContext() } - - let spreadRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize).insetBy(dx: -0.25, dy: -0.25) - let spreadPath = UIBezierPath( - roundedRect: spreadRect, - cornerRadius: min(spreadRect.width, spreadRect.height) * 0.5 - ).cgPath - - context.setShadow(offset: CGSize(width: position.x, height: position.y), blur: blur, color: shadowColor.cgColor) - context.setFillColor(UIColor.black.withAlphaComponent(1.0).cgColor) - let enclosingRect = spreadRect.insetBy(dx: -10000.0, dy: -10000.0) - context.addPath(UIBezierPath(rect: enclosingRect).cgPath) - context.addPath(spreadPath) - context.fillPath(using: .evenOdd) - - let cleanRect = CGRect(origin: CGPoint(x: inset, y: inset), size: innerSize) - let cleanPath = UIBezierPath( - roundedRect: cleanRect, - cornerRadius: min(cleanRect.width, cleanRect.height) * 0.5 - ).cgPath - context.setBlendMode(.copy) - context.setFillColor(UIColor.clear.cgColor) - context.addPath(UIBezierPath(rect: enclosingRect).cgPath) - context.addPath(cleanPath) - context.fillPath(using: .evenOdd) - context.setBlendMode(.normal) } } if isDark { - addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.12)) - addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.1)) + addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.12), false) + addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.1), false) context.setFillColor(fillColor.cgColor) context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset)) - addShadow(false, CGPoint(x: 0.0, y: 0.0), 3.0, 0.0, UIColor(white: 1.0, alpha: 0.5)) - addShadow(false, CGPoint(x: 3.0, y: -3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25)) - addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25)) + addShadow(false, CGPoint(x: 0.0, y: 0.0), 3.0, 0.0, UIColor(white: 1.0, alpha: 0.5), false) + addShadow(false, CGPoint(x: 3.0, y: -3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false) + addShadow(false, CGPoint(x: -3.0, y: 3.0), 2.0, 0.0, UIColor(white: 1.0, alpha: 0.25), false) } else { - addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08)) - addShadow(true, CGPoint(), 8.0, 0.0, UIColor(white: 0.0, alpha: 0.08)) + addShadow(true, CGPoint(), 32.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false) + addShadow(true, CGPoint(), 16.0, 0.0, UIColor(white: 0.0, alpha: 0.08), false) context.setFillColor(fillColor.cgColor) context.fillEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: inset, dy: inset)) - addShadow(false, CGPoint(x: 3.0, y: -3.0), 0.5, 0.0, fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(3.0).withMultipliedAlpha(1.0)) - addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15)) - } - - if "".isEmpty { - return - } - - let maxColor = UIColor(white: 1.0, alpha: isDark ? 0.25 : 0.9) - let minColor = UIColor(white: 1.0, alpha: 0.0) - - context.setFillColor(fillColor.cgColor) - context.fillEllipse(in: CGRect(origin: CGPoint(), size: size)) - - let lineWidth: CGFloat = isDark ? 0.66 : 0.66 - - context.saveGState() - - let darkShadeColor = UIColor(white: isDark ? 1.0 : 0.0, alpha: 0.035) - let lightShadeColor = UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.035) - let innerShadowBlur: CGFloat = 24.0 - - context.resetClip() - context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)) - context.clip() - context.addRect(CGRect(origin: CGPoint(), size: size).insetBy(dx: -100.0, dy: -100.0)) - context.addEllipse(in: CGRect(origin: CGPoint(), size: size)) - context.setFillColor(UIColor.black.cgColor) - context.setShadow(offset: CGSize(width: 10.0, height: -10.0), blur: innerShadowBlur, color: darkShadeColor.cgColor) - context.fillPath(using: .evenOdd) - - context.resetClip() - context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)) - context.clip() - context.addRect(CGRect(origin: CGPoint(), size: size).insetBy(dx: -100.0, dy: -100.0)) - context.addEllipse(in: CGRect(origin: CGPoint(), size: size)) - context.setFillColor(UIColor.black.cgColor) - context.setShadow(offset: CGSize(width: -10.0, height: 10.0), blur: innerShadowBlur, color: lightShadeColor.cgColor) - context.fillPath(using: .evenOdd) - - context.restoreGState() - - context.setLineWidth(lineWidth) - - context.addRect(CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width * 0.5, height: size.height))) - context.clip() - context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)) - context.replacePathWithStrokedPath() - context.clip() - - do { - var locations: [CGFloat] = [0.0, 0.5, 0.5 + 0.2, 1.0 - 0.1, 1.0] - let colors: [CGColor] = [maxColor.cgColor, maxColor.cgColor, minColor.cgColor, minColor.cgColor, maxColor.cgColor] + let highlightColor: UIColor + if fillColor.hsb.s > 0.5 { + highlightColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(2.0) + + let shadowColor = fillColor.withMultiplied(hue: 1.0, saturation: 2.0, brightness: 1.0).adjustedPerceivedBrightness(0.5).withMultipliedAlpha(0.2) + addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, shadowColor, false) + } else { + highlightColor = UIColor(white: 1.0, alpha: 0.4) + addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.5, 0.0, UIColor.black.withMultipliedAlpha(0.15), true) + addShadow(false, CGPoint(x: -2.0, y: 2.0), 0.6, 0.0, UIColor(white: 0.0, alpha: 0.1), false) + } - let colorSpace = CGColorSpaceCreateDeviceRGB() - let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! - - context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions()) - } - - context.resetClip() - context.addRect(CGRect(origin: CGPoint(x: size.width - size.width * 0.5, y: 0.0), size: CGSize(width: size.width * 0.5, height: size.height))) - context.clip() - context.addEllipse(in: CGRect(origin: CGPoint(), size: size).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5)) - context.replacePathWithStrokedPath() - context.clip() - - do { - var locations: [CGFloat] = [0.0, 0.1, 0.5 - 0.2, 0.5, 1.0] - let colors: [CGColor] = [maxColor.cgColor, minColor.cgColor, minColor.cgColor, maxColor.cgColor, maxColor.cgColor] - - let colorSpace = CGColorSpaceCreateDeviceRGB() - let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)! - - context.drawLinearGradient(gradient, start: CGPoint(x: 0.0, y: 0.0), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions()) + addShadow(false, CGPoint(x: 2.0, y: -2.0), 0.5, 0.0, highlightColor, false) } })!.stretchableImage(withLeftCapWidth: Int(size.width * 0.5), topCapHeight: Int(size.height * 0.5)) } @@ -784,10 +771,12 @@ public extension GlassBackgroundView { public final class GlassBackgroundComponent: Component { private let size: CGSize + private let isDark: Bool private let tintColor: GlassBackgroundView.TintColor - public init(size: CGSize, tintColor: GlassBackgroundView.TintColor) { + public init(size: CGSize, isDark: Bool, tintColor: GlassBackgroundView.TintColor) { self.size = size + self.isDark = isDark self.tintColor = tintColor } @@ -795,6 +784,9 @@ public final class GlassBackgroundComponent: Component { if lhs.size != rhs.size { return false } + if lhs.isDark != rhs.isDark { + return false + } if lhs.tintColor != rhs.tintColor { return false } @@ -803,7 +795,7 @@ public final class GlassBackgroundComponent: Component { public final class View: GlassBackgroundView { func update(component: GlassBackgroundComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { - self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: true, tintColor: component.tintColor, transition: transition) + self.update(size: component.size, cornerRadius: component.size.height / 2.0, isDark: component.isDark, tintColor: component.tintColor, transition: transition) self.frame = CGRect(origin: .zero, size: component.size) return component.size diff --git a/submodules/TelegramUI/Components/TabBarComponent/Sources/TabBarComponent.swift b/submodules/TelegramUI/Components/TabBarComponent/Sources/TabBarComponent.swift index 22f05322f5..05314e4fd4 100644 --- a/submodules/TelegramUI/Components/TabBarComponent/Sources/TabBarComponent.swift +++ b/submodules/TelegramUI/Components/TabBarComponent/Sources/TabBarComponent.swift @@ -315,6 +315,8 @@ public final class TabBarComponent: Component { self.component = component self.state = state + self.overrideUserInterfaceStyle = component.theme.overallDarkAppearance ? .dark : .light + if let nativeTabBar = self.nativeTabBar { if nativeTabBar.items?.count != component.items.count { nativeTabBar.items = (0 ..< component.items.count).map { i in diff --git a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift index 21d99066ef..f6c371dee2 100644 --- a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift +++ b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift @@ -191,7 +191,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { enum ImageKey: Hashable { case flip case flash - case buttonBackground case flashImage } private var cachedImages: [ImageKey: UIImage] = [:] @@ -205,9 +204,6 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { image = UIImage(bundleImageName: "Camera/VideoMessageFlip")!.withRenderingMode(.alwaysTemplate) case .flash: image = UIImage(bundleImageName: "Camera/VideoMessageFlash")!.withRenderingMode(.alwaysTemplate) - case .buttonBackground: - let innerSize = CGSize(width: 40.0, height: 40.0) - image = generateFilledCircleImage(diameter: innerSize.width, color: theme.rootController.navigationBar.opaqueBackgroundColor, strokeColor: theme.chat.inputPanel.panelSeparatorColor, strokeWidth: 0.5, backgroundColor: nil)! case .flashImage: image = generateImage(CGSize(width: 393.0, height: 852.0), rotatedContext: { size, context in context.clear(CGRect(origin: .zero, size: size)) @@ -590,6 +586,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { let flipButtonBackground = flipButtonBackground.update( component: GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: environment.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) ), availableSize: CGSize(width: 40.0, height: 40.0), @@ -691,6 +688,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { let flashButtonBackground = flashButtonBackground.update( component: GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: environment.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) ), availableSize: CGSize(width: 40.0, height: 40.0), @@ -719,9 +717,10 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { AnyComponentWithIdentity( id: "background", component: AnyComponent( - Image( - image: state.image(.buttonBackground, theme: environment.theme), - size: CGSize(width: 40.0, height: 40.0) + GlassBackgroundComponent( + size: CGSize(width: 40.0, height: 40.0), + isDark: environment.theme.overallDarkAppearance, + tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) ) ) ), @@ -749,7 +748,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { transition: context.transition ) context.add(viewOnceButton - .position(CGPoint(x: availableSize.width - viewOnceButton.size.width / 2.0 - 2.0 - UIScreenPixel, y: availableSize.height - viewOnceButton.size.height / 2.0 - 8.0 - viewOnceOffset)) + .position(CGPoint(x: availableSize.width - viewOnceButton.size.width / 2.0 - 8.0, y: availableSize.height - viewOnceButton.size.height / 2.0 - 8.0 - viewOnceOffset)) .appear(.default(scale: true, alpha: true)) .disappear(.default(scale: true, alpha: true)) ) @@ -764,6 +763,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { id: "background", component: AnyComponent(GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: environment.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) )) ), @@ -1466,7 +1466,7 @@ public class VideoMessageCameraScreen: ViewController { var backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: controller.inputPanelFrame.0.minY)) let actualBackgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height)) if backgroundFrame.maxY < layout.size.height - 100.0 && (layout.inputHeight ?? 0.0).isZero && !controller.inputPanelFrame.1 && layout.additionalInsets.bottom.isZero { - backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height - layout.intrinsicInsets.bottom - controller.inputPanelFrame.0.height)) + backgroundFrame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: layout.size.height - layout.intrinsicInsets.bottom - controller.inputPanelFrame.0.height - 8.0)) } transition.setPosition(view: self.backgroundView, position: actualBackgroundFrame.center) diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift index 41d40bcaea..da9d2e03f9 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift @@ -330,12 +330,6 @@ extension ChatControllerImpl { self?.canReadHistory.set(true) } controller.immediateItemsTransitionAnimation = disableTransitionAnimations - controller.getOverlayViews = { [weak self] in - guard let self else { - return [] - } - return [self.chatDisplayNode.navigateButtons.view] - } self.currentContextController = controller controller.premiumReactionsSelected = { [weak self, weak controller] in diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index d929b56901..61b7e8aef1 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -1311,6 +1311,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { previousInputPanelOrigin.y -= inputPanelNode.bounds.size.height } if let secondaryInputPanelNode = self.secondaryInputPanelNode { + previousInputPanelOrigin.y -= 8.0 previousInputPanelOrigin.y -= secondaryInputPanelNode.bounds.size.height } self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight) @@ -1568,6 +1569,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { inputPanelNodeBaseHeight += inputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) } if let secondaryInputPanelNode = self.secondaryInputPanelNode { + inputPanelNodeBaseHeight += 8.0 inputPanelNodeBaseHeight += secondaryInputPanelNode.minimalHeight(interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics) } @@ -1739,6 +1741,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } } if let secondaryInputPanelSize = secondaryInputPanelSize { + maximumInputNodeHeight -= 8.0 maximumInputNodeHeight -= secondaryInputPanelSize.height } if let accessoryPanelSize = accessoryPanelSize { @@ -2128,8 +2131,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { if overlayContextPanelNode !== self.overlayContextPanelNode { dismissedOverlayContextPanelNode = self.overlayContextPanelNode self.overlayContextPanelNode = overlayContextPanelNode - - self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode) + if let navigationBar = self.navigationBar { + self.contentContainerNode.contentNode.insertSubnode(overlayContextPanelNode, belowSubnode: navigationBar) + } else { + self.contentContainerNode.contentNode.addSubnode(overlayContextPanelNode) + } immediatelyLayoutOverlayContextPanelAndAnimateAppearance = true } } else if let overlayContextPanelNode = self.overlayContextPanelNode { @@ -2147,10 +2153,10 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { var inputPanelHideOffset: CGFloat = 0.0 if let inputNode = self.inputNode, inputNode.hideInput { if let inputPanelSize = inputPanelSize { - inputPanelHideOffset += -inputPanelSize.height + inputPanelHideOffset += -inputPanelSize.height - 80.0 } if let accessoryPanelSize = accessoryPanelSize { - inputPanelHideOffset += -accessoryPanelSize.height + inputPanelHideOffset += -accessoryPanelSize.height - 80.0 } } @@ -2164,11 +2170,11 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } if self.secondaryInputPanelNode != nil { - secondaryInputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - bottomOverflowOffset - inputPanelsHeight - secondaryInputPanelSize!.height), size: CGSize(width: layout.size.width, height: secondaryInputPanelSize!.height)) + secondaryInputPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - bottomOverflowOffset - inputPanelsHeight - secondaryInputPanelSize!.height - 8.0), size: CGSize(width: layout.size.width, height: secondaryInputPanelSize!.height)) if self.dismissedAsOverlay { secondaryInputPanelFrame!.origin.y = layout.size.height } - inputPanelsHeight += secondaryInputPanelSize!.height + inputPanelsHeight += 8.0 + secondaryInputPanelSize!.height } var accessoryPanelFrame: CGRect? diff --git a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift index 3018633377..d889eeaa7c 100644 --- a/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRestrictedInputPanelNode.swift @@ -161,6 +161,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { let subtitleSize = self.subtitleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 8.0 * 2.0, height: panelHeight)) var originX: CGFloat = leftInset + floor((width - leftInset - rightInset - textSize.width) / 2.0) + var totalWidth = textSize.width if let iconImage { let iconView: UIImageView @@ -173,7 +174,7 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { } iconView.image = iconImage - let totalWidth = textSize.width + iconImage.size.width + iconSpacing + totalWidth += iconImage.size.width + iconSpacing iconView.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - totalWidth) / 2.0), y: floor((panelHeight - textSize.height) / 2.0) + UIScreenPixel + floorToScreenPixels((textSize.height - iconImage.size.height) / 2.0)), size: iconImage.size) originX += iconImage.size.width + iconSpacing @@ -190,7 +191,11 @@ final class ChatRestrictedInputPanelNode: ChatInputPanelNode { let subtitleFrame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - subtitleSize.width) / 2.0), y: floor((panelHeight + combinedHeight) / 2.0) - subtitleSize.height), size: subtitleSize) - var combinedFrame = textFrame.union(subtitleFrame).insetBy(dx: -12.0, dy: -6.0) + var combinedFrame = textFrame.union(subtitleFrame) + if let iconView { + combinedFrame = combinedFrame.union(iconView.frame) + } + combinedFrame = combinedFrame.insetBy(dx: -12.0, dy: -6.0) combinedFrame.origin.y += 1.0 self.textNode.frame = textFrame.offsetBy(dx: -combinedFrame.minX, dy: -combinedFrame.minY) diff --git a/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift index 465a52d442..1d184dea2a 100644 --- a/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/CommandChatInputContextPanelNode.swift @@ -243,7 +243,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable { messageCount: shortcut.totalCount, hideSeparator: false, hideDate: true, - hidePeerStatus: true + hidePeerStatus: true, + isInTransparentContainer: true ) )), editing: false, diff --git a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift index c8b33b8ff2..369f90ac19 100644 --- a/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift +++ b/submodules/TelegramUI/Sources/HorizontalListContextResultsChatInputContextPanelNode.swift @@ -84,7 +84,6 @@ private func preparedTransition(from fromEntries: [HorizontalListContextResultsC final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputContextPanelNode { private let listView: ListView - private let separatorNode: ASDisplayNode private var currentExternalResults: ChatContextResultCollection? private var currentProcessedResults: ChatContextResultCollection? private var currentEntries: [HorizontalListContextResultsChatInputContextPanelEntry]? @@ -97,11 +96,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont private let batchVideoContext: QueueLocalObject override init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, fontSize: PresentationFontSize, chatPresentationContext: ChatPresentationContext) { - self.separatorNode = ASDisplayNode() - self.separatorNode.isLayerBacked = true - self.separatorNode.backgroundColor = theme.list.itemPlainSeparatorColor - self.separatorNode.isHidden = true - self.listView = ListView() self.listView.isOpaque = true self.listView.backgroundColor = theme.list.plainBackgroundColor @@ -121,7 +115,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont self.clipsToBounds = true self.addSubnode(self.listView) - self.addSubnode(self.separatorNode) self.listView.displayedItemRangeChanged = { [weak self] displayedRange, opaqueTransactionState in if let strongSelf = self, let state = opaqueTransactionState as? HorizontalListContextResultsOpaqueState { @@ -358,18 +351,10 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont self.listView.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: HorizontalListContextResultsOpaqueState(entryCount: transition.entryCount, hasMore: transition.hasMore), completion: { [weak self] _ in if let strongSelf = self, firstTime { - let position = strongSelf.listView.position - let separatorPosition = strongSelf.separatorNode.layer.position - strongSelf.listView.isHidden = false - strongSelf.separatorNode.isHidden = false - strongSelf.listView.position = CGPoint(x: position.x, y: position.y + strongSelf.listView.bounds.size.width) - strongSelf.separatorNode.position = CGPoint(x: separatorPosition.x, y: separatorPosition.y + strongSelf.listView.bounds.size.width) - ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring).animateView { - strongSelf.listView.position = position - strongSelf.separatorNode.position = separatorPosition - } + strongSelf.layer.allowsGroupOpacity = true + strongSelf.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } }) } @@ -378,7 +363,6 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) { let listHeight: CGFloat = 105.0 - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: size.height - bottomInset - 8.0 - listHeight), size: CGSize(width: size.width, height: UIScreenPixel))) self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: listHeight, height: size.width) //transition.updateFrame(node: self.listView, frame: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)) @@ -403,18 +387,18 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont if self.theme !== interfaceState.theme { self.theme = interfaceState.theme - self.separatorNode.backgroundColor = theme.list.itemPlainSeparatorColor - self.listView.backgroundColor = theme.list.plainBackgroundColor + self.listView.backgroundColor = self.theme.list.plainBackgroundColor } } override func animateOut(completion: @escaping () -> Void) { - let position = self.listView.layer.position + /*let position = self.listView.layer.position self.listView.layer.animatePosition(from: position, to: CGPoint(x: position.x, y: position.y + self.listView.bounds.size.width), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in completion() + })*/ + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in + completion() }) - let separatorPosition = self.separatorNode.layer.position - self.separatorNode.layer.animatePosition(from: separatorPosition, to: CGPoint(x: separatorPosition.x, y: separatorPosition.y + listView.bounds.size.width), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { diff --git a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift index ad862f9774..bfb93e523b 100644 --- a/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/SecretChatHandshakeStatusInputPanelNode.swift @@ -8,8 +8,13 @@ import SwiftSignalKit import LocalizedPeerData import ChatPresentationInterfaceState import ChatInputPanelNode +import ComponentFlow +import MultilineTextComponent +import GlassBackgroundComponent final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { + private let titleBackground: GlassBackgroundView + private let title = ComponentView() private let button: HighlightableButtonNode private var statusDisposable: Disposable? @@ -22,9 +27,12 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { self.button.titleNode.maximumNumberOfLines = 2 self.button.titleNode.truncationMode = .byTruncatingMiddle + self.titleBackground = GlassBackgroundView() + super.init() self.addSubnode(self.button) + self.button.view.addSubview(self.titleBackground) self.button.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: [.touchUpInside]) } @@ -46,31 +54,48 @@ final class SecretChatHandshakeStatusInputPanelNode: ChatInputPanelNode { } override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, maxOverlayHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { - if self.presentationInterfaceState != interfaceState { - self.presentationInterfaceState = interfaceState - - if let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.peer as? TelegramSecretChat, let userPeer = renderedPeer.peers[peer.regularPeerId] { - switch peer.embeddedState { - case .handshake: - let text: String - switch peer.role { - case .creator: - text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string - case .participant: - text = interfaceState.strings.Conversation_EncryptionProcessing - } - self.button.setAttributedTitle(NSAttributedString(string: text, font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.primaryTextColor, paragraphAlignment: .center), for: []) - case .active, .terminated: - break + self.presentationInterfaceState = interfaceState + + var text: String? + + if let renderedPeer = interfaceState.renderedPeer, let peer = renderedPeer.peer as? TelegramSecretChat, let userPeer = renderedPeer.peers[peer.regularPeerId] { + switch peer.embeddedState { + case .handshake: + switch peer.role { + case .creator: + text = interfaceState.strings.DialogList_AwaitingEncryption(EnginePeer(userPeer).compactDisplayTitle).string + case .participant: + text = interfaceState.strings.Conversation_EncryptionProcessing } + case .active, .terminated: + break } } - let buttonSize = self.button.measure(CGSize(width: width - 10.0, height: 100.0)) + let titleSize = self.title.update( + transition: .immediate, + component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString(string: text ?? " ", font: Font.regular(15.0), textColor: interfaceState.theme.chat.inputPanel.primaryTextColor, paragraphAlignment: .center)) + )), + environment: {}, + containerSize: CGSize(width: width - 16.0 * 2.0, height: 100.0) + ) let panelHeight = defaultHeight(metrics: metrics) - self.button.frame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - buttonSize.width) / 2.0), y: floor((panelHeight - buttonSize.height) / 2.0)), size: buttonSize) + let backgroundSize = CGSize(width: titleSize.width + 16.0 * 2.0, height: 40.0) + let backgroundFrame = CGRect(origin: CGPoint(x: leftInset + floor((width - leftInset - rightInset - backgroundSize.width) * 0.5), y: floor((panelHeight - backgroundSize.height) / 2.0)), size: backgroundSize) + transition.updateFrame(node: self.button, frame: backgroundFrame) + transition.updateFrame(view: self.titleBackground, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size)) + self.titleBackground.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: interfaceState.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)), transition: .immediate) + let titleFrame = CGRect(origin: CGPoint(x: floor((backgroundFrame.width - titleSize.width) * 0.5), y: floor((backgroundFrame.height - titleSize.height) * 0.5)), size: titleSize) + if let titleView = self.title.view { + if titleView.superview == nil { + titleView.setMonochromaticEffect(tintColor: interfaceState.theme.chat.inputPanel.primaryTextColor) + self.titleBackground.contentView.addSubview(titleView) + } + titleView.frame = titleFrame + } return panelHeight } diff --git a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift index 4344efb867..806397d5dc 100644 --- a/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift +++ b/submodules/TelegramUI/Sources/VerticalListContextResultsChatInputPanelButtonItem.swift @@ -84,17 +84,13 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem private let buttonNode: HighlightTrackingButtonNode private let titleNode: TextNode - private let topSeparatorNode: ASDisplayNode private let separatorNode: ASDisplayNode private var item: VerticalListContextResultsChatInputPanelButtonItem? init() { self.buttonNode = HighlightTrackingButtonNode() - - self.topSeparatorNode = ASDisplayNode() - self.topSeparatorNode.isLayerBacked = true - + self.separatorNode = ASDisplayNode() self.separatorNode.isLayerBacked = true @@ -102,7 +98,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem super.init(layerBacked: false, dynamicBounce: false) - self.addSubnode(self.topSeparatorNode) self.addSubnode(self.separatorNode) self.addSubnode(self.titleNode) @@ -145,7 +140,7 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem titleFont = Font.regular(17.0) } - let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.list.itemAccentColor) + let titleString = NSAttributedString(string: item.title, font: titleFont, textColor: item.theme.chat.inputPanel.panelControlColor) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 16.0, height: 100.0), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) @@ -156,7 +151,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem strongSelf.item = item strongSelf.separatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor - strongSelf.topSeparatorNode.backgroundColor = item.theme.list.itemPlainSeparatorColor let titleOffsetY: CGFloat switch item.style { @@ -172,7 +166,6 @@ final class VerticalListContextResultsChatInputPanelButtonItemNode: ListViewItem strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: floor((params.width - titleLayout.size.width) / 2.0), y: floor((nodeLayout.contentSize.height - titleLayout.size.height) / 2.0) + titleOffsetY), size: titleLayout.size) - strongSelf.topSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: params.width, height: UIScreenPixel)) strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width, height: UIScreenPixel)) strongSelf.buttonNode.frame = CGRect(origin: CGPoint(), size: nodeLayout.contentSize) diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h index 91fb9d6141..c65fd7a175 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.h @@ -4,6 +4,7 @@ double animationDurationFactorImpl(); CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath); +CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration); CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping); CGFloat springAnimationValueAtImpl(CABasicAnimation * _Nonnull animation, CGFloat t); @@ -36,3 +37,5 @@ void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshot bool getLayerDisableScreenshots(CALayer * _Nonnull layer); void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode); + +void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled); diff --git a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m index e1e78f986f..a3f7bc1e81 100644 --- a/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m +++ b/submodules/UIKitRuntimeUtils/Source/UIKitRuntimeUtils/UIKitUtils.m @@ -61,6 +61,24 @@ CABasicAnimation * _Nonnull makeSpringAnimationImpl(NSString * _Nonnull keyPath) return springAnimation; } +CABasicAnimation * _Nonnull make26SpringAnimationImpl(NSString * _Nonnull keyPath, double duration) { + CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath]; + springAnimation.mass = 1.0f; + springAnimation.stiffness = 555.027; + springAnimation.damping = 47.118; + springAnimation.duration = duration; + springAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + if (@available(iOS 17.0, *)) { + springAnimation.allowsOverdamping = false; + } + if (@available(iOS 15.0, *)) { + [springAnimation setValue:@(1048619) forKey:@"highFrameRateReason"]; + springAnimation.preferredFrameRateRange = CAFrameRateRangeMake(80.0, 120.0, 120.0); + } + + return springAnimation; +} + CABasicAnimation * _Nonnull makeSpringBounceAnimationImpl(NSString * _Nonnull keyPath, CGFloat initialVelocity, CGFloat damping) { CASpringAnimation *springAnimation = [CASpringAnimation animationWithKeyPath:keyPath]; springAnimation.mass = 5.0f; @@ -134,6 +152,20 @@ static void setBoolField(NSObject *object, NSString *name, BOOL value) { [inv invoke]; } +static void setLongLongField(NSObject *object, NSString *name, long long value) { + SEL selector = NSSelectorFromString(name); + NSMethodSignature *signature = [[object class] instanceMethodSignatureForSelector:selector]; + if (signature == nil) { + return; + } + + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:signature]; + [inv setSelector:selector]; + [inv setArgument:&value atIndex:2]; + [inv setTarget:object]; + [inv invoke]; +} + UIBlurEffect *makeCustomZoomBlurEffectImpl(bool isLight) { if (@available(iOS 13.0, *)) { if (isLight) { @@ -299,3 +331,27 @@ void setLayerContentsMaskMode(CALayer * _Nonnull layer, bool maskMode) { [layer setValue:@"RGBA" forKey:key]; } } + +void setMonochromaticEffectImpl(UIView * _Nonnull view, bool isEnabled) { + if (@available(iOS 26.0, *)) { + static NSString *key1 = nil; + static NSString *key2 = nil; + static NSString *key3 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + key1 = [[@"_" stringByAppendingString:@"setAllows"] stringByAppendingString:@"MonochromaticTreatment:"]; + key2 = [[@"_" stringByAppendingString:@"setEnable"] stringByAppendingString:@"MonochromaticTreatment:"]; + key3 = [[@"_" stringByAppendingString:@"set"] stringByAppendingString:@"MonochromaticTreatment:"]; + }); + + if (isEnabled) { + setBoolField(view, key1, true); + setBoolField(view, key2, true); + setLongLongField(view, key3, 2); + } else { + setBoolField(view, key1, false); + setBoolField(view, key2, false); + setLongLongField(view, key3, 0); + } + } +}