diff --git a/submodules/PeerInfoUI/Sources/ChatSlowmodeItem.swift b/submodules/PeerInfoUI/Sources/ChatSlowmodeItem.swift index b522dea458..739c992377 100644 --- a/submodules/PeerInfoUI/Sources/ChatSlowmodeItem.swift +++ b/submodules/PeerInfoUI/Sources/ChatSlowmodeItem.swift @@ -59,7 +59,7 @@ class ChatSlowmodeItem: ListViewItem, ItemListItem { } } -private let allowedValues: [Int32] = [0, 10, 30, 60, 300, 900, 3600] +private let allowedValues: [Int32] = [0, 5, 10, 30, 60, 300, 900, 3600] class ChatSlowmodeItemNode: ListViewItemNode { private let backgroundNode: ASDisplayNode diff --git a/submodules/SettingsUI/Sources/UsernameSetupController.swift b/submodules/SettingsUI/Sources/UsernameSetupController.swift index fae5c43cab..d7fb506d42 100644 --- a/submodules/SettingsUI/Sources/UsernameSetupController.swift +++ b/submodules/SettingsUI/Sources/UsernameSetupController.swift @@ -60,7 +60,7 @@ private enum UsernameSetupEntry: ItemListNodeEntry { case publicLinkInfo(PresentationTheme, String) case additionalLinkHeader(PresentationTheme, String) - case additionalLink(PresentationTheme, TelegramPeerUsername, Int32) + case additionalLink(PresentationTheme, TelegramPeerUsername, Int32, Bool) case additionalLinkInfo(PresentationTheme, String) var section: ItemListSectionId { @@ -84,7 +84,7 @@ private enum UsernameSetupEntry: ItemListNodeEntry { return .index(3) case .additionalLinkHeader: return .index(4) - case let .additionalLink(_, username, _): + case let .additionalLink(_, username, _, _): return .username(username.username) case .additionalLinkInfo: return .index(5) @@ -123,8 +123,8 @@ private enum UsernameSetupEntry: ItemListNodeEntry { } else { return false } - case let .additionalLink(lhsTheme, lhsAddressName, lhsIndex): - if case let .additionalLink(rhsTheme, rhsAddressName, rhsIndex) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsIndex == rhsIndex { + case let .additionalLink(lhsTheme, lhsAddressName, lhsIndex, lhsCanToggleIsActive): + if case let .additionalLink(rhsTheme, rhsAddressName, rhsIndex, rhsCanToggleIsActive) = rhs, lhsTheme === rhsTheme, lhsAddressName == rhsAddressName, lhsIndex == rhsIndex, lhsCanToggleIsActive == rhsCanToggleIsActive { return true } else { return false @@ -175,9 +175,9 @@ private enum UsernameSetupEntry: ItemListNodeEntry { default: return true } - case let .additionalLink(_, _, lhsIndex): + case let .additionalLink(_, _, lhsIndex, _): switch rhs { - case let .additionalLink(_, _, rhsIndex): + case let .additionalLink(_, _, rhsIndex, _): return lhsIndex < rhsIndex case .publicLinkHeader, .editablePublicLink, .publicLinkStatus, .publicLinkInfo, .additionalLinkHeader: return false @@ -232,9 +232,9 @@ private enum UsernameSetupEntry: ItemListNodeEntry { }, sectionId: self.section) case let .additionalLinkHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) - case let .additionalLink(_, link, _): + case let .additionalLink(_, link, _, canToggleIsActive): return AdditionalLinkItem(presentationData: presentationData, username: link, sectionId: self.section, style: .blocks, tapAction: { - if !link.flags.contains(.isEditable) { + if canToggleIsActive { if link.isActive { arguments.deactivateLink(link.username) } else { @@ -348,8 +348,12 @@ private func usernameSetupControllerEntries(presentationData: PresentationData, entries.append(.publicLinkStatus(presentationData.theme, currentUsername, status, statusText, currentUsername)) } + var isBot = false + let otherUsernames = peer.usernames.filter { !$0.flags.contains(.isEditable) } if case .bot = mode { + isBot = true + var infoText = presentationData.strings.Username_BotLinkHint if otherUsernames.isEmpty { infoText = presentationData.strings.Username_BotLinkHintExtended @@ -384,7 +388,11 @@ private func usernameSetupControllerEntries(presentationData: PresentationData, } var i: Int32 = 0 for username in usernames { - entries.append(.additionalLink(presentationData.theme, username, i)) + var canToggleIsActive = false + if !username.flags.contains(.isEditable) || isBot { + canToggleIsActive = true + } + entries.append(.additionalLink(presentationData.theme, username, i, canToggleIsActive)) i += 1 } @@ -613,7 +621,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup controller.setReorderEntry({ (fromIndex: Int, toIndex: Int, entries: [UsernameSetupEntry]) -> Signal in let fromEntry = entries[fromIndex] - guard case let .additionalLink(_, fromUsername, _) = fromEntry else { + guard case let .additionalLink(_, fromUsername, _, _) = fromEntry else { return .single(false) } var referenceId: String? @@ -626,7 +634,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup var i = 0 for entry in entries { switch entry { - case let .additionalLink(_, link, _): + case let .additionalLink(_, link, _, _): currentUsernames.append(link.username) if !link.isActive && maxIndex == nil { maxIndex = max(0, i - 1) @@ -639,7 +647,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup if toIndex < entries.count { switch entries[toIndex] { - case let .additionalLink(_, toUsername, _): + case let .additionalLink(_, toUsername, _, _): if toUsername.isActive { referenceId = toUsername.username } else { @@ -716,7 +724,7 @@ public func usernameSetupController(context: AccountContext, mode: UsernameSetup var currentUsernames: [TelegramPeerUsername] = [] for entry in entries { switch entry { - case let .additionalLink(_, username, _): + case let .additionalLink(_, username, _, _): currentUsernames.append(username) default: break diff --git a/submodules/TelegramCallsUI/Sources/VideoChatActionButtonComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatActionButtonComponent.swift index 621b648255..da16339766 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatActionButtonComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatActionButtonComponent.swift @@ -142,10 +142,11 @@ final class VideoChatActionButtonComponent: Component { let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.2) - let genericBackgroundColor = UIColor(rgb: 0x1b1d22) + let genericBackgroundColor = UIColor(rgb: 0x2d2f38) let titleText: String let backgroundColor: UIColor + var tintColorKind: GlassBackgroundView.TintColor.Kind = .panel let iconDiameter: CGFloat var isEnabled: Bool = true switch component.content { @@ -208,6 +209,7 @@ final class VideoChatActionButtonComponent: Component { case .leave: titleText = component.strings.VoiceChat_Leave backgroundColor = UIColor(rgb: 0x330d0b) + tintColorKind = .custom iconDiameter = 22.0 } @@ -282,7 +284,7 @@ final class VideoChatActionButtonComponent: Component { } } - self.background.update(size: size, cornerRadius: size.width * 0.5, isDark: true, tintColor: .init(kind: .custom, color: backgroundColor), transition: tintTransition) + self.background.update(size: size, cornerRadius: size.width * 0.5, isDark: true, tintColor: .init(kind: tintColorKind, color: backgroundColor), transition: tintTransition) transition.setFrame(view: self.background, frame: CGRect(origin: CGPoint(), size: size)) let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) * 0.5), y: size.height + 8.0), size: titleSize) diff --git a/submodules/TelegramCallsUI/Sources/VideoChatParticipantVideoComponent.swift b/submodules/TelegramCallsUI/Sources/VideoChatParticipantVideoComponent.swift index ec362d6601..a46563c51a 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatParticipantVideoComponent.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatParticipantVideoComponent.swift @@ -34,7 +34,7 @@ private func blurredAvatarImage(_ dataImage: UIImage) -> UIImage? { } private let activityBorderImage: UIImage = { - return generateStretchableFilledCircleImage(diameter: 20.0, color: nil, strokeColor: .white, strokeWidth: 2.0)!.withRenderingMode(.alwaysTemplate) + return generateStretchableFilledCircleImage(diameter: 32.0, color: nil, strokeColor: .white, strokeWidth: 2.0)!.withRenderingMode(.alwaysTemplate) }() final class VideoChatParticipantVideoComponent: Component { @@ -227,7 +227,7 @@ final class VideoChatParticipantVideoComponent: Component { self.pinchContainerNode.contentNode.view.addSubview(self.backgroundGradientView) //TODO:release optimize - self.pinchContainerNode.contentNode.view.layer.cornerRadius = 10.0 + self.pinchContainerNode.contentNode.view.layer.cornerRadius = 16.0 self.pinchContainerNode.contentNode.view.clipsToBounds = true self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) @@ -680,7 +680,7 @@ final class VideoChatParticipantVideoComponent: Component { if videoDescription != nil && self.videoSpec == nil && !isEffectivelyPaused { if self.loadingEffectView == nil { - let loadingEffectView = VideoChatVideoLoadingEffectView(effectAlpha: 0.1, borderAlpha: 0.2, cornerRadius: 10.0, duration: 1.0) + let loadingEffectView = VideoChatVideoLoadingEffectView(effectAlpha: 0.1, borderAlpha: 0.2, cornerRadius: 16.0, duration: 1.0) self.loadingEffectView = loadingEffectView loadingEffectView.alpha = 0.0 loadingEffectView.isUserInteractionEnabled = false diff --git a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift index cfca87664f..f8d039a3bb 100644 --- a/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VideoChatScreen.swift @@ -485,6 +485,14 @@ final class VideoChatScreenComponent: Component { if gestureRecognizer is UIPanGestureRecognizer { if let otherGestureRecognizer = otherGestureRecognizer as? UIPanGestureRecognizer { if otherGestureRecognizer.view is UIScrollView { + if let view = otherGestureRecognizer.view { + if let inputView = self.inputMediaNode?.view, view.isDescendant(of: inputView) { + return false + } + if let reactionView = self.reactionContextNode?.view, view.isDescendant(of: reactionView) { + return false + } + } return true } if let participantsView = self.participants.view as? VideoChatParticipantsComponent.View { @@ -2195,7 +2203,7 @@ final class VideoChatScreenComponent: Component { let landscapeControlsWidth: CGFloat = 104.0 var landscapeControlsOffsetX: CGFloat = 0.0 - //let landscapeControlsSpacing: CGFloat = 30.0 + let landscapeControlsSpacing: CGFloat = 30.0 var leftInset: CGFloat = max(environment.safeInsets.left, 16.0) @@ -2222,6 +2230,8 @@ final class VideoChatScreenComponent: Component { let navigationButtonDiameter: CGFloat = 40.0 let navigationButtonInset: CGFloat = 4.0 + let panelColor = UIColor(rgb: 0x1f1f27) + let navigationLeftButtonSize = self.navigationLeftButton.update( transition: .immediate, component: AnyComponent(PlainButtonComponent( @@ -2232,7 +2242,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: false, tintColor: .init(kind: .panel, color: panelColor)) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), @@ -2254,7 +2264,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: false, tintColor: .init(kind: .panel, color: panelColor)) ), effectAlignment: .center, minSize: CGSize(width: navigationButtonDiameter, height: navigationButtonDiameter), @@ -2646,24 +2656,28 @@ final class VideoChatScreenComponent: Component { //TODO:release let actionButtonSize = CGSize(width: actionButtonDiameter, height: actionButtonDiameter) - let firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) - let secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) + var firstActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) + var secondActionButtonFrame = CGRect(origin: CGPoint(x: firstActionButtonFrame.minX + 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) - let fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) - let thirdActionButtonFrame = CGRect(origin: CGPoint(x: fourthActionButtonFrame.minX - 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) - - let _ = firstActionButtonFrame - + var fourthActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) + var thirdActionButtonFrame = CGRect(origin: CGPoint(x: fourthActionButtonFrame.minX - 80.0, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: actionButtonSize) + // var leftActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.minX - actionMicrophoneButtonSpacing - actionButtonDiameter, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: CGSize(width: actionButtonDiameter, height: actionButtonDiameter)) // var rightActionButtonFrame = CGRect(origin: CGPoint(x: microphoneButtonFrame.maxX + actionMicrophoneButtonSpacing, y: microphoneButtonFrame.minY + floor((microphoneButtonFrame.height - actionButtonDiameter) * 0.5)), size: CGSize(width: actionButtonDiameter, height: actionButtonDiameter)) -// if buttonsOnTheSide { -// leftActionButtonFrame.origin.x = microphoneButtonFrame.minX -// leftActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter -// -// rightActionButtonFrame.origin.x = microphoneButtonFrame.minX -// rightActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing -// } + if buttonsOnTheSide { + secondActionButtonFrame.origin.x = microphoneButtonFrame.minX + secondActionButtonFrame.origin.y = microphoneButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter + + firstActionButtonFrame.origin.x = microphoneButtonFrame.minX + firstActionButtonFrame.origin.y = secondActionButtonFrame.minY - landscapeControlsSpacing - actionButtonDiameter + + thirdActionButtonFrame.origin.x = microphoneButtonFrame.minX + thirdActionButtonFrame.origin.y = microphoneButtonFrame.maxY + landscapeControlsSpacing + + fourthActionButtonFrame.origin.x = microphoneButtonFrame.minX + fourthActionButtonFrame.origin.y = thirdActionButtonFrame.maxY + landscapeControlsSpacing + } let participantsSize = availableSize diff --git a/submodules/TelegramUI/Components/ButtonComponent/BUILD b/submodules/TelegramUI/Components/ButtonComponent/BUILD index eeb8fe1cab..5ac4fd0d54 100644 --- a/submodules/TelegramUI/Components/ButtonComponent/BUILD +++ b/submodules/TelegramUI/Components/ButtonComponent/BUILD @@ -16,6 +16,8 @@ swift_library( "//submodules/ActivityIndicator", "//submodules/ShimmerEffect", "//submodules/Components/BundleIconComponent", + "//submodules/TelegramUI/Components/GlassBackgroundComponent", + ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift b/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift index 8d08f8da01..5b592224b0 100644 --- a/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift +++ b/submodules/TelegramUI/Components/ButtonComponent/Sources/ButtonComponent.swift @@ -6,6 +6,7 @@ import AnimatedTextComponent import ActivityIndicator import BundleIconComponent import ShimmerEffect +import GlassBackgroundComponent public final class ButtonBadgeComponent: Component { let fillColor: UIColor @@ -338,6 +339,12 @@ public final class ButtonTextContentComponent: Component { public final class ButtonComponent: Component { public struct Background: Equatable { + public enum Style { + case glass + case legacy + } + + public var style: Style public var color: UIColor public var foreground: UIColor public var pressedColor: UIColor @@ -345,12 +352,14 @@ public final class ButtonComponent: Component { public var isShimmering: Bool public init( + style: Style = .legacy, color: UIColor, foreground: UIColor, pressedColor: UIColor, cornerRadius: CGFloat = 10.0, isShimmering: Bool = false ) { + self.style = style self.color = color self.foreground = foreground self.pressedColor = pressedColor @@ -360,6 +369,7 @@ public final class ButtonComponent: Component { public func withIsShimmering(_ isShimmering: Bool) -> Background { return Background( + style: self.style, color: self.color, foreground: self.foreground, pressedColor: self.pressedColor, @@ -431,6 +441,7 @@ public final class ButtonComponent: Component { private weak var componentState: EmptyComponentState? private var shimmeringView: ButtonShimmeringView? + private var chromeView: UIImageView? private var contentItem: ContentItem? private var activityIndicator: ActivityIndicator? @@ -475,7 +486,12 @@ public final class ButtonComponent: Component { self.isEnabled = (component.isEnabled || component.allowActionWhenDisabled) && !component.displaysProgress transition.setBackgroundColor(view: self, color: component.background.color) - transition.setCornerRadius(layer: self.layer, cornerRadius: component.background.cornerRadius) + + var cornerRadius: CGFloat = component.background.cornerRadius + if case .glass = component.background.style, component.background.cornerRadius == 10.0 { + cornerRadius = availableSize.height * 0.5 + } + transition.setCornerRadius(layer: self.layer, cornerRadius: cornerRadius) var contentAlpha: CGFloat = 1.0 if component.displaysProgress { @@ -581,6 +597,33 @@ public final class ButtonComponent: Component { }) } + if component.background.style == .glass { + let chromeView: UIImageView + var chromeTransition = transition + if let current = self.chromeView { + chromeView = current + } else { + chromeTransition = .immediate + chromeView = UIImageView() + self.chromeView = chromeView + if let shimmeringView = self.shimmeringView { + self.insertSubview(chromeView, aboveSubview: shimmeringView) + } else { + self.insertSubview(chromeView, at: 0) + } + + chromeView.layer.compositingFilter = "overlayBlendMode" + chromeView.alpha = 0.8 + chromeView.image = GlassBackgroundView.generateForegroundImage(size: CGSize(width: 26.0 * 2.0, height: 26.0 * 2.0), isDark: component.background.color.lightness < 0.4, fillColor: .clear) + } + chromeTransition.setFrame(view: chromeView, frame: CGRect(origin: .zero, size: availableSize)) + } else if let chromeView = self.chromeView { + self.chromeView = nil + chromeView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { _ in + chromeView.removeFromSuperview() + }) + } + return availableSize } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift index b766c38d04..11e5e71808 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift @@ -834,7 +834,8 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { file: arguments.parentMessage.associatedMedia[MediaId( namespace: Namespaces.Media.CloudFile, id: backgroundEmojiId - )] as? TelegramMediaFile + )] as? TelegramMediaFile, + emptyCorner: giftEmojiFileId != nil ) } var isTransparent: Bool = false @@ -898,16 +899,19 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { } if let giftEmojiFileId { - let giftLayerSize = CGSize(width: 20.0, height: 20.0) - let giftLayerFrame = CGRect(origin: CGPoint(x: textFrame.minX - 16.0, y: 5.0), size: giftLayerSize) + let giftLayerSize = CGSize(width: 18.0, height: 18.0) + let giftLayerFrame = CGRect(origin: CGPoint(x: realSize.width - giftLayerSize.width - 4.0, y: 3.0), size: giftLayerSize) let giftEmojiLayer: InlineStickerItemLayer - if let current = node.giftEmojiLayer { + if let current = node.giftEmojiLayer, current.file?.fileId.id == giftEmojiFileId { giftEmojiLayer = current - animation.animator.updateFrame(layer: giftEmojiLayer, frame: giftLayerFrame, completion: nil) } else { - giftEmojiLayer = InlineStickerItemLayer(context: arguments.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: giftEmojiFileId, file: nil, custom: nil, enableAnimation: true), file: nil, cache: arguments.context.animationCache, renderer: arguments.context.animationRenderer, unique: false, placeholderColor: placeholderColor, pointSize: giftLayerSize, dynamicColor: nil, loopCount: 2) + if let giftEmojiLayer = node.giftEmojiLayer { + node.giftEmojiLayer = nil + giftEmojiLayer.removeFromSuperlayer() + } + giftEmojiLayer = InlineStickerItemLayer(context: arguments.context, userLocation: .other, attemptSynchronousLoad: true, emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: giftEmojiFileId, file: nil, custom: nil, enableAnimation: true), file: nil, cache: arguments.context.animationCache, renderer: arguments.context.animationRenderer, unique: false, placeholderColor: placeholderColor, pointSize: CGSize(width: giftLayerSize.width * 2.0, height: giftLayerSize.height * 2.0), dynamicColor: nil, loopCount: 2) node.giftEmojiLayer = giftEmojiLayer node.contentNode.layer.addSublayer(giftEmojiLayer) diff --git a/submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView/Sources/MessageInlineBlockBackgroundView.swift b/submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView/Sources/MessageInlineBlockBackgroundView.swift index e1797506dc..7408d13b04 100644 --- a/submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView/Sources/MessageInlineBlockBackgroundView.swift +++ b/submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView/Sources/MessageInlineBlockBackgroundView.swift @@ -426,11 +426,13 @@ public final class MessageInlineBlockBackgroundView: UIView { public let context: AccountContext public let fileId: Int64 public let file: TelegramMediaFile? + public let emptyCorner: Bool - public init(context: AccountContext, fileId: Int64, file: TelegramMediaFile?) { + public init(context: AccountContext, fileId: Int64, file: TelegramMediaFile?, emptyCorner: Bool = false) { self.context = context self.fileId = fileId self.file = file + self.emptyCorner = emptyCorner } public static func ==(lhs: Pattern, rhs: Pattern) -> Bool { @@ -446,7 +448,9 @@ public final class MessageInlineBlockBackgroundView: UIView { if lhs.file?.fileId != rhs.file?.fileId { return false } - + if lhs.emptyCorner != rhs.emptyCorner { + return false + } return true } } @@ -771,8 +775,13 @@ public final class MessageInlineBlockBackgroundView: UIView { patternContentLayer.frame = CGRect(origin: CGPoint(x: patternOrigin.x - placement.position.x / 3.0 - itemSize.width * 0.5, y: patternOrigin.y + placement.position.y / 3.0 - itemSize.height * 0.5), size: itemSize) var alphaFraction = abs(placement.position.x / 3.0) / min(500.0, size.width) alphaFraction = min(1.0, max(0.0, alphaFraction)) - patternContentLayer.opacity = 0.3 * Float(1.0 - alphaFraction) * Float(patternAlpha) + if maxIndex == 1 && params.pattern?.emptyCorner == true { + patternContentLayer.opacity = 0.0 + } else { + patternContentLayer.opacity = 0.3 * Float(1.0 - alphaFraction) * Float(patternAlpha) + } + maxIndex += 1 } diff --git a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift index 88d6c0083e..7408ebb792 100644 --- a/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift +++ b/submodules/TelegramUI/Components/GlassBackgroundComponent/Sources/GlassBackgroundComponent.swift @@ -784,10 +784,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 +797,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 +808,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/ListActionItemComponent/Sources/ListActionItemComponent.swift b/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift index 0840cf9a5b..91b1cb1f84 100644 --- a/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift +++ b/submodules/TelegramUI/Components/ListActionItemComponent/Sources/ListActionItemComponent.swift @@ -8,6 +8,11 @@ import SwitchNode import CheckNode public final class ListActionItemComponent: Component { + public enum Style { + case glass + case legacy + } + public enum ToggleStyle { case regular case icons @@ -133,6 +138,7 @@ public final class ListActionItemComponent: Component { } public let theme: PresentationTheme + public let style: Style public let background: AnyComponent? public let title: AnyComponent public let titleAlignment: Alignment @@ -146,6 +152,7 @@ public final class ListActionItemComponent: Component { public init( theme: PresentationTheme, + style: Style = .legacy, background: AnyComponent? = nil, title: AnyComponent, titleAlignment: Alignment = .default, @@ -158,6 +165,7 @@ public final class ListActionItemComponent: Component { updateIsHighlighted: ((UIView, Bool) -> Void)? = nil ) { self.theme = theme + self.style = style self.background = background self.title = title self.titleAlignment = titleAlignment @@ -174,6 +182,9 @@ public final class ListActionItemComponent: Component { if lhs.theme !== rhs.theme { return false } + if lhs.style != rhs.style { + return false + } if lhs.background != rhs.background { return false } @@ -391,8 +402,19 @@ public final class ListActionItemComponent: Component { contentRightInset = customAccessorySizeValue.width + customAccessory.insets.left + customAccessory.insets.right } + var contentInsets = component.contentInsets + switch component.style { + case .glass: + if contentInsets.top == 12.0 && contentInsets.bottom == 12.0 { + contentInsets.top = 16.0 + contentInsets.bottom = 16.0 + } + case .legacy: + break + } + var contentHeight: CGFloat = 0.0 - contentHeight += component.contentInsets.top + contentHeight += contentInsets.top if let leftIcon = component.leftIcon { switch leftIcon { @@ -413,12 +435,11 @@ public final class ListActionItemComponent: Component { if case .center = component.titleAlignment { contentLeftInset = floor((availableSize.width - titleSize.width) / 2.0) } - - + let titleY = contentHeight contentHeight += titleSize.height - contentHeight += component.contentInsets.bottom + contentHeight += contentInsets.bottom if let iconValue = component.icon { if previousComponent?.icon?.component.id != iconValue.component.id, let icon = self.icon { diff --git a/submodules/TelegramUI/Components/ListSectionComponent/Sources/ListSectionComponent.swift b/submodules/TelegramUI/Components/ListSectionComponent/Sources/ListSectionComponent.swift index 85e90bf1cb..1c41f855c9 100644 --- a/submodules/TelegramUI/Components/ListSectionComponent/Sources/ListSectionComponent.swift +++ b/submodules/TelegramUI/Components/ListSectionComponent/Sources/ListSectionComponent.swift @@ -41,6 +41,7 @@ public final class ListSectionContentView: UIView { public final class Configuration { public let theme: PresentationTheme + public let style: ListSectionComponent.Style public let isModal: Bool public let displaySeparators: Bool public let extendsItemHighlightToSection: Bool @@ -48,12 +49,14 @@ public final class ListSectionContentView: UIView { public init( theme: PresentationTheme, + style: ListSectionComponent.Style = .legacy, isModal: Bool = false, displaySeparators: Bool, extendsItemHighlightToSection: Bool, background: ListSectionComponent.Background ) { self.theme = theme + self.style = style self.isModal = isModal self.displaySeparators = displaySeparators self.extendsItemHighlightToSection = extendsItemHighlightToSection @@ -152,6 +155,14 @@ public final class ListSectionContentView: UIView { } self.externalContentBackgroundView.updateColor(color: backgroundColor, transition: transition) + let cornerRadius: CGFloat + switch configuration.style { + case .glass: + cornerRadius = 26.0 + case .legacy: + cornerRadius = 11.0 + } + var innerContentHeight: CGFloat = 0.0 var validItemIds: [AnyHashable] = [] for index in 0 ..< readyItems.count { @@ -264,18 +275,18 @@ public final class ListSectionContentView: UIView { let backgroundFrame: CGRect var backgroundAlpha: CGFloat = 1.0 - var contentCornerRadius: CGFloat = 11.0 + var contentCornerRadius: CGFloat = cornerRadius switch configuration.background { case let .none(clipped): backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size) backgroundAlpha = 0.0 - self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: 11.0, maxXMinY: 11.0, minXMaxY: 11.0, maxXMaxY: 11.0), transition: transition) + self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: cornerRadius, maxXMinY: cornerRadius, minXMaxY: cornerRadius, maxXMaxY: cornerRadius), transition: transition) if !clipped { contentCornerRadius = 0.0 } case .all: backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: size) - self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: 11.0, maxXMinY: 11.0, minXMaxY: 11.0, maxXMaxY: 11.0), transition: transition) + self.externalContentBackgroundView.update(size: backgroundFrame.size, corners: DynamicCornerRadiusView.Corners(minXMinY: cornerRadius, maxXMinY: cornerRadius, minXMaxY: cornerRadius, maxXMaxY: cornerRadius), transition: transition) case let .range(from, corners): if let itemView = self.itemViews[from], itemView.frame.minY < size.height { backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: itemView.frame.minY), size: CGSize(width: size.width, height: size.height - itemView.frame.minY)) @@ -306,7 +317,13 @@ public final class ListSectionComponent: Component { case range(from: AnyHashable, corners: DynamicCornerRadiusView.Corners) } + public enum Style { + case glass + case legacy + } + public let theme: PresentationTheme + public let style: Style public let background: Background public let header: AnyComponent? public let footer: AnyComponent? @@ -317,6 +334,7 @@ public final class ListSectionComponent: Component { public init( theme: PresentationTheme, + style: Style = .legacy, background: Background = .all, header: AnyComponent?, footer: AnyComponent?, @@ -326,6 +344,7 @@ public final class ListSectionComponent: Component { extendsItemHighlightToSection: Bool = false ) { self.theme = theme + self.style = style self.background = background self.header = header self.footer = footer @@ -339,6 +358,9 @@ public final class ListSectionComponent: Component { if lhs.theme !== rhs.theme { return false } + if lhs.style != rhs.style { + return false + } if lhs.background != rhs.background { return false } @@ -464,6 +486,7 @@ public final class ListSectionComponent: Component { let contentResult = self.contentView.update( configuration: ListSectionContentView.Configuration( theme: component.theme, + style: component.style, isModal: component.isModal, displaySeparators: component.displaySeparators, extendsItemHighlightToSection: component.extendsItemHighlightToSection, @@ -638,6 +661,7 @@ public final class ListSubSectionComponent: Component { let contentResult = self.contentView.update( configuration: ListSectionContentView.Configuration( theme: component.theme, + style: .legacy, isModal: component.isModal, displaySeparators: component.displaySeparators, extendsItemHighlightToSection: false, diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD index 6b4a2af12c..b7188b46bd 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/BUILD @@ -54,6 +54,7 @@ swift_library( "//submodules/TelegramUI/Components/EmojiActionIconComponent", "//submodules/TelegramUI/Components/TabSelectorComponent", "//submodules/TelegramUI/Components/PlainButtonComponent", + "//submodules/TextFormat", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift index 1920156e41..c3c1ee0d1e 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift @@ -33,6 +33,8 @@ import PeerNameColorItem import EmojiActionIconComponent import TabSelectorComponent import WallpaperResources +import EdgeEffect +import TextFormat private let giftListTag = GenericComponentViewTag() @@ -143,8 +145,7 @@ final class UserAppearanceScreenComponent: Component { private let topOverscrollLayer = SimpleLayer() private let scrollView: ScrollView private let actionButton = ComponentView() - private let bottomPanelBackgroundView: BlurredBackgroundView - private let bottomPanelSeparator: SimpleLayer + private let edgeEffectView: EdgeEffectView private let backButton = PeerInfoHeaderNavigationButton() @@ -154,13 +155,14 @@ final class UserAppearanceScreenComponent: Component { case name } private var currentSection: Section = .profile - - private let previewSection = ComponentView() - private let boostSection = ComponentView() - private let bannerSection = ComponentView() - private let replySection = ComponentView() - private let resetColorSection = ComponentView() + + private let profilePreview = ComponentView() + private let profileColorSection = ComponentView() + private let profileResetColorSection = ComponentView() private let profileGiftsSection = ComponentView() + + private let namePreview = ComponentView() + private let nameColorSection = ComponentView() private let nameGiftsSection = ComponentView() private var isUpdating: Bool = false @@ -195,6 +197,8 @@ final class UserAppearanceScreenComponent: Component { private weak var emojiStatusSelectionController: ViewController? + private var cachedChevronImage: (UIImage, PresentationTheme)? + override init(frame: CGRect) { self.scrollView = ScrollView() self.scrollView.showsVerticalScrollIndicator = false @@ -208,8 +212,7 @@ final class UserAppearanceScreenComponent: Component { } self.scrollView.alwaysBounceVertical = true - self.bottomPanelBackgroundView = BlurredBackgroundView(color: .clear, enableBlur: true) - self.bottomPanelSeparator = SimpleLayer() + self.edgeEffectView = EdgeEffectView() super.init(frame: frame) @@ -218,9 +221,8 @@ final class UserAppearanceScreenComponent: Component { self.scrollView.layer.addSublayer(self.topOverscrollLayer) - self.addSubview(self.bottomPanelBackgroundView) - self.layer.addSublayer(self.bottomPanelSeparator) - + self.addSubview(self.edgeEffectView) + self.backButton.action = { [weak self] _, _ in if let self, let controller = self.environment?.controller() { controller.navigationController?.popViewController(animated: true) @@ -297,16 +299,10 @@ final class UserAppearanceScreenComponent: Component { if self.scrolledUp != scrolledUp { self.scrolledUp = scrolledUp if !self.isUpdating { - self.state?.updated() + self.state?.updated(transition: .easeInOut(duration: 0.3)) } } - let bottomNavigationAlphaDistance: CGFloat = 16.0 - let bottomNavigationAlpha: CGFloat = max(0.0, min(1.0, (self.scrollView.contentSize.height - self.scrollView.bounds.maxY) / bottomNavigationAlphaDistance)) - - transition.setAlpha(view: self.bottomPanelBackgroundView, alpha: bottomNavigationAlpha) - transition.setAlpha(layer: self.bottomPanelSeparator, alpha: bottomNavigationAlpha) - switch self.currentSection { case .profile: if let giftListView = self.profileGiftsSection.findTaggedView(tag: giftListTag) as? GiftListItemComponent.View { @@ -600,6 +596,9 @@ final class UserAppearanceScreenComponent: Component { } switch subject { case .reply: + if case .collectible = resolvedState.nameColor { + self.updatedPeerNameColor = .preset(.blue) + } if let result { self.updatedPeerNameEmoji = result.fileId.id } else { @@ -681,6 +680,10 @@ final class UserAppearanceScreenComponent: Component { self.backgroundColor = environment.theme.list.blocksBackgroundColor } + if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme { + self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme) + } + if self.contentsDataDisposable == nil { self.contentsDataDisposable = (ContentsData.get(context: component.context) |> deliverOnMainQueue).start(next: { [weak self] contentsData in @@ -804,7 +807,7 @@ final class UserAppearanceScreenComponent: Component { } if let intValue = value.base as? Int32 { self.currentSection = Section(rawValue: intValue) ?? .profile - self.state?.updated(transition: .immediate) + self.state?.updated(transition: .easeInOut(duration: 0.3)) } } ) @@ -828,15 +831,21 @@ final class UserAppearanceScreenComponent: Component { let listItemParams = ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true) var contentHeight: CGFloat = 0.0 - - let sectionTransition = transition - - let itemCornerRadius: CGFloat = 10.0 + + let itemCornerRadius: CGFloat = 26.0 switch self.currentSection { case .profile: - if let replySectionView = self.replySection.view, replySectionView.superview != nil { - replySectionView.removeFromSuperview() + var transition = transition + if self.profilePreview.view == nil { + transition = .immediate + } + + if let namePreviewView = self.namePreview.view, namePreviewView.superview != nil { + namePreviewView.removeFromSuperview() + } + if let nameColorSectionView = self.nameColorSection.view, nameColorSectionView.superview != nil { + nameColorSectionView.removeFromSuperview() } if let nameGiftsSectionView = self.nameGiftsSection.view, nameGiftsSectionView.superview != nil { nameGiftsSectionView.removeFromSuperview() @@ -849,47 +858,36 @@ final class UserAppearanceScreenComponent: Component { if case .starGift = resolvedState.emojiStatus?.content { hasHeaderColor = true } - - let previewSectionSize = self.previewSection.update( - transition: sectionTransition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - background: .none(clipped: false), - header: nil, - footer: nil, - items: [ - AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor( - itemGenerator: PeerNameColorProfilePreviewItem( - context: component.context, - theme: environment.theme, - componentTheme: environment.theme, - strings: environment.strings, - topInset: 0.0, - sectionId: 0, - peer: peer, - subtitleString: environment.strings.Presence_online, - files: self.cachedIconFiles, - nameDisplayOrder: presentationData.nameDisplayOrder, - showBackground: false - ), - params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true) - ))), - ], - displaySeparators: false, - extendsItemHighlightToSection: true - )), + + let profilePreviewSize = self.profilePreview.update( + transition: transition, + component: AnyComponent(TopBottomCornersComponent(topCornerRadius: itemCornerRadius, bottomCornerRadius: !self.scrolledUp ? itemCornerRadius : 0.0, component: AnyComponent(ListItemComponentAdaptor( + itemGenerator: PeerNameColorProfilePreviewItem( + context: component.context, + theme: environment.theme, + componentTheme: environment.theme, + strings: environment.strings, + topInset: 0.0, + sectionId: 0, + peer: peer, + subtitleString: environment.strings.Presence_online, + files: self.cachedIconFiles, + nameDisplayOrder: presentationData.nameDisplayOrder, + showBackground: false + ), + params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true) + )))), environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) - let previewSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: previewSectionSize) - if let previewSectionView = self.previewSection.view { - if previewSectionView.superview == nil { - self.addSubview(previewSectionView) + let profilePreviewFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: profilePreviewSize) + if let profilePreviewView = self.profilePreview.view { + if profilePreviewView.superview == nil { + self.addSubview(profilePreviewView) } - sectionTransition.setFrame(view: previewSectionView, frame: previewSectionFrame) + transition.setFrame(view: profilePreviewView, frame: profilePreviewFrame) } - contentHeight += previewSectionSize.height - contentHeight += environment.navigationHeight + 12.0 + contentHeight += profilePreviewSize.height - 18.0 var profileLogoContents: [AnyComponentWithIdentity] = [] profileLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( @@ -900,15 +898,50 @@ final class UserAppearanceScreenComponent: Component { )), maximumNumberOfLines: 0 )))) - let bannerSectionSize = self.bannerSection.update( - transition: sectionTransition, + + //TODO:localize + let footerAttributes = MarkdownAttributes( + body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.freeTextColor), + bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: environment.theme.list.freeTextColor), + link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: environment.theme.list.itemAccentColor), + linkAttribute: { contents in + return (TelegramTextAttributes.URL, contents) + } + ) + let previewFooterText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("You can also change color of your name and customize replies to you. [Change >]()", attributes: footerAttributes)) + if let range = previewFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 { + previewFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: previewFooterText.string)) + } + + let profileColorSectionSize = self.profileColorSection.update( + transition: transition, component: AnyComponent(ListSectionComponent( theme: environment.theme, - background: .range(from: 1, corners: DynamicCornerRadiusView.Corners(minXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, maxXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)), + style: .glass, + background: .range(from: 0, corners: DynamicCornerRadiusView.Corners(minXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, maxXMinY: !hasHeaderColor ? itemCornerRadius : 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)), header: nil, - footer: nil, + footer: AnyComponent(MultilineTextComponent( + text: .plain(previewFooterText), + maximumNumberOfLines: 0, + highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1), + highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), + highlightAction: { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { + return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + } else { + return nil + } + }, + tapAction: { [weak self] _, _ in + guard let self else { + return + } + self.currentSection = .name + self.state?.updated(transition: .easeInOut(duration: 0.3)) + } + )), items: [ - AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor( + AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor( itemGenerator: PeerNameColorItem( theme: environment.theme, colors: component.context.peerNameColors, @@ -928,8 +961,9 @@ final class UserAppearanceScreenComponent: Component { ), params: listItemParams ))), - AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( + AnyComponentWithIdentity(id: 1, component: AnyComponent(ListActionItemComponent( theme: environment.theme, + style: .glass, title: AnyComponent(HStack(profileLogoContents, spacing: 6.0)), icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( context: component.context, @@ -956,25 +990,27 @@ final class UserAppearanceScreenComponent: Component { environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) - let bannerSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: bannerSectionSize) - if let bannerSectionView = self.bannerSection.view { - if bannerSectionView.superview == nil { - self.scrollView.addSubview(bannerSectionView) + let profileColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: profileColorSectionSize) + if let profileColorSectionView = self.profileColorSection.view { + if profileColorSectionView.superview == nil { + self.scrollView.addSubview(profileColorSectionView) } - sectionTransition.setFrame(view: bannerSectionView, frame: bannerSectionFrame) + transition.setFrame(view: profileColorSectionView, frame: profileColorSectionFrame) } - contentHeight += bannerSectionSize.height + contentHeight += profileColorSectionSize.height contentHeight += sectionSpacing - let resetColorSectionSize = self.resetColorSection.update( - transition: sectionTransition, + let profileResetColorSectionSize = self.profileResetColorSection.update( + transition: transition, component: AnyComponent(ListSectionComponent( theme: environment.theme, + style: .glass, header: nil, footer: nil, items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( theme: environment.theme, + style: .glass, title: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: environment.strings.Channel_Appearance_ResetProfileColor, @@ -1011,18 +1047,18 @@ final class UserAppearanceScreenComponent: Component { displayResetProfileColor = true } - let resetColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: resetColorSectionSize) - if let resetColorSectionView = self.resetColorSection.view { - if resetColorSectionView.superview == nil { - self.scrollView.addSubview(resetColorSectionView) + let profileResetColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: profileResetColorSectionSize) + if let profileResetColorSectionView = self.profileResetColorSection.view { + if profileResetColorSectionView.superview == nil { + self.scrollView.addSubview(profileResetColorSectionView) } - sectionTransition.setPosition(view: resetColorSectionView, position: resetColorSectionFrame.center) - sectionTransition.setBounds(view: resetColorSectionView, bounds: CGRect(origin: CGPoint(), size: resetColorSectionFrame.size)) - sectionTransition.setScale(view: resetColorSectionView, scale: displayResetProfileColor ? 1.0 : 0.001) - sectionTransition.setAlpha(view: resetColorSectionView, alpha: displayResetProfileColor ? 1.0 : 0.0) + transition.setPosition(view: profileResetColorSectionView, position: profileResetColorSectionFrame.center) + transition.setBounds(view: profileResetColorSectionView, bounds: CGRect(origin: CGPoint(), size: profileResetColorSectionFrame.size)) + transition.setScale(view: profileResetColorSectionView, scale: displayResetProfileColor ? 1.0 : 0.001) + transition.setAlpha(view: profileResetColorSectionView, alpha: displayResetProfileColor ? 1.0 : 0.0) } if displayResetProfileColor { - contentHeight += resetColorSectionSize.height + contentHeight += profileResetColorSectionSize.height contentHeight += sectionSpacing } @@ -1032,9 +1068,10 @@ final class UserAppearanceScreenComponent: Component { selectedGiftId = id } let giftsSectionSize = self.profileGiftsSection.update( - transition: sectionTransition, + transition: transition, component: AnyComponent(ListSectionComponent( theme: environment.theme, + style: .glass, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: environment.strings.NameColor_GiftTitle, @@ -1106,19 +1143,24 @@ final class UserAppearanceScreenComponent: Component { if giftsSectionView.superview == nil { self.scrollView.addSubview(giftsSectionView) } - sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) + transition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) } contentHeight += giftsSectionSize.height contentHeight += sectionSpacing } case .name: - if let previewSectionView = self.previewSection.view, previewSectionView.superview != nil { - previewSectionView.removeFromSuperview() + var transition = transition + if self.namePreview.view == nil { + transition = .immediate } - if let bannerSectionView = self.bannerSection.view, bannerSectionView.superview != nil { - bannerSectionView.removeFromSuperview() + + if let profilePreviewView = self.profilePreview.view, profilePreviewView.superview != nil { + profilePreviewView.removeFromSuperview() } - if let resetColorSectionView = self.resetColorSection.view, resetColorSectionView.superview != nil { + if let profileColorSectionView = self.profileColorSection.view, profileColorSectionView.superview != nil { + profileColorSectionView.removeFromSuperview() + } + if let resetColorSectionView = self.profileResetColorSection.view, resetColorSectionView.superview != nil { resetColorSectionView.removeFromSuperview() } if let profileGiftsSectionView = self.profileGiftsSection.view, profileGiftsSectionView.superview != nil { @@ -1165,10 +1207,42 @@ final class UserAppearanceScreenComponent: Component { replyColor = collectibleColor.mainColor(dark: environment.theme.overallDarkAppearance) } - let replySectionSize = self.replySection.update( - transition: sectionTransition, + let namePreviewSize = self.namePreview.update( + transition: transition, + component: AnyComponent(TopBottomCornersComponent(topCornerRadius: itemCornerRadius, bottomCornerRadius: !self.scrolledUp ? itemCornerRadius : 0.0, component: AnyComponent(ListItemComponentAdaptor( + itemGenerator: PeerNameColorChatPreviewItem( + context: component.context, + theme: chatPreviewTheme, + componentTheme: chatPreviewTheme, + strings: environment.strings, + sectionId: 0, + fontSize: presentationData.chatFontSize, + chatBubbleCorners: presentationData.chatBubbleCorners, + wallpaper: chatPreviewWallpaper, + dateTimeFormat: environment.dateTimeFormat, + nameDisplayOrder: presentationData.nameDisplayOrder, + messageItems: [messageItem] + ), + params: ListViewItemLayoutParams(width: availableSize.width - sideInset * 2.0, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true) + )))), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + ) + let namePreviewFrame = CGRect(origin: CGPoint(x: sideInset, y: environment.navigationHeight + 12.0), size: namePreviewSize) + if let namePreviewView = self.namePreview.view { + if namePreviewView.superview == nil { + self.addSubview(namePreviewView) + } + transition.setFrame(view: namePreviewView, frame: namePreviewFrame) + } + contentHeight += namePreviewSize.height - 18.0 + + let nameColorSectionSize = self.nameColorSection.update( + transition: transition, component: AnyComponent(ListSectionComponent( theme: environment.theme, + style: .glass, + background: .range(from: 0, corners: DynamicCornerRadiusView.Corners(minXMinY: 0.0, maxXMinY: 0.0, minXMaxY: itemCornerRadius, maxXMaxY: itemCornerRadius)), header: nil, footer: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( @@ -1180,31 +1254,18 @@ final class UserAppearanceScreenComponent: Component { )), items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor( - itemGenerator: PeerNameColorChatPreviewItem( - context: component.context, - theme: chatPreviewTheme, - componentTheme: chatPreviewTheme, - strings: environment.strings, - sectionId: 0, - fontSize: presentationData.chatFontSize, - chatBubbleCorners: presentationData.chatBubbleCorners, - wallpaper: chatPreviewWallpaper, - dateTimeFormat: environment.dateTimeFormat, - nameDisplayOrder: presentationData.nameDisplayOrder, - messageItems: [messageItem] - ), - params: listItemParams - ))), - AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor( itemGenerator: PeerNameColorItem( theme: environment.theme, colors: component.context.peerNameColors, mode: .name, currentColor: resolvedState.nameColor.nameColor, updated: { [weak self] value in - guard let self, let value else { + guard let self, let resolvedState = self.resolveState(), let value else { return } + if case .collectible = resolvedState.nameColor { + self.updatedPeerNameEmoji = .some(nil) + } self.updatedPeerNameColor = .preset(value) self.state?.updated(transition: .spring(duration: 0.4)) }, @@ -1212,8 +1273,9 @@ final class UserAppearanceScreenComponent: Component { ), params: listItemParams ))), - AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( + AnyComponentWithIdentity(id: 1, component: AnyComponent(ListActionItemComponent( theme: environment.theme, + style: .glass, title: AnyComponent(HStack(replyLogoContents, spacing: 6.0)), icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( context: component.context, @@ -1236,14 +1298,14 @@ final class UserAppearanceScreenComponent: Component { environment: {}, containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) - let replySectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: replySectionSize) - if let replySectionView = self.replySection.view { - if replySectionView.superview == nil { - self.scrollView.addSubview(replySectionView) + let nameColorSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: nameColorSectionSize) + if let nameColorSectionView = self.nameColorSection.view { + if nameColorSectionView.superview == nil { + self.scrollView.addSubview(nameColorSectionView) } - sectionTransition.setFrame(view: replySectionView, frame: replySectionFrame) + transition.setFrame(view: nameColorSectionView, frame: nameColorSectionFrame) } - contentHeight += replySectionSize.height + contentHeight += nameColorSectionSize.height contentHeight += sectionSpacing if !self.starGifts.isEmpty { @@ -1252,9 +1314,10 @@ final class UserAppearanceScreenComponent: Component { selectedGiftId = collectibleColor.collectibleId } let giftsSectionSize = self.nameGiftsSection.update( - transition: sectionTransition, + transition: transition, component: AnyComponent(ListSectionComponent( theme: environment.theme, + style: .glass, header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: environment.strings.NameColor_GiftTitle, @@ -1284,6 +1347,7 @@ final class UserAppearanceScreenComponent: Component { } self.updatedPeerNameColor = .collectible(peerColor) + self.updatedPeerNameEmoji = peerColor.backgroundEmojiId self.state?.updated(transition: .spring(duration: 0.4)) }, tag: giftListTag @@ -1300,7 +1364,7 @@ final class UserAppearanceScreenComponent: Component { if giftsSectionView.superview == nil { self.scrollView.addSubview(giftsSectionView) } - sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) + transition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) } contentHeight += giftsSectionSize.height contentHeight += sectionSpacing @@ -1309,10 +1373,12 @@ final class UserAppearanceScreenComponent: Component { contentHeight += bottomContentInset - var buttonTitle = environment.strings.Channel_Appearance_ApplyButton - if let emojiStatus = resolvedState.emojiStatus, case .starGift = emojiStatus.content, resolvedState.changes.contains(.emojiStatus) { - buttonTitle = environment.strings.NameColor_WearCollectible - } + //TODO:localize + let buttonSideInset: CGFloat = 36.0 + let buttonTitle = "Apply Style" // environment.strings.Channel_Appearance_ApplyButton +// if let emojiStatus = resolvedState.emojiStatus, case .starGift = emojiStatus.content, resolvedState.changes.contains(.emojiStatus) { +// buttonTitle = environment.strings.NameColor_WearCollectible +// } var buttonContents: [AnyComponentWithIdentity] = [] buttonContents.append(AnyComponentWithIdentity(id: AnyHashable(buttonTitle), component: AnyComponent( @@ -1323,6 +1389,7 @@ final class UserAppearanceScreenComponent: Component { transition: transition, component: AnyComponent(ButtonComponent( background: ButtonComponent.Background( + style: .glass, color: environment.theme.list.itemCheckColors.fillColor, foreground: environment.theme.list.itemCheckColors.foregroundColor, pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8) @@ -1341,7 +1408,7 @@ final class UserAppearanceScreenComponent: Component { } )), environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0) + containerSize: CGSize(width: availableSize.width - buttonSideInset * 2.0, height: 52.0) ) contentHeight += buttonSize.height @@ -1350,7 +1417,7 @@ final class UserAppearanceScreenComponent: Component { let buttonY = availableSize.height - bottomInset - environment.safeInsets.bottom - buttonSize.height - let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: buttonY), size: buttonSize) + let buttonFrame = CGRect(origin: CGPoint(x: buttonSideInset, y: buttonY), size: buttonSize) if let buttonView = self.actionButton.view { if buttonView.superview == nil { self.addSubview(buttonView) @@ -1359,26 +1426,24 @@ final class UserAppearanceScreenComponent: Component { transition.setAlpha(view: buttonView, alpha: 1.0) } - let bottomPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: buttonY - 8.0), size: CGSize(width: availableSize.width, height: availableSize.height - buttonY + 8.0)) - transition.setFrame(view: self.bottomPanelBackgroundView, frame: bottomPanelFrame) - self.bottomPanelBackgroundView.updateColor(color: environment.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) - self.bottomPanelBackgroundView.update(size: bottomPanelFrame.size, transition: transition.containedViewLayoutTransition) - - self.bottomPanelSeparator.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor - transition.setFrame(layer: self.bottomPanelSeparator, frame: CGRect(origin: CGPoint(x: bottomPanelFrame.minX, y: bottomPanelFrame.minY), size: CGSize(width: bottomPanelFrame.width, height: UIScreenPixel))) - + let edgeEffectHeight: CGFloat = availableSize.height - buttonY + 8.0 + let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - edgeEffectHeight), size: CGSize(width: availableSize.width, height: edgeEffectHeight)) + transition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame) + self.edgeEffectView.update(content: environment.theme.list.blocksBackgroundColor, isInverted: false, rect: edgeEffectFrame, edge: .bottom, edgeSize: edgeEffectFrame.height, containerSize: availableSize, transition: transition) + let previousBounds = self.scrollView.bounds let contentSize = CGSize(width: availableSize.width, height: contentHeight) - if self.scrollView.frame != CGRect(origin: CGPoint(), size: availableSize) { - self.scrollView.frame = CGRect(origin: CGPoint(), size: availableSize) + let scrollViewFrame = CGRect(origin: CGPoint(x: 0.0, y: environment.navigationHeight + 30.0), size: CGSize(width: availableSize.width, height: availableSize.height - environment.navigationHeight - 30.0)) + if self.scrollView.frame != scrollViewFrame { + self.scrollView.frame = scrollViewFrame } if self.scrollView.contentSize != contentSize { self.scrollView.contentSize = contentSize } - let scrollInsets = UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: availableSize.height - bottomPanelFrame.minY, right: 0.0) - if self.scrollView.verticalScrollIndicatorInsets != scrollInsets { - self.scrollView.verticalScrollIndicatorInsets = scrollInsets - } +// let scrollInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: availableSize.height - bottomPanelFrame.minY, right: 0.0) +// if self.scrollView.verticalScrollIndicatorInsets != scrollInsets { +// self.scrollView.verticalScrollIndicatorInsets = scrollInsets +// } if !previousBounds.isEmpty, !transition.animation.isImmediate { let bounds = self.scrollView.bounds @@ -1388,7 +1453,8 @@ final class UserAppearanceScreenComponent: Component { } } - self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -3000.0), size: CGSize(width: availableSize.width, height: 3000.0)) + self.topOverscrollLayer.backgroundColor = environment.theme.list.itemBlocksBackgroundColor.cgColor + self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: sideInset, y: -1000.0), size: CGSize(width: availableSize.width - sideInset * 2.0, height: 1315.0)) self.updateScrolling(transition: transition) @@ -1397,7 +1463,7 @@ final class UserAppearanceScreenComponent: Component { size: availableSize, metrics: environment.metrics, deviceMetrics: environment.deviceMetrics, - intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomPanelFrame.height, right: 0.0), + intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: edgeEffectHeight, right: 0.0), safeInsets: UIEdgeInsets(top: 0.0, left: environment.safeInsets.left, bottom: 0.0, right: environment.safeInsets.right), additionalInsets: .zero, statusBarHeight: environment.statusBarHeight, @@ -1494,3 +1560,79 @@ private extension PeerColor { } } } + + +final class TopBottomCornersComponent: Component { + private let topCornerRadius: CGFloat + private let bottomCornerRadius: CGFloat + private let component: AnyComponent + + public init( + topCornerRadius: CGFloat, + bottomCornerRadius: CGFloat, + component: AnyComponent + ) { + self.topCornerRadius = topCornerRadius + self.bottomCornerRadius = bottomCornerRadius + self.component = component + } + + public static func == (lhs: TopBottomCornersComponent, rhs: TopBottomCornersComponent) -> Bool { + if lhs.topCornerRadius != rhs.topCornerRadius { + return false + } + if lhs.bottomCornerRadius != rhs.bottomCornerRadius { + return false + } + if lhs.component != rhs.component { + return false + } + return true + } + + public final class View: UIView { + private let containerView: UIView + private let hostView: ComponentHostView + + public override init(frame: CGRect) { + self.containerView = UIView() + self.hostView = ComponentHostView() + + super.init(frame: frame) + + self.clipsToBounds = true + self.containerView.clipsToBounds = true + + self.addSubview(self.containerView) + self.containerView.addSubview(self.hostView) + } + + public required init?(coder: NSCoder) { + preconditionFailure() + } + + func update(component: TopBottomCornersComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + + let size = self.hostView.update( + transition: transition, + component: component.component, + environment: {}, + containerSize: availableSize + ) + + transition.setCornerRadius(layer: self.containerView.layer, cornerRadius: component.topCornerRadius) + transition.setCornerRadius(layer: self.layer, cornerRadius: component.bottomCornerRadius) + transition.setFrame(view: self.containerView, frame: CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: availableSize.height + component.bottomCornerRadius))) + + return size + } + } + + public func makeView() -> View { + return View() + } + + public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} diff --git a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift index 21d99066ef..02d2bea010 100644 --- a/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift +++ b/submodules/TelegramUI/Components/VideoMessageCameraScreen/Sources/VideoMessageCameraScreen.swift @@ -590,6 +590,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { let flipButtonBackground = flipButtonBackground.update( component: GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: true, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) ), availableSize: CGSize(width: 40.0, height: 40.0), @@ -691,6 +692,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { let flashButtonBackground = flashButtonBackground.update( component: GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: true, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) ), availableSize: CGSize(width: 40.0, height: 40.0), @@ -764,6 +766,7 @@ private final class VideoMessageCameraScreenComponent: CombinedComponent { id: "background", component: AnyComponent(GlassBackgroundComponent( size: CGSize(width: 40.0, height: 40.0), + isDark: true, tintColor: .init(kind: .panel, color: environment.theme.chat.inputPanel.inputBackgroundColor.withMultipliedAlpha(0.7)) )) ),