From 58eb4ce2bb0b3b702a19eb858a4a81efd0107dfc Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Mon, 27 Nov 2023 17:05:20 +0400 Subject: [PATCH] Modernize color changed toast --- .../Themes/ThemeSettingsController.swift | 29 ++++++++--- .../Sources/PeerInfoCoverComponent.swift | 48 ++++++++----------- .../PeerInfoScreenDisclosureItem.swift | 27 +++++++---- .../Sources/PeerInfoScreen.swift | 26 +++++++++- .../Sources/PeerNameColorItem.swift | 29 ++++++++++- .../Sources/PeerNameColorScreen.swift | 13 ++++- .../Sources/UndoOverlayControllerNode.swift | 13 +++-- 7 files changed, 135 insertions(+), 50 deletions(-) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 764e2e6c2b..583fa88a8a 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -122,7 +122,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { case themes(PresentationTheme, PresentationStrings, [PresentationThemeReference], PresentationThemeReference, Bool, [String: [StickerPackItem]], [Int64: PresentationThemeAccentColor], [Int64: TelegramWallpaper]) case chatTheme(PresentationTheme, String) case wallpaper(PresentationTheme, String) - case nameColor(PresentationTheme, String, String, UIColor) + case nameColor(PresentationTheme, String, String, PeerNameColors.Colors?, PeerNameColors.Colors?) case autoNight(PresentationTheme, String, Bool, Bool) case autoNightTheme(PresentationTheme, String, String) case textSize(PresentationTheme, String, String) @@ -217,8 +217,8 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { } else { return false } - case let .nameColor(lhsTheme, lhsText, lhsName, lhsColor): - if case let .nameColor(rhsTheme, rhsText, rhsName, rhsColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsName == rhsName, lhsColor == rhsColor { + case let .nameColor(lhsTheme, lhsText, lhsName, lhsNameColor, lhsProfileColor): + if case let .nameColor(rhsTheme, rhsText, rhsName, rhsNameColor, rhsProfileColor) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsName == rhsName, lhsNameColor == rhsNameColor, lhsProfileColor == rhsProfileColor { return true } else { return false @@ -321,8 +321,18 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", sectionId: self.section, style: .blocks, action: { arguments.openWallpaperSettings() }) - case let .nameColor(_, text, name, color): - return ItemListDisclosureItem(presentationData: presentationData, title: text, label: name, labelStyle: .semitransparentBadge(color), sectionId: self.section, style: .blocks, action: { + case let .nameColor(_, text, _, nameColor, profileColor): + var colors: [PeerNameColors.Colors] = [] + if let nameColor { + colors.append(nameColor) + } + if let profileColor { + colors.append(profileColor) + } + + let colorImage = generateSettingsMenuPeerColorsLabelIcon(colors: colors) + + return ItemListDisclosureItem(presentationData: presentationData, title: text, label: "", labelStyle: .image(image: colorImage, size: colorImage.size), sectionId: self.section, style: .blocks, action: { arguments.openNameColorSettings() }) case let .autoNight(_, title, value, enabled): @@ -377,14 +387,17 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, entries.append(.themeListHeader(presentationData.theme, title)) let nameColor: PeerNameColor + let profileColor: PeerNameColor? var authorName = presentationData.strings.Appearance_PreviewReplyAuthor if let accountPeer { nameColor = accountPeer.nameColor ?? .blue if accountPeer._asPeer().hasCustomNameColor { authorName = accountPeer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) } + profileColor = accountPeer.profileColor } else { nameColor = .blue + profileColor = nil } entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (authorName, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText, nameColor: nameColor, backgroundEmojiId: accountPeer?.backgroundEmojiId), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)])) @@ -393,8 +406,10 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, entries.append(.chatTheme(presentationData.theme, strings.Settings_ChatThemes)) entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground)) - let colors = nameColors.get(nameColor) - entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer?.compactDisplayTitle ?? "", colors.main)) + let colors = nameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance) + let profileColors = profileColor.flatMap { nameColors.getProfile($0, dark: presentationData.theme.overallDarkAppearance, subject: .palette) } + //TODO:localize + entries.append(.nameColor(presentationData.theme, "Your Color", accountPeer?.compactDisplayTitle ?? "", colors, profileColors)) entries.append(.autoNight(presentationData.theme, strings.Appearance_NightTheme, presentationThemeSettings.automaticThemeSwitchSetting.force, !presentationData.autoNightModeTriggered || presentationThemeSettings.automaticThemeSwitchSetting.force)) let autoNightMode: String diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift index c62395a331..21933d7ab6 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift @@ -149,7 +149,9 @@ public final class PeerInfoCoverComponent: Component { self.avatarBackgroundGradientLayer.type = .radial self.avatarBackgroundPatternContentsLayer = SimpleGradientLayer() - self.avatarBackgroundPatternContentsLayer.compositingFilter = "overlayBlendMode" + self.avatarBackgroundPatternContentsLayer.startPoint = CGPoint(x: 0.5, y: 0.5) + self.avatarBackgroundPatternContentsLayer.endPoint = CGPoint(x: 1.0, y: 1.0) + self.avatarBackgroundPatternContentsLayer.type = .radial self.avatarBackgroundPatternMaskLayer = SimpleLayer() self.backgroundPatternContainer = UIView() @@ -269,33 +271,15 @@ public final class PeerInfoCoverComponent: Component { let backgroundColor: UIColor let secondaryBackgroundColor: UIColor - let patternBackgroundColor: UIColor - let secondaryPatternBackgroundColor: UIColor - let useClearPatternColor: Bool - if let peer = component.peer, let colors = peer._asPeer().profileColor.flatMap({ component.context.peerNameColors.getProfile($0, dark: component.isDark) }) { backgroundColor = colors.main secondaryBackgroundColor = colors.secondary ?? colors.main - - patternBackgroundColor = backgroundColor - secondaryPatternBackgroundColor = secondaryBackgroundColor - - useClearPatternColor = false } else { backgroundColor = .clear secondaryBackgroundColor = .clear - - patternBackgroundColor = component.isDark ? UIColor(white: 1.0, alpha: 0.2) : UIColor(white: 0.0, alpha: 0.2) - secondaryPatternBackgroundColor = patternBackgroundColor - - useClearPatternColor = true } - let _ = useClearPatternColor - let _ = patternBackgroundColor - let _ = secondaryPatternBackgroundColor - self.backgroundView.backgroundColor = secondaryBackgroundColor self.backgroundGradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0) @@ -325,17 +309,27 @@ public final class PeerInfoCoverComponent: Component { //transition.setFrame(view: self.avatarBackgroundPatternView, frame: CGSize(width: 200.0, height: 200.0).centered(around: CGPoint())) - let avatarPatternFrame = CGSize(width: 380.0, height: 380.0).centered(around: component.avatarCenter) + let avatarPatternFrame = CGSize(width: 380.0, height: floor(component.defaultHeight * 1.0)).centered(around: component.avatarCenter) transition.setFrame(layer: self.avatarBackgroundPatternContentsLayer, frame: avatarPatternFrame) - self.avatarBackgroundPatternContentsLayer.type = .radial - self.avatarBackgroundPatternContentsLayer.startPoint = CGPoint(x: 0.5, y: 0.5) - self.avatarBackgroundPatternContentsLayer.endPoint = CGPoint(x: 1.0, y: 1.0) - self.avatarBackgroundPatternContentsLayer.colors = [ - UIColor(white: 0.0, alpha: 0.6).cgColor, - UIColor(white: 0.0, alpha: 0.0).cgColor - ] + if component.peer?.profileColor != nil { + self.avatarBackgroundPatternContentsLayer.compositingFilter = "overlayBlendMode" + self.avatarBackgroundPatternContentsLayer.colors = [ + UIColor(white: 0.0, alpha: 0.6).cgColor, + UIColor(white: 0.0, alpha: 0.0).cgColor + ] + + } else { + self.avatarBackgroundPatternContentsLayer.compositingFilter = nil + let baseWhite: CGFloat = component.isDark ? 0.5 : 0.3 + + self.avatarBackgroundPatternContentsLayer.colors = [ + UIColor(white: baseWhite, alpha: 0.6).cgColor, + UIColor(white: baseWhite, alpha: 0.0).cgColor + ] + } + self.avatarBackgroundGradientLayer.isHidden = component.peer?.profileColor == nil transition.setFrame(layer: self.avatarBackgroundGradientLayer, frame: CGSize(width: 300.0, height: 300.0).centered(around: component.avatarCenter)) transition.setAlpha(layer: self.avatarBackgroundGradientLayer, alpha: 1.0 - component.avatarTransitionFraction) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift index 524dcf9466..dcf1946b95 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenDisclosureItem.swift @@ -10,22 +10,23 @@ final class PeerInfoScreenDisclosureItem: PeerInfoScreenItem { case badge(String, UIColor) case semitransparentBadge(String, UIColor) case titleBadge(String, UIColor) + case image(UIImage, CGSize) var text: String { switch self { - case .none: - return "" + case .none, .image: + return "" case let .text(text), let .badge(text, _), let .semitransparentBadge(text, _), let .titleBadge(text, _): - return text + return text } } var badgeColor: UIColor? { switch self { - case .none, .text: - return nil - case let .badge(_, color), let .semitransparentBadge(_, color), let .titleBadge(_, color): - return color + case .none, .text, .image: + return nil + case let .badge(_, color), let .semitransparentBadge(_, color), let .titleBadge(_, color): + return color } } } @@ -209,7 +210,13 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode { } var badgeDiameter: CGFloat = 20.0 - if case let .semitransparentBadge(text, badgeColor) = item.label, !text.isEmpty { + if case let .image(image, imageSize) = item.label { + self.labelBadgeNode.image = image + badgeDiameter = imageSize.height + if self.labelBadgeNode.supernode == nil { + self.insertSubnode(self.labelBadgeNode, belowSubnode: self.labelNode) + } + } else if case let .semitransparentBadge(text, badgeColor) = item.label, !text.isEmpty { badgeDiameter = 24.0 if previousItem?.label.badgeColor != badgeColor { self.labelBadgeNode.image = generateStretchableFilledCircleImage(diameter: badgeDiameter, color: badgeColor.withAlphaComponent(0.1)) @@ -277,7 +284,9 @@ private final class PeerInfoScreenDisclosureItemNode: PeerInfoScreenItemNode { } let labelBadgeNodeFrame: CGRect - if case .titleBadge = item.label { + if case let .image(_, imageSize) = item.label { + labelBadgeNodeFrame = CGRect(origin: CGPoint(x: width - rightInset - imageSize.width, y: floorToScreenPixels(textFrame.midY - imageSize.height / 2.0)), size:imageSize) + } else if case .titleBadge = item.label { labelBadgeNodeFrame = labelFrame.insetBy(dx: -4.0, dy: -2.0 + UIScreenPixel) } else if let additionalLabelNode = self.additionalLabelNode { labelBadgeNodeFrame = additionalLabelNode.frame.insetBy(dx: -4.0, dy: -2.0 + UIScreenPixel) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index b6f69dc68b..6816be219d 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -984,6 +984,7 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat let ItemAddAccount = 5 let ItemAddAccountHelp = 6 let ItemLogout = 7 + let ItemPeerColor = 8 items[.help]!.append(PeerInfoScreenCommentItem(id: ItemNameHelp, text: presentationData.strings.EditProfile_NameAndPhotoOrVideoHelp)) @@ -1009,6 +1010,22 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat interaction.openSettings(.username) })) + if let peer = data.peer as? TelegramUser { + var colors: [PeerNameColors.Colors] = [] + if let nameColor = peer.nameColor.flatMap({ context.peerNameColors.get($0, dark: presentationData.theme.overallDarkAppearance) }) { + colors.append(nameColor) + } + if let profileColor = peer.profileColor.flatMap({ context.peerNameColors.getProfile($0, dark: presentationData.theme.overallDarkAppearance, subject: .palette) }) { + colors.append(profileColor) + } + let colorImage = generateSettingsMenuPeerColorsLabelIcon(colors: colors) + + //TODO:localize + items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), text: "Your Color", icon: nil, action: { + interaction.editingOpenNameColorSetup() + })) + } + items[.account]!.append(PeerInfoScreenActionItem(id: ItemAddAccount, text: presentationData.strings.Settings_AddAnotherAccount, alignment: .center, action: { interaction.openSettings(.addAccount) })) @@ -7153,8 +7170,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } private func editingOpenNameColorSetup() { - let controller = PeerNameColorScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, subject: .channel(self.peerId)) - self.controller?.push(controller) + if self.peerId == self.context.account.peerId { + let controller = PeerNameColorScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, subject: .account) + self.controller?.push(controller) + } else { + let controller = PeerNameColorScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, subject: .channel(self.peerId)) + self.controller?.push(controller) + } } private func editingOpenInviteLinksSetup() { diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift index 7fb25f90e5..0fb6b12f6f 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift @@ -127,7 +127,7 @@ private func generateRingImage(nameColor: PeerNameColors.Colors) -> UIImage? { }) } -func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, isDark: Bool, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? { +public func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, isDark: Bool, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? { return generateImage(bounds, rotatedContext: { contextSize, context in let bounds = CGRect(origin: CGPoint(), size: contextSize) context.clear(bounds) @@ -179,6 +179,33 @@ func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, isDark: Bool, }) } +public func generateSettingsMenuPeerColorsLabelIcon(colors: [PeerNameColors.Colors]) -> UIImage { + let iconWidth: CGFloat = 24.0 + let iconSpacing: CGFloat = 18.0 + let borderWidth: CGFloat = 2.0 + + return generateImage(CGSize(width: CGFloat(max(0, colors.count - 1)) * iconSpacing + CGFloat(colors.count == 0 ? 0 : 1) * iconWidth, height: 24.0), rotatedContext: { size, context in + context.clear(CGRect(origin: CGPoint(), size: size)) + + for i in 0 ..< colors.count { + let iconFrame = CGRect(origin: CGPoint(x: CGFloat(i) * iconSpacing, y: 0.0), size: CGSize(width: iconWidth, height: iconWidth)) + context.setBlendMode(.copy) + context.setFillColor(UIColor.clear.cgColor) + context.fillEllipse(in: iconFrame.insetBy(dx: -borderWidth, dy: -borderWidth)) + context.setBlendMode(.normal) + + if let image = generatePeerNameColorImage(nameColor: colors[i], isDark: false, bounds: iconFrame.size, size: iconFrame.size)?.cgImage { + context.saveGState() + context.translateBy(x: iconFrame.midX, y: iconFrame.midY) + context.scaleBy(x: 1.0, y: -1.0) + context.translateBy(x: -iconFrame.midX, y: -iconFrame.midY) + context.draw(image, in: iconFrame) + context.restoreGState() + } + } + })! +} + private final class PeerNameColorIconItemNode : ListViewItemNode { private let containerNode: ContextControllerSourceNode private let fillNode: ASImageNode diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift index 7d08793545..580201d780 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift @@ -835,7 +835,18 @@ public func PeerNameColorScreen( if let navigationController = controller?.navigationController as? NavigationController { Queue.mainQueue().after(0.25) { if let lastController = navigationController.viewControllers.last as? ViewController { - let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, isDark: presentationData.theme.overallDarkAppearance, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_YourColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }) + var colorList: [PeerNameColors.Colors] = [] + if let nameColor { + colorList.append(context.peerNameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance)) + } + if let profileColor { + colorList.append(context.peerNameColors.getProfile(profileColor, dark: presentationData.theme.overallDarkAppearance, subject: .palette)) + } + + let colorImage = generateSettingsMenuPeerColorsLabelIcon(colors: colorList) + + //TODO:localize + let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: colorImage, title: nil, text: "Your color has been updated.", round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }) lastController.present(tipController, in: .window(.root)) } } diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index 84a945971f..17a66b8128 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -1071,7 +1071,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.iconNode?.contentMode = .scaleAspectFill self.iconNode?.image = image self.iconNode?.cornerRadius = round ? 16.0 : 4.0 - self.iconImageSize = CGSize(width: 32.0, height: 32.0) + self.iconImageSize = image.size.aspectFitted(CGSize(width: 128.0, height: 32.0)) self.iconCheckNode = nil self.animationNode = nil self.animatedStickerNode = nil @@ -1381,7 +1381,9 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { } var leftInset: CGFloat = 50.0 - if let iconSize = preferredSize { + if let iconImageSize = self.iconImageSize { + leftInset = 9.0 + iconImageSize.width + 9.0 + } else if let iconSize = preferredSize { if iconSize.width > leftInset { leftInset = iconSize.width - 8.0 } @@ -1468,7 +1470,12 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { iconSize = CGSize() } - let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize) + let iconFrame: CGRect + if self.iconImageSize != nil { + iconFrame = CGRect(origin: CGPoint(x: 9.0, y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize) + } else { + iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0) + verticalOffset), size: iconSize) + } transition.updateFrame(node: iconNode, frame: iconFrame) if let iconCheckNode = self.iconCheckNode {