diff --git a/submodules/AccountContext/Sources/PeerNameColors.swift b/submodules/AccountContext/Sources/PeerNameColors.swift index 1966a168ea..63c13124ff 100644 --- a/submodules/AccountContext/Sources/PeerNameColors.swift +++ b/submodules/AccountContext/Sources/PeerNameColors.swift @@ -323,3 +323,41 @@ public class PeerNameColors: Equatable { return true } } + +public extension PeerCollectibleColor { + func peerNameColors(dark: Bool) -> PeerNameColors.Colors { + return PeerNameColors.Colors( + main: self.mainColor(dark: dark), + secondary: self.secondaryColor(dark: dark), + tertiary: self.tertiaryColor(dark: dark) + ) + } + + func mainColor(dark: Bool) -> UIColor { + if dark, let darkAccentColor = self.darkAccentColor { + return UIColor(rgb: darkAccentColor) + } else { + return UIColor(rgb: self.accentColor) + } + } + + func secondaryColor(dark: Bool) -> UIColor? { + if dark, let darkColors = self.darkColors, darkColors.count > 0 { + return UIColor(rgb: darkColors[0]) + } else if self.colors.count > 0 { + return UIColor(rgb: self.colors[0]) + } else { + return nil + } + } + + func tertiaryColor(dark: Bool) -> UIColor? { + if dark, let darkColors = self.darkColors, darkColors.count > 1 { + return UIColor(rgb: darkColors[1]) + } else if self.colors.count > 1 { + return UIColor(rgb: self.colors[1]) + } else { + return nil + } + } +} diff --git a/submodules/AvatarNode/Sources/AvatarNode.swift b/submodules/AvatarNode/Sources/AvatarNode.swift index 371a11518a..7d329e142d 100644 --- a/submodules/AvatarNode/Sources/AvatarNode.swift +++ b/submodules/AvatarNode/Sources/AvatarNode.swift @@ -72,7 +72,7 @@ private class AvatarNodeParameters: NSObject { } } -public func calculateAvatarColors(context: AccountContext?, explicitColorIndex: Int?, peerId: EnginePeer.Id?, nameColor: PeerNameColor?, icon: AvatarNodeIcon, theme: PresentationTheme?) -> [UIColor] { +public func calculateAvatarColors(context: AccountContext?, explicitColorIndex: Int?, peerId: EnginePeer.Id?, nameColor: PeerColor?, icon: AvatarNodeIcon, theme: PresentationTheme?) -> [UIColor] { let colorIndex: Int if let explicitColorIndex = explicitColorIndex { colorIndex = explicitColorIndex @@ -138,9 +138,8 @@ public func calculateAvatarColors(context: AccountContext?, explicitColorIndex: } } else { if let nameColor { - if let context, nameColor.rawValue > 13 { - let nameColors = context.peerNameColors.get(nameColor) - let hue = nameColors.main.hsb.h + func colorIndexFromColor(color: UIColor) -> Int { + let hue = color.hsb.h var index: Int = 0 if hue > 0.9 || hue < 0.02 { index = 0 @@ -157,10 +156,24 @@ public func calculateAvatarColors(context: AccountContext?, explicitColorIndex: } else { index = 6 } - colors = AvatarNode.gradientColors[index % AvatarNode.gradientColors.count] - } else { - colors = AvatarNode.gradientColors[Int(nameColor.rawValue) % AvatarNode.gradientColors.count] + return index } + + switch nameColor { + case let .preset(nameColor): + if let context, nameColor.rawValue > 13 { + let nameColors = context.peerNameColors.get(nameColor) + let index = colorIndexFromColor(color: nameColors.main) + colors = AvatarNode.gradientColors[index % AvatarNode.gradientColors.count] + } else { + colors = AvatarNode.gradientColors[Int(nameColor.rawValue) % AvatarNode.gradientColors.count] + } + case let .collectible(peerCollectibleColor): + let color = UIColor(rgb: peerCollectibleColor.accentColor) + let index = colorIndexFromColor(color: color) + colors = AvatarNode.gradientColors[index % AvatarNode.gradientColors.count] + } + } else { colors = AvatarNode.gradientColors[colorIndex % AvatarNode.gradientColors.count] } @@ -175,7 +188,7 @@ public enum AvatarNodeExplicitIcon { private enum AvatarNodeState: Equatable { case empty - case peerAvatar(EnginePeer.Id, PeerNameColor?, [String], TelegramMediaImageRepresentation?, AvatarNodeClipStyle, CGRect?) + case peerAvatar(EnginePeer.Id, PeerColor?, [String], TelegramMediaImageRepresentation?, AvatarNodeClipStyle, CGRect?) case custom(letter: [String], explicitColorIndex: Int?, explicitIcon: AvatarNodeExplicitIcon?) } diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index 7d1a9c8009..17d3374616 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -398,7 +398,7 @@ public func peerAvatarImage(postbox: Postbox, network: Network, peerReference: P } } -public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool = true, font: UIFont, letters: [String], peerId: EnginePeer.Id, nameColor: PeerNameColor?) { +public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool = true, font: UIFont, letters: [String], peerId: EnginePeer.Id, nameColor: PeerColor?) { if round { context.beginPath() context.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: @@ -419,7 +419,13 @@ public func drawPeerAvatarLetters(context: CGContext, size: CGSize, round: Bool } else { var index = colorIndex % AvatarNode.gradientColors.count if let nameColor { - index = Int(nameColor.rawValue) % AvatarNode.gradientColors.count + switch nameColor { + case let .preset(peerNameColor): + index = Int(peerNameColor.rawValue) % AvatarNode.gradientColors.count + case let .collectible(peerCollectibleColor): + let _ = peerCollectibleColor + break + } } colorsArray = AvatarNode.gradientColors[index].map(\.cgColor) as NSArray } diff --git a/submodules/GalleryUI/Sources/GalleryController.swift b/submodules/GalleryUI/Sources/GalleryController.swift index 2b09ceb02a..d8af3d8fa9 100644 --- a/submodules/GalleryUI/Sources/GalleryController.swift +++ b/submodules/GalleryUI/Sources/GalleryController.swift @@ -150,7 +150,13 @@ public func galleryCaptionStringWithAppliedEntities(context: AccountContext, tex var baseQuoteSecondaryTintColor: UIColor? var baseQuoteTertiaryTintColor: UIColor? if let nameColor = message?.author?.nameColor { - let resolvedColor = context.peerNameColors.get(nameColor) + let resolvedColor: PeerNameColors.Colors + switch nameColor { + case let .preset(nameColor): + resolvedColor = context.peerNameColors.get(nameColor) + case let .collectible(collectibleColor): + resolvedColor = collectibleColor.peerNameColors(dark: false) + } if resolvedColor.secondary != nil { baseQuoteSecondaryTintColor = .clear } diff --git a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift index d491b0a930..6596535389 100644 --- a/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift +++ b/submodules/SettingsUI/Sources/BubbleSettings/BubbleSettingsController.swift @@ -163,8 +163,8 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, ASScrollViewDel let otherPeerId = self.context.account.peerId var peers = SimpleDictionary() var messages = SimpleDictionary() - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) - peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/ForwardPrivacyChatPreviewItem.swift b/submodules/SettingsUI/Sources/Privacy and Security/ForwardPrivacyChatPreviewItem.swift index 31af98a5c3..4475f0c0af 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/ForwardPrivacyChatPreviewItem.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/ForwardPrivacyChatPreviewItem.swift @@ -145,7 +145,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode { var peers = SimpleDictionary() let messages = SimpleDictionary() - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: item.peerName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: item.peerName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil, flags: []) diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index 86d484ae40..44ab48af9e 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -441,8 +441,8 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, ASScrollView let otherPeerId = self.context.account.peerId var peers = SimpleDictionary() var messages = SimpleDictionary() - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) - peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) diff --git a/submodules/SettingsUI/Sources/ThemePickerController.swift b/submodules/SettingsUI/Sources/ThemePickerController.swift index a045020c38..527ffc8475 100644 --- a/submodules/SettingsUI/Sources/ThemePickerController.swift +++ b/submodules/SettingsUI/Sources/ThemePickerController.swift @@ -291,7 +291,7 @@ private func themePickerControllerEntries(presentationData: PresentationData, pr entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, nightMode, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers)) entries.append(.customHeader(presentationData.theme, presentationData.strings.Themes_BuildOwn.uppercased())) - entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText, nameColor: .blue, backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)])) + entries.append(.chatPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (presentationData.strings.Appearance_PreviewReplyAuthor, presentationData.strings.Appearance_PreviewReplyText), text: presentationData.strings.Appearance_PreviewIncomingText, nameColor: .preset(.blue), backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText, nameColor: .preset(.blue), backgroundEmojiId: nil)])) let generalThemes: [PresentationThemeReference] = availableThemes.filter { reference in if case let .cloud(theme) = reference { diff --git a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift index 0b009def43..530f7e3844 100644 --- a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift +++ b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift @@ -285,7 +285,7 @@ private func editThemeControllerEntries(presentationData: PresentationData, stat entries.append(.slugInfo(presentationData.theme, infoText)) entries.append(.chatPreviewHeader(presentationData.theme, presentationData.strings.EditTheme_Preview.uppercased())) - entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText, nameColor: .blue, backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText, nameColor: .blue, backgroundEmojiId: nil)])) + entries.append(.chatPreview(presentationData.theme, previewTheme, previewTheme.chat.defaultWallpaper, presentationData.chatFontSize, presentationData.chatBubbleCorners, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, [ChatPreviewMessageItem(outgoing: false, reply: (previewIncomingReplyName, previewIncomingReplyText), text: previewIncomingText, nameColor: .preset(.blue), backgroundEmojiId: nil), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText, nameColor: .preset(.blue), backgroundEmojiId: nil)])) entries.append(.changeColors(presentationData.theme, presentationData.strings.EditTheme_ChangeColors)) if hasSettings { diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index 12bfd759ad..9232eaf461 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -596,8 +596,8 @@ final class ThemePreviewControllerNode: ASDisplayNode, ASScrollViewDelegate { let otherPeerId = self.context.account.peerId var peers = SimpleDictionary() var messages = SimpleDictionary() - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) - peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) var sampleMessages: [Message] = [] diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift index e464e8e82d..0359d23db1 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift @@ -37,7 +37,7 @@ struct ChatPreviewMessageItem: Equatable { let outgoing: Bool let reply: (String, String)? let text: String - let nameColor: PeerNameColor + let nameColor: PeerColor let backgroundEmojiId: Int64? } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 7dfc024c33..2ce19ffb97 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -366,27 +366,33 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased() entries.append(.themeListHeader(presentationData.theme, title)) - let nameColor: PeerNameColor + let nameColor: PeerColor let profileColor: PeerNameColor? var authorName = presentationData.strings.Appearance_PreviewReplyAuthor if let accountPeer { - nameColor = accountPeer.nameColor ?? .blue + nameColor = accountPeer.nameColor ?? .preset(.blue) if accountPeer._asPeer().hasCustomNameColor { authorName = accountPeer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) } profileColor = accountPeer.profileColor } else { - nameColor = .blue + nameColor = .preset(.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)])) + 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: .preset(.blue), backgroundEmojiId: nil)])) entries.append(.themes(presentationData.theme, presentationData.strings, chatThemes, themeReference, presentationThemeSettings.automaticThemeSwitchSetting.force || presentationData.autoNightModeTriggered, animatedEmojiStickers, presentationThemeSettings.themeSpecificAccentColors, presentationThemeSettings.themeSpecificChatWallpapers)) entries.append(.chatTheme(presentationData.theme, strings.Settings_ChatThemes)) entries.append(.wallpaper(presentationData.theme, strings.Settings_ChatBackground)) - let colors = nameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance) + let colors: PeerNameColors.Colors + switch nameColor { + case let .preset(nameColor): + colors = nameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + colors = collectibleColor.peerNameColors(dark: presentationData.theme.overallDarkAppearance) + } let profileColors = profileColor.flatMap { nameColors.getProfile($0, dark: presentationData.theme.overallDarkAppearance, subject: .palette) } entries.append(.nameColor(presentationData.theme, presentationData.strings.Settings_YourColor, accountPeer?.compactDisplayTitle ?? "", colors, profileColors)) diff --git a/submodules/TelegramCore/FlatSerialization/Models/PeerCollectibleColor.fbs b/submodules/TelegramCore/FlatSerialization/Models/PeerCollectibleColor.fbs new file mode 100644 index 0000000000..aeeb3edfcb --- /dev/null +++ b/submodules/TelegramCore/FlatSerialization/Models/PeerCollectibleColor.fbs @@ -0,0 +1,13 @@ +namespace TelegramCore; + +table PeerCollectibleColor { + collectibleId:long (id: 0); + giftEmojiFileId:long (id: 1); + backgroundEmojiId:long (id: 2); + accentColor:uint (id: 3); + colors:[uint] (id: 4); + darkAccentColor:uint (id: 5); + darkColors:[uint] (id: 6); +} + +root_type PeerCollectibleColor; diff --git a/submodules/TelegramCore/FlatSerialization/Models/TelegramUser.fbs b/submodules/TelegramCore/FlatSerialization/Models/TelegramUser.fbs index 6e8431878e..4f718a10b7 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/TelegramUser.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/TelegramUser.fbs @@ -5,6 +5,7 @@ include "PeerAccessRestrictionInfo.fbs"; include "PeerEmojiStatus.fbs"; include "TelegramPeerUsername.fbs"; include "PeerNameColor.fbs"; +include "PeerCollectibleColor.fbs"; include "Optional.fbs"; include "StarsAmount.fbs"; @@ -35,6 +36,7 @@ table TelegramUser { profileBackgroundEmojiId:int64 (id: 16); subscriberCount:int32 (id: 17); verificationIconFileId:int64 (id: 18); + collectibleColor:PeerCollectibleColor (id: 19); } root_type TelegramUser; diff --git a/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift b/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift index 5f3c71b847..d8e49deb6e 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ApiGroupOrChannel.swift @@ -175,14 +175,8 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? { case let .peerColor(_, color, backgroundEmojiIdValue): nameColorIndex = color backgroundEmojiId = backgroundEmojiIdValue - case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiId, accentColor, colors, darkAccentColor, darkColors): - let _ = collectibleId - let _ = giftEmojiId - let _ = backgroundEmojiId - let _ = accentColor - let _ = colors - let _ = darkAccentColor - let _ = darkColors + case .peerColorCollectible: + break case .inputPeerColorCollectible: break } @@ -266,14 +260,8 @@ func mergeGroupOrChannel(lhs: Peer?, rhs: Api.Chat) -> Peer? { case let .peerColor(_, color, backgroundEmojiIdValue): nameColorIndex = color backgroundEmojiId = backgroundEmojiIdValue - case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiId, accentColor, colors, darkAccentColor, darkColors): - let _ = collectibleId - let _ = giftEmojiId - let _ = backgroundEmojiId - let _ = accentColor - let _ = colors - let _ = darkAccentColor - let _ = darkColors + case .peerColorCollectible: + break case .inputPeerColorCollectible: break } diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramUser.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramUser.swift index 6ce71f46c1..c8e7d1d63f 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramUser.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramUser.swift @@ -126,21 +126,26 @@ extension TelegramUser { let restrictionInfo: PeerAccessRestrictionInfo? = restrictionReason.flatMap(PeerAccessRestrictionInfo.init(apiReasons:)) - var nameColorIndex: Int32? + var nameColor: PeerColor? var backgroundEmojiId: Int64? if let color = color { switch color { case let .peerColor(_, color, backgroundEmojiIdValue): - nameColorIndex = color + if let color { + nameColor = .preset(PeerNameColor(rawValue: color)) + } + backgroundEmojiId = backgroundEmojiIdValue + case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiIdValue, accentColor, colors, darkAccentColor, darkColors): + nameColor = .collectible(PeerCollectibleColor( + collectibleId: collectibleId, + giftEmojiFileId: giftEmojiId, + backgroundEmojiId: backgroundEmojiIdValue, + accentColor: UInt32(bitPattern: accentColor), + colors: colors.map { UInt32(bitPattern: $0) }, + darkAccentColor: darkAccentColor.flatMap { UInt32(bitPattern: $0) }, + darkColors: darkColors.flatMap { $0.map { UInt32(bitPattern: $0) } } + )) backgroundEmojiId = backgroundEmojiIdValue - case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiId, accentColor, colors, darkAccentColor, darkColors): - let _ = collectibleId - let _ = giftEmojiId - let _ = backgroundEmojiId - let _ = accentColor - let _ = colors - let _ = darkAccentColor - let _ = darkColors case .inputPeerColorCollectible: break } @@ -158,7 +163,7 @@ extension TelegramUser { } } - self.init(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id)), accessHash: accessHashValue, firstName: firstName, lastName: lastName, username: username, phone: phone, photo: representations, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags, emojiStatus: emojiStatus.flatMap(PeerEmojiStatus.init(apiStatus:)), usernames: usernames?.map(TelegramPeerUsername.init(apiUsername:)) ?? [], storiesHidden: storiesHidden, nameColor: nameColorIndex.flatMap { PeerNameColor(rawValue: $0) }, backgroundEmojiId: backgroundEmojiId, profileColor: profileColorIndex.flatMap { PeerNameColor(rawValue: $0) }, profileBackgroundEmojiId: profileBackgroundEmojiId, subscriberCount: subscriberCount, verificationIconFileId: verificationIconFileId) + self.init(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id)), accessHash: accessHashValue, firstName: firstName, lastName: lastName, username: username, phone: phone, photo: representations, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags, emojiStatus: emojiStatus.flatMap(PeerEmojiStatus.init(apiStatus:)), usernames: usernames?.map(TelegramPeerUsername.init(apiUsername:)) ?? [], storiesHidden: storiesHidden, nameColor: nameColor, backgroundEmojiId: backgroundEmojiId, profileColor: profileColorIndex.flatMap { PeerNameColor(rawValue: $0) }, profileBackgroundEmojiId: profileBackgroundEmojiId, subscriberCount: subscriberCount, verificationIconFileId: verificationIconFileId) case let .userEmpty(id): self.init(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id)), accessHash: nil, firstName: nil, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) } @@ -166,7 +171,7 @@ extension TelegramUser { static func merge(_ lhs: TelegramUser?, rhs: Api.User) -> TelegramUser? { switch rhs { - case let .user(flags, _, _, rhsAccessHash, _, _, _, _, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, _, _, nameColor, profileColor, subscriberCount, _, _): + case let .user(flags, _, _, rhsAccessHash, _, _, _, _, photo, _, _, restrictionReason, botInlinePlaceholder, _, emojiStatus, _, _, color, profileColor, subscriberCount, _, _): let isMin = (flags & (1 << 20)) != 0 if !isMin { return TelegramUser(user: rhs) @@ -247,21 +252,26 @@ extension TelegramUser { accessHash = lhs.accessHash ?? rhsAccessHashValue } - var nameColorIndex: Int32? + var nameColor: PeerColor? var backgroundEmojiId: Int64? - if let nameColor = nameColor { - switch nameColor { + if let color { + switch color { case let .peerColor(_, color, backgroundEmojiIdValue): - nameColorIndex = color + if let color { + nameColor = .preset(PeerNameColor(rawValue: color)) + } + backgroundEmojiId = backgroundEmojiIdValue + case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiIdValue, accentColor, colors, darkAccentColor, darkColors): + nameColor = .collectible(PeerCollectibleColor( + collectibleId: collectibleId, + giftEmojiFileId: giftEmojiId, + backgroundEmojiId: backgroundEmojiIdValue, + accentColor: UInt32(bitPattern: accentColor), + colors: colors.map { UInt32(bitPattern: $0) }, + darkAccentColor: darkAccentColor.flatMap { UInt32(bitPattern: $0) }, + darkColors: darkColors.flatMap { $0.map { UInt32(bitPattern: $0) } } + )) backgroundEmojiId = backgroundEmojiIdValue - case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiId, accentColor, colors, darkAccentColor, darkColors): - let _ = collectibleId - let _ = giftEmojiId - let _ = backgroundEmojiId - let _ = accentColor - let _ = colors - let _ = darkAccentColor - let _ = darkColors case .inputPeerColorCollectible: break } @@ -279,7 +289,7 @@ extension TelegramUser { } } - return TelegramUser(id: lhs.id, accessHash: accessHash, firstName: lhs.firstName, lastName: lhs.lastName, username: lhs.username, phone: lhs.phone, photo: telegramPhoto, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags, emojiStatus: emojiStatus.flatMap(PeerEmojiStatus.init(apiStatus:)), usernames: lhs.usernames, storiesHidden: lhs.storiesHidden, nameColor: nameColorIndex.flatMap { PeerNameColor(rawValue: $0) }, backgroundEmojiId: backgroundEmojiId, profileColor: profileColorIndex.flatMap { PeerNameColor(rawValue: $0) }, profileBackgroundEmojiId: profileBackgroundEmojiId, subscriberCount: subscriberCount, verificationIconFileId: lhs.verificationIconFileId) + return TelegramUser(id: lhs.id, accessHash: accessHash, firstName: lhs.firstName, lastName: lhs.lastName, username: lhs.username, phone: lhs.phone, photo: telegramPhoto, botInfo: botInfo, restrictionInfo: restrictionInfo, flags: userFlags, emojiStatus: emojiStatus.flatMap(PeerEmojiStatus.init(apiStatus:)), usernames: lhs.usernames, storiesHidden: lhs.storiesHidden, nameColor: nameColor, backgroundEmojiId: backgroundEmojiId, profileColor: profileColorIndex.flatMap { PeerNameColor(rawValue: $0) }, profileBackgroundEmojiId: profileBackgroundEmojiId, subscriberCount: subscriberCount, verificationIconFileId: lhs.verificationIconFileId) } else { return TelegramUser(user: rhs) } diff --git a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift index f3400dbef0..351c87737b 100644 --- a/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift +++ b/submodules/TelegramCore/Sources/State/ManagedRecentStickers.swift @@ -361,7 +361,8 @@ func managedUniqueStarGifts(accountPeerId: PeerId, postbox: Postbox, network: Ne valueAmount: nil, valueCurrency: nil, flags: [], - themePeerId: nil + themePeerId: nil, + peerColor: nil ) if let entry = CodableEntry(RecentStarGiftItem(gift)) { items.append(OrderedItemListEntry(id: RecentStarGiftItemId(id).rawValue, contents: entry)) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift index 71a525f59b..2eba659bc4 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift @@ -275,6 +275,124 @@ public enum PeerNameColor: Hashable { } } +public struct PeerCollectibleColor: Equatable, Codable { + enum CodingKeys: String, CodingKey { + case collectibleId + case giftEmojiFileId + case backgroundEmojiId + case accentColor + case colors + case darkAccentColor + case darkColors + } + + public let collectibleId: Int64 + public let giftEmojiFileId: Int64 + public let backgroundEmojiId: Int64 + public let accentColor: UInt32 + public let colors: [UInt32] + public let darkAccentColor: UInt32? + public let darkColors: [UInt32]? + + public init( + collectibleId: Int64, + giftEmojiFileId: Int64, + backgroundEmojiId: Int64, + accentColor: UInt32, + colors: [UInt32], + darkAccentColor: UInt32?, + darkColors: [UInt32]? + ) { + self.collectibleId = collectibleId + self.giftEmojiFileId = giftEmojiFileId + self.backgroundEmojiId = backgroundEmojiId + self.accentColor = accentColor + self.colors = colors + self.darkAccentColor = darkAccentColor + self.darkColors = darkColors + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.collectibleId = try container.decode(Int64.self, forKey: .collectibleId) + self.giftEmojiFileId = try container.decode(Int64.self, forKey: .giftEmojiFileId) + self.backgroundEmojiId = try container.decode(Int64.self, forKey: .backgroundEmojiId) + self.accentColor = UInt32(bitPattern: try container.decode(Int32.self, forKey: .accentColor)) + self.colors = try container.decode([Int32].self, forKey: .colors).map { UInt32(bitPattern: $0) } + self.darkAccentColor = try container.decodeIfPresent(Int32.self, forKey: .darkAccentColor).flatMap { UInt32(bitPattern: $0) } + self.darkColors = try container.decodeIfPresent([Int32].self, forKey: .darkColors).flatMap { $0.map { UInt32(bitPattern: $0) } } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.collectibleId, forKey: .collectibleId) + try container.encode(self.giftEmojiFileId, forKey: .giftEmojiFileId) + try container.encode(self.backgroundEmojiId, forKey: .backgroundEmojiId) + try container.encode(Int32(bitPattern: self.accentColor), forKey: .accentColor) + try container.encode(self.colors.map { Int32(bitPattern: $0) }, forKey: .colors) + try container.encodeIfPresent(self.darkAccentColor.flatMap { Int32(bitPattern: $0)}, forKey: .darkAccentColor) + try container.encodeIfPresent(self.darkColors.flatMap { $0.map { Int32(bitPattern: $0) } }, forKey: .darkColors) + } + + public init(flatBuffersObject: TelegramCore_PeerCollectibleColor) throws { + self.collectibleId = flatBuffersObject.collectibleId + self.giftEmojiFileId = flatBuffersObject.giftEmojiFileId + self.backgroundEmojiId = flatBuffersObject.backgroundEmojiId + self.accentColor = flatBuffersObject.accentColor + + let colorsCount = Int(flatBuffersObject.colorsCount) + if colorsCount > 0 { + var colors: [UInt32] = [] + colors.reserveCapacity(colorsCount) + for i in 0.. 0 { + var darkColors: [UInt32] = [] + darkColors.reserveCapacity(darkColorsCount) + for i in 0.. Offset { + let colorsOffset = builder.createVector(self.colors) + let darkColorsOffset: Offset? = self.darkColors.map { builder.createVector($0) } + + let start = TelegramCore_PeerCollectibleColor.startPeerCollectibleColor(&builder) + TelegramCore_PeerCollectibleColor.add(collectibleId: self.collectibleId, &builder) + TelegramCore_PeerCollectibleColor.add(giftEmojiFileId: self.giftEmojiFileId, &builder) + TelegramCore_PeerCollectibleColor.add(backgroundEmojiId: self.backgroundEmojiId, &builder) + TelegramCore_PeerCollectibleColor.add(accentColor: self.accentColor, &builder) + TelegramCore_PeerCollectibleColor.addVectorOf(colors: colorsOffset, &builder) + TelegramCore_PeerCollectibleColor.add(darkAccentColor: self.darkAccentColor ?? UInt32.min, &builder) + if let darkColorsOffset { + TelegramCore_PeerCollectibleColor.addVectorOf(darkColors: darkColorsOffset, &builder) + } + + return TelegramCore_PeerCollectibleColor.endPeerCollectibleColor(&builder, start: start) + } +} + +public enum PeerColor: Equatable { + case preset(PeerNameColor) + case collectible(PeerCollectibleColor) +} + public struct PeerEmojiStatus: Equatable, Codable { private enum CodingKeys: String, CodingKey { case fileId diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift index c6cf96b758..1006e61bd1 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramUser.swift @@ -164,7 +164,7 @@ public final class TelegramUser: Peer, Equatable { public let emojiStatus: PeerEmojiStatus? public let usernames: [TelegramPeerUsername] public let storiesHidden: Bool? - public let nameColor: PeerNameColor? + public let nameColor: PeerColor? public let backgroundEmojiId: Int64? public let profileColor: PeerNameColor? public let profileBackgroundEmojiId: Int64? @@ -259,7 +259,7 @@ public final class TelegramUser: Peer, Equatable { emojiStatus: PeerEmojiStatus?, usernames: [TelegramPeerUsername], storiesHidden: Bool?, - nameColor: PeerNameColor?, + nameColor: PeerColor?, backgroundEmojiId: Int64?, profileColor: PeerNameColor?, profileBackgroundEmojiId: Int64?, @@ -325,7 +325,13 @@ public final class TelegramUser: Peer, Equatable { self.usernames = decoder.decodeObjectArrayForKey("uns") self.storiesHidden = decoder.decodeOptionalBoolForKey("sth") - self.nameColor = decoder.decodeOptionalInt32ForKey("nclr").flatMap { PeerNameColor(rawValue: $0) } + if let collectibleColor = decoder.decodeCodable(PeerCollectibleColor.self, forKey: "clclr") { + self.nameColor = .collectible(collectibleColor) + } else if let nameColor = decoder.decodeOptionalInt32ForKey("nclr").flatMap({ PeerNameColor(rawValue: $0) }) { + self.nameColor = .preset(nameColor) + } else { + self.nameColor = nil + } self.backgroundEmojiId = decoder.decodeOptionalInt64ForKey("bgem") self.profileColor = decoder.decodeOptionalInt32ForKey("pclr").flatMap { PeerNameColor(rawValue: $0) } self.profileBackgroundEmojiId = decoder.decodeOptionalInt64ForKey("pgem") @@ -403,8 +409,16 @@ public final class TelegramUser: Peer, Equatable { } if let nameColor = self.nameColor { - encoder.encodeInt32(nameColor.rawValue, forKey: "nclr") + switch nameColor { + case let .preset(nameColor): + encoder.encodeInt32(nameColor.rawValue, forKey: "nclr") + encoder.encodeNil(forKey: "clclr") + case let .collectible(collectibleColor): + encoder.encodeCodable(collectibleColor, forKey: "clclr") + encoder.encodeNil(forKey: "nclr") + } } else { + encoder.encodeNil(forKey: "clclr") encoder.encodeNil(forKey: "nclr") } @@ -545,7 +559,7 @@ public final class TelegramUser: Peer, Equatable { return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: self.username, phone: self.phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags, emojiStatus: self.emojiStatus, usernames: self.usernames, storiesHidden: storiesHidden, nameColor: self.nameColor, backgroundEmojiId: self.backgroundEmojiId, profileColor: self.profileColor, profileBackgroundEmojiId: self.profileBackgroundEmojiId, subscriberCount: self.subscriberCount, verificationIconFileId: self.verificationIconFileId) } - public func withUpdatedNameColor(_ nameColor: PeerNameColor) -> TelegramUser { + public func withUpdatedNameColor(_ nameColor: PeerColor) -> TelegramUser { return TelegramUser(id: self.id, accessHash: self.accessHash, firstName: self.firstName, lastName: self.lastName, username: self.username, phone: self.phone, photo: self.photo, botInfo: self.botInfo, restrictionInfo: self.restrictionInfo, flags: self.flags, emojiStatus: self.emojiStatus, usernames: self.usernames, storiesHidden: self.storiesHidden, nameColor: nameColor, backgroundEmojiId: self.backgroundEmojiId, profileColor: self.profileColor, profileBackgroundEmojiId: self.profileBackgroundEmojiId, subscriberCount: self.subscriberCount, verificationIconFileId: self.verificationIconFileId) } @@ -575,7 +589,13 @@ public final class TelegramUser: Peer, Equatable { self.emojiStatus = try flatBuffersObject.emojiStatus.flatMap { try PeerEmojiStatus(flatBuffersObject: $0) } self.usernames = try (0 ..< flatBuffersObject.usernamesCount).map { try TelegramPeerUsername(flatBuffersObject: flatBuffersObject.usernames(at: $0)!) } self.storiesHidden = flatBuffersObject.storiesHidden?.value - self.nameColor = try flatBuffersObject.nameColor.flatMap(PeerNameColor.init) + if let collectibleColor = try flatBuffersObject.collectibleColor.flatMap(PeerCollectibleColor.init) { + self.nameColor = .collectible(collectibleColor) + } else if let nameColor = try flatBuffersObject.nameColor.flatMap(PeerNameColor.init) { + self.nameColor = .preset(nameColor) + } else { + self.nameColor = nil + } self.backgroundEmojiId = flatBuffersObject.backgroundEmojiId == Int64.min ? nil : flatBuffersObject.backgroundEmojiId self.profileColor = try flatBuffersObject.profileColor.flatMap(PeerNameColor.init) self.profileBackgroundEmojiId = flatBuffersObject.profileBackgroundEmojiId == Int64.min ? nil : flatBuffersObject.profileBackgroundEmojiId @@ -600,7 +620,18 @@ public final class TelegramUser: Peer, Equatable { let usernamesOffsets = self.usernames.map { $0.encodeToFlatBuffers(builder: &builder) } let usernamesOffset = builder.createVector(ofOffsets: usernamesOffsets, len: usernamesOffsets.count) - let nameColorOffset = self.nameColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) } + let nameColorOffset: Offset? + let collectibleColorOffset: Offset? + if case let .collectible(collectibleColor) = self.nameColor { + nameColorOffset = nil + collectibleColorOffset = collectibleColor.encodeToFlatBuffers(builder: &builder) + } else if case let .preset(nameColor) = self.nameColor { + nameColorOffset = nameColor.encodeToFlatBuffers(builder: &builder) + collectibleColorOffset = nil + } else { + nameColorOffset = nil + collectibleColorOffset = nil + } let profileColorOffset = self.profileColor.flatMap { $0.encodeToFlatBuffers(builder: &builder) } let emojiStatusOffset = self.emojiStatus?.encodeToFlatBuffers(builder: &builder) @@ -641,6 +672,9 @@ public final class TelegramUser: Peer, Equatable { if let nameColorOffset { TelegramCore_TelegramUser.add(nameColor: nameColorOffset, &builder) } + if let collectibleColorOffset { + TelegramCore_TelegramUser.add(collectibleColor: collectibleColorOffset, &builder) + } TelegramCore_TelegramUser.add(backgroundEmojiId: self.backgroundEmojiId ?? Int64.min, &builder) if let profileColorOffset { TelegramCore_TelegramUser.add(profileColor: profileColorOffset, &builder) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift index d69ec3624d..c71b6cdbb6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/TelegramEngineAccountData.swift @@ -43,8 +43,8 @@ public extension TelegramEngine { return _internal_observeAvailableColorOptions(postbox: self.account.postbox, scope: scope) } - public func updateNameColorAndEmoji(nameColor: PeerNameColor, backgroundEmojiId: Int64?, profileColor: PeerNameColor?, profileBackgroundEmojiId: Int64?) -> Signal { - return _internal_updateNameColorAndEmoji(account: self.account, nameColor: nameColor, backgroundEmojiId: backgroundEmojiId, profileColor: profileColor, profileBackgroundEmojiId: profileBackgroundEmojiId) + public func updateNameColorAndEmoji(nameColor: UpdateNameColor, profileColor: PeerNameColor?, profileBackgroundEmojiId: Int64?) -> Signal { + return _internal_updateNameColorAndEmoji(account: self.account, nameColor: nameColor, profileColor: profileColor, profileBackgroundEmojiId: profileBackgroundEmojiId) } public func unregisterNotificationToken(token: Data, type: NotificationTokenType, otherAccountUserIds: [PeerId.Id]) -> Signal { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/UpdateAccountPeerName.swift b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/UpdateAccountPeerName.swift index e1354a30ba..6a953e4699 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/AccountData/UpdateAccountPeerName.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/AccountData/UpdateAccountPeerName.swift @@ -47,16 +47,32 @@ func _internal_updateAbout(account: Account, about: String?) -> Signal Signal { +func _internal_updateNameColorAndEmoji(account: Account, nameColor: UpdateNameColor, profileColor: PeerNameColor?, profileBackgroundEmojiId: Int64?) -> Signal { return account.postbox.transaction { transaction -> Signal in guard let peer = transaction.getPeer(account.peerId) as? TelegramUser else { return .complete() } - updatePeersCustom(transaction: transaction, peers: [peer.withUpdatedNameColor(nameColor).withUpdatedBackgroundEmojiId(backgroundEmojiId).withUpdatedProfileColor(profileColor).withUpdatedProfileBackgroundEmojiId(profileBackgroundEmojiId)], update: { _, updated in + var nameColorValue: PeerColor + var backgroundEmojiIdValue: Int64? + switch nameColor { + case let .preset(color, backgroundEmojiId): + nameColorValue = .preset(color) + backgroundEmojiIdValue = backgroundEmojiId + case let .collectible(collectibleColor): + nameColorValue = .collectible(collectibleColor) + backgroundEmojiIdValue = collectibleColor.backgroundEmojiId + } + + updatePeersCustom(transaction: transaction, peers: [peer.withUpdatedNameColor(nameColorValue).withUpdatedBackgroundEmojiId(backgroundEmojiIdValue).withUpdatedProfileColor(profileColor).withUpdatedProfileBackgroundEmojiId(profileBackgroundEmojiId)], update: { _, updated in return updated }) return .single(peer) @@ -64,10 +80,18 @@ func _internal_updateNameColorAndEmoji(account: Account, nameColor: PeerNameColo |> switchToLatest |> castError(UpdateNameColorAndEmojiError.self) |> mapToSignal { _ -> Signal in - var flagsReplies: Int32 = (1 << 0) - if let _ = backgroundEmojiId { - flagsReplies |= (1 << 1) + let inputRepliesColor: Api.PeerColor + switch nameColor { + case let .preset(color, backgroundEmojiId): + var flags: Int32 = (1 << 0) + if let _ = backgroundEmojiId { + flags |= (1 << 1) + } + inputRepliesColor = .peerColor(flags: flags, color: color.rawValue, backgroundEmojiId: backgroundEmojiId) + case let .collectible(collectibleColor): + inputRepliesColor = .inputPeerColorCollectible(collectibleId: collectibleColor.collectibleId) } + var flagsProfile: Int32 = 0 if let _ = profileColor { flagsProfile |= (1 << 0) @@ -75,9 +99,9 @@ func _internal_updateNameColorAndEmoji(account: Account, nameColor: PeerNameColo if let _ = profileBackgroundEmojiId { flagsProfile |= (1 << 1) } - + return combineLatest( - account.network.request(Api.functions.account.updateColor(flags: (1 << 2), color: .peerColor(flags: flagsReplies, color: nameColor.rawValue, backgroundEmojiId: backgroundEmojiId))), + account.network.request(Api.functions.account.updateColor(flags: (1 << 2), color: inputRepliesColor)), account.network.request(Api.functions.account.updateColor(flags: (1 << 1) | (1 << 2), color: .peerColor(flags: flagsProfile, color: profileColor?.rawValue ?? 0, backgroundEmojiId: profileBackgroundEmojiId))) ) |> mapError { _ -> UpdateNameColorAndEmojiError in diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift index 2b5dfadea2..9d50c8e691 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift @@ -608,8 +608,9 @@ public enum StarGift: Equatable, Codable, PostboxCoding { public let valueCurrency: String? public let flags: Flags public let themePeerId: EnginePeer.Id? + public let peerColor: PeerCollectibleColor? - public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?, flags: Flags, themePeerId: EnginePeer.Id?) { + public init(id: Int64, giftId: Int64, title: String, number: Int32, slug: String, owner: Owner, attributes: [Attribute], availability: Availability, giftAddress: String?, resellAmounts: [CurrencyAmount]?, resellForTonOnly: Bool, releasedBy: EnginePeer.Id?, valueAmount: Int64?, valueCurrency: String?, flags: Flags, themePeerId: EnginePeer.Id?, peerColor: PeerCollectibleColor?) { self.id = id self.giftId = giftId self.title = title @@ -626,6 +627,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding { self.valueCurrency = valueCurrency self.flags = flags self.themePeerId = themePeerId + self.peerColor = peerColor } public init(from decoder: Decoder) throws { @@ -660,6 +662,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding { self.valueCurrency = try container.decodeIfPresent(String.self, forKey: .valueCurrency) self.flags = try container.decodeIfPresent(Int32.self, forKey: .flags).flatMap { Flags(rawValue: $0) } ?? [] self.themePeerId = try container.decodeIfPresent(Int64.self, forKey: .themePeerId).flatMap { EnginePeer.Id($0) } + self.peerColor = try container.decodeIfPresent(PeerCollectibleColor.self, forKey: .peerColor) } public init(decoder: PostboxDecoder) { @@ -693,6 +696,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding { self.valueCurrency = decoder.decodeOptionalStringForKey(CodingKeys.valueCurrency.rawValue) self.flags = decoder.decodeOptionalInt32ForKey(CodingKeys.flags.rawValue).flatMap { Flags(rawValue: $0) } ?? [] self.themePeerId = decoder.decodeOptionalInt64ForKey(CodingKeys.themePeerId.rawValue).flatMap { EnginePeer.Id($0) } + self.peerColor = decoder.decodeCodable(PeerCollectibleColor.self, forKey: CodingKeys.peerColor.rawValue) } public func encode(to encoder: Encoder) throws { @@ -720,6 +724,7 @@ public enum StarGift: Equatable, Codable, PostboxCoding { try container.encodeIfPresent(self.valueCurrency, forKey: .valueCurrency) try container.encode(self.flags.rawValue, forKey: .flags) try container.encodeIfPresent(self.themePeerId?.toInt64(), forKey: .themePeerId) + try container.encodeIfPresent(self.peerColor, forKey: .peerColor) } public func encode(_ encoder: PostboxEncoder) { @@ -767,6 +772,11 @@ public enum StarGift: Equatable, Codable, PostboxCoding { } else { encoder.encodeNil(forKey: CodingKeys.themePeerId.rawValue) } + if let peerColor = self.peerColor { + encoder.encodeCodable(peerColor, forKey: CodingKeys.peerColor.rawValue) + } else { + encoder.encodeNil(forKey: CodingKeys.peerColor.rawValue) + } } public func withResellAmounts(_ resellAmounts: [CurrencyAmount]?) -> UniqueGift { @@ -786,7 +796,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding { valueAmount: self.valueAmount, valueCurrency: self.valueCurrency, flags: self.flags, - themePeerId: self.themePeerId + themePeerId: self.themePeerId, + peerColor: self.peerColor ) } @@ -807,7 +818,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding { valueAmount: self.valueAmount, valueCurrency: self.valueCurrency, flags: self.flags, - themePeerId: self.themePeerId + themePeerId: self.themePeerId, + peerColor: self.peerColor ) } @@ -828,7 +840,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding { valueAmount: self.valueAmount, valueCurrency: self.valueCurrency, flags: self.flags, - themePeerId: themePeerId + themePeerId: themePeerId, + peerColor: self.peerColor ) } @@ -849,7 +862,8 @@ public enum StarGift: Equatable, Codable, PostboxCoding { valueAmount: self.valueAmount, valueCurrency: self.valueCurrency, flags: self.flags, - themePeerId: self.themePeerId + themePeerId: self.themePeerId, + peerColor: self.peerColor ) } } @@ -960,7 +974,6 @@ extension StarGift { } self = .generic(StarGift.Gift(id: id, title: title, file: file, price: stars, convertStars: convertStars, availability: availability, soldOut: soldOut, flags: flags, upgradeStars: upgradeStars, releasedBy: releasedBy?.peerId, perUserLimit: perUserLimit, lockedUntilDate: lockedUntilDate)) case let .starGiftUnique(apiFlags, id, giftId, title, slug, num, ownerPeerId, ownerName, ownerAddress, attributes, availabilityIssued, availabilityTotal, giftAddress, resellAmounts, releasedBy, valueAmount, valueCurrency, themePeer, peerColor): - let _ = peerColor let owner: StarGift.UniqueGift.Owner if let ownerAddress { owner = .address(ownerAddress) @@ -976,7 +989,23 @@ extension StarGift { if (apiFlags & (1 << 9)) != 0 { flags.insert(.isThemeAvailable) } - self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (apiFlags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency, flags: flags, themePeerId: themePeer?.peerId)) + var peerCollectibleColor: PeerCollectibleColor? + switch peerColor { + case let .peerColorCollectible(_, collectibleId, giftEmojiId, backgroundEmojiId, accentColor, colors, darkAccentColor, darkColors): + peerCollectibleColor = PeerCollectibleColor( + collectibleId: collectibleId, + giftEmojiFileId: giftEmojiId, + backgroundEmojiId: backgroundEmojiId, + accentColor: UInt32(bitPattern: accentColor), + colors: colors.map { UInt32(bitPattern: $0) }, + darkAccentColor: darkAccentColor.flatMap { UInt32(bitPattern: $0) }, + darkColors: darkColors.flatMap { $0.map { UInt32(bitPattern: $0) } } + ) + default: + break + } + + self = .unique(StarGift.UniqueGift(id: id, giftId: giftId, title: title, number: num, slug: slug, owner: owner, attributes: attributes.compactMap { UniqueGift.Attribute(apiAttribute: $0) }, availability: UniqueGift.Availability(issued: availabilityIssued, total: availabilityTotal), giftAddress: giftAddress, resellAmounts: resellAmounts, resellForTonOnly: (apiFlags & (1 << 7)) != 0, releasedBy: releasedBy?.peerId, valueAmount: valueAmount, valueCurrency: valueCurrency, flags: flags, themePeerId: themePeer?.peerId, peerColor: peerCollectibleColor)) } } } @@ -1513,13 +1542,14 @@ private final class ProfileGiftsContextImpl { self.filteredCount = nil } let isUniqueOnlyFilter = self.filter == [.unique, .displayed, .hidden] + let isPeerColorFilter = self.filter == .peerColor let dataState = isFiltered ? self.filteredDataState : self.dataState guard case let .ready(true, initialNextOffset) = dataState else { return } - if !isFiltered || isUniqueOnlyFilter, self.gifts.isEmpty, initialNextOffset == nil, !reload { + if !isFiltered || isUniqueOnlyFilter || isPeerColorFilter, self.gifts.isEmpty, initialNextOffset == nil, !reload { self.cacheDisposable.set((self.account.postbox.transaction { transaction -> CachedProfileGifts? in let cachedGifts = transaction.retrieveItemCacheEntry(id: giftsEntryId(peerId: peerId, collectionId: collectionId))?.get(CachedProfileGifts.self) cachedGifts?.render(transaction: transaction) @@ -1528,17 +1558,26 @@ private final class ProfileGiftsContextImpl { guard let self, let cachedGifts else { return } - if isUniqueOnlyFilter, case .loading = self.filteredDataState { - var gifts = cachedGifts.gifts - if isUniqueOnlyFilter { - gifts = gifts.filter({ gift in - if case .unique = gift.gift { - return true - } else { - return false - } - }) - } + if isPeerColorFilter, case .loading = self.filteredDataState { + let gifts = cachedGifts.gifts.filter({ gift in + if case let .unique(uniqueGift) = gift.gift, let _ = uniqueGift.peerColor { + return true + } else { + return false + } + }) + self.gifts = gifts + self.count = cachedGifts.count + self.notificationsEnabled = cachedGifts.notificationsEnabled + self.pushState() + } else if isUniqueOnlyFilter, case .loading = self.filteredDataState { + let gifts = cachedGifts.gifts.filter({ gift in + if case .unique = gift.gift { + return true + } else { + return false + } + }) self.gifts = gifts self.count = cachedGifts.count self.notificationsEnabled = cachedGifts.notificationsEnabled @@ -1575,23 +1614,27 @@ private final class ProfileGiftsContextImpl { if case .value = sorting { flags |= (1 << 5) } - if !filter.contains(.hidden) { - flags |= (1 << 0) - } - if !filter.contains(.displayed) { - flags |= (1 << 1) - } - if !filter.contains(.unlimited) { - flags |= (1 << 2) - } - if !filter.contains(.limitedUpgradable) { - flags |= (1 << 7) - } - if !filter.contains(.limitedNonUpgradable) { - flags |= (1 << 8) - } - if !filter.contains(.unique) { - flags |= (1 << 4) + if filter.contains(.peerColor) { + flags |= (1 << 9) + } else { + if !filter.contains(.hidden) { + flags |= (1 << 0) + } + if !filter.contains(.displayed) { + flags |= (1 << 1) + } + if !filter.contains(.unlimited) { + flags |= (1 << 2) + } + if !filter.contains(.limitedUpgradable) { + flags |= (1 << 7) + } + if !filter.contains(.limitedNonUpgradable) { + flags |= (1 << 8) + } + if !filter.contains(.unique) { + flags |= (1 << 4) + } } return network.request(Api.functions.payments.getSavedStarGifts(flags: flags, peer: inputPeer, collectionId: collectionId, offset: initialNextOffset ?? "", limit: limit)) |> map(Optional.init) @@ -2187,6 +2230,7 @@ public final class ProfileGiftsContext { public static let unique = Filters(rawValue: 1 << 3) public static let displayed = Filters(rawValue: 1 << 4) public static let hidden = Filters(rawValue: 1 << 5) + public static let peerColor = Filters(rawValue: 1 << 6) public static var All: Filters { return [.unlimited, .limitedUpgradable, .limitedNonUpgradable, .unique, .displayed, .hidden] diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift index 26605aff93..5df8dd58ab 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift @@ -531,7 +531,7 @@ public extension EnginePeer { return false } - var nameColor: PeerNameColor? { + var nameColor: PeerColor? { return self._asPeer().nameColor } diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 1ab6b7d55c..68ccd30621 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -301,19 +301,19 @@ public extension Peer { } } - var nameColor: PeerNameColor? { + var nameColor: PeerColor? { switch self { case let user as TelegramUser: if let nameColor = user.nameColor { return nameColor } else { - return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) + return .preset(PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7))) } case let channel as TelegramChannel: if let nameColor = channel.nameColor { - return nameColor + return .preset(nameColor) } else { - return PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) + return .preset(PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7))) } default: return nil @@ -352,7 +352,7 @@ public extension Peer { var hasCustomNameColor: Bool { let defaultNameColor = PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) - if self.nameColor != defaultNameColor { + if self.nameColor != .preset(defaultNameColor) { return true } return false diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift index 206f7d0a3c..fee0565330 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift @@ -240,7 +240,15 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { } } - let nameColors = author?.nameColor.flatMap { context.peerNameColors.get($0, dark: presentationData.theme.theme.overallDarkAppearance) } + let nameColors: PeerNameColors.Colors? + switch author?.nameColor { + case let .preset(nameColor): + nameColors = context.peerNameColors.get(nameColor, dark: presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = nil + } let mainColor: UIColor var secondaryColor: UIColor? diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index ec45087b2f..61f056323c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -2211,11 +2211,26 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case .broadcast = peer.info, item.content.firstMessage.adAttribute == nil { let peer = (peer as Peer) - let nameColors = peer.nameColor.flatMap { item.context.peerNameColors.get($0, dark: item.presentationData.theme.theme.overallDarkAppearance) } + let nameColors: PeerNameColors.Colors? + switch peer.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = nil + } authorNameColor = nameColors?.main } else if let effectiveAuthor = effectiveAuthor { - let nameColor = effectiveAuthor.nameColor ?? .blue - let nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + let nameColors: PeerNameColors.Colors + switch effectiveAuthor.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = item.context.peerNameColors.get(.blue, dark: item.presentationData.theme.theme.overallDarkAppearance) + } let color: UIColor if incoming { color = nameColors.main @@ -2230,13 +2245,28 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI authorNameString = EnginePeer(peer).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) let peer = (peer as Peer) - let nameColors = peer.nameColor.flatMap { item.context.peerNameColors.get($0, dark: item.presentationData.theme.theme.overallDarkAppearance) } + let nameColors: PeerNameColors.Colors? + switch peer.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = nil + } authorNameColor = nameColors?.main } else if let effectiveAuthor = effectiveAuthor { authorNameString = EnginePeer(effectiveAuthor).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) - let nameColor = effectiveAuthor.nameColor ?? .blue - let nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + let nameColors: PeerNameColors.Colors + switch effectiveAuthor.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = item.context.peerNameColors.get(.blue, dark: item.presentationData.theme.theme.overallDarkAppearance) + } let color: UIColor if incoming { color = nameColors.main @@ -6259,7 +6289,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI default: return } - item.controllerInteraction.openPremiumStatusInfo(peer.id, credibilityIconView, emojiFileId, peer.nameColor ?? .blue) + item.controllerInteraction.openPremiumStatusInfo(peer.id, credibilityIconView, emojiFileId, peer.nameColor ?? .preset(.blue)) } } } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageContactBubbleContentNode/Sources/ChatMessageContactBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageContactBubbleContentNode/Sources/ChatMessageContactBubbleContentNode.swift index 6d6aa353a6..b668005ce7 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageContactBubbleContentNode/Sources/ChatMessageContactBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageContactBubbleContentNode/Sources/ChatMessageContactBubbleContentNode.swift @@ -117,7 +117,15 @@ public class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { contactPeer = peer } - let nameColors = contactPeer?.nameColor.flatMap { item.context.peerNameColors.get($0, dark: item.presentationData.theme.theme.overallDarkAppearance) } + let nameColors: PeerNameColors.Colors? + switch contactPeer?.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = nil + } let messageTheme = incoming ? item.presentationData.theme.theme.chat.message.incoming : item.presentationData.theme.theme.chat.message.outgoing let mainColor: UIColor diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift index 4ed2ba5005..e6699164f0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageForwardInfoNode/Sources/ChatMessageForwardInfoNode.swift @@ -344,7 +344,12 @@ public class ChatMessageForwardInfoNode: ASDisplayNode { } else { if incoming { if let nameColor = peer?.nameColor { - titleColor = context.peerNameColors.get(nameColor, dark: presentationData.theme.theme.overallDarkAppearance).main + switch nameColor { + case let .preset(nameColor): + titleColor = context.peerNameColors.get(nameColor, dark: presentationData.theme.theme.overallDarkAppearance).main + case let .collectible(collectibleColor): + titleColor = collectibleColor.mainColor(dark: presentationData.theme.theme.overallDarkAppearance) + } } else { titleColor = presentationData.theme.theme.chat.message.incoming.accentTextColor } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift index dc611f355c..fbb56f38f3 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift @@ -983,7 +983,12 @@ private final class PeerButtonsStackNode: ASDisplayNode { var titleColor = titleColor var backgroundColor = backgroundColor if incoming, let nameColor = peer.nameColor, makeChannelButtonLayouts.count > 1 { - titleColor = context.peerNameColors.get(nameColor, dark: dark).main + switch nameColor { + case let .preset(nameColor): + titleColor = context.peerNameColors.get(nameColor, dark: dark).main + case let .collectible(collectibleColor): + titleColor = collectibleColor.mainColor(dark: dark) + } backgroundColor = titleColor.withAlphaComponent(0.1) } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/BUILD b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/BUILD index e49f6f160f..9c5a9df3aa 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/BUILD +++ b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/BUILD @@ -28,6 +28,7 @@ swift_library( "//submodules/TelegramUI/Components/MultiAnimationRenderer", "//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon", "//submodules/TelegramUI/Components/Chat/MessageInlineBlockBackgroundView", + "//submodules/TelegramUI/Components/EmojiTextAttachmentView", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift index f60fbd37ec..b766c38d04 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageReplyInfoNode/Sources/ChatMessageReplyInfoNode.swift @@ -18,6 +18,7 @@ import MultiAnimationRenderer import ChatMessageItemCommon import MessageInlineBlockBackgroundView import CheckNode +import EmojiTextAttachmentView public enum ChatMessageReplyInfoType { case bubble(incoming: Bool) @@ -141,6 +142,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { private var previousMediaReference: AnyMediaReference? private var expiredStoryIconView: UIImageView? private var checkLayer: CheckLayer? + private var giftEmojiLayer: InlineStickerItemLayer? private var currentProgressDisposable: Disposable? @@ -204,9 +206,11 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { var secondaryColor: UIColor? var tertiaryColor: UIColor? + var authorNameColor: UIColor? var dashSecondaryColor: UIColor? var dashTertiaryColor: UIColor? + let placeholderColor: UIColor var author = arguments.message?.effectiveAuthor @@ -218,10 +222,22 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { } } - let colors = author?.nameColor.flatMap { arguments.context.peerNameColors.get($0, dark: arguments.presentationData.theme.theme.overallDarkAppearance) } - authorNameColor = colors?.main - dashSecondaryColor = colors?.secondary - dashTertiaryColor = colors?.tertiary + var giftEmojiFileId: Int64? + switch author?.nameColor { + case let .preset(nameColor): + let colors = arguments.context.peerNameColors.get(nameColor, dark: arguments.presentationData.theme.theme.overallDarkAppearance) + authorNameColor = colors.main + dashSecondaryColor = colors.secondary + dashTertiaryColor = colors.tertiary + case let .collectible(collectibleColor): + let colors = collectibleColor.peerNameColors(dark: arguments.presentationData.theme.theme.overallDarkAppearance) + authorNameColor = colors.main + dashSecondaryColor = colors.secondary + dashTertiaryColor = colors.tertiary + giftEmojiFileId = collectibleColor.giftEmojiFileId + default: + break + } switch arguments.type { case let .bubble(incoming): @@ -244,6 +260,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { } } dustColor = incoming ? arguments.presentationData.theme.theme.chat.message.incoming.secondaryTextColor : arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor + placeholderColor = incoming ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor case .standalone: let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) titleColor = serviceColor.primaryText @@ -256,6 +273,7 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { mainColor = serviceMessageColorComponents(chatTheme: arguments.presentationData.theme.theme.chat, wallpaper: arguments.presentationData.theme.wallpaper).primaryText dustColor = titleColor + placeholderColor = serviceColor.primaryText.withAlphaComponent(0.2) } if let message = arguments.message { @@ -403,10 +421,6 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { isText = false } - let isIncoming = arguments.parentMessage.effectivelyIncoming(arguments.context.account.peerId) - - let placeholderColor: UIColor = isIncoming ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor - let textColor: UIColor switch arguments.type { @@ -883,6 +897,28 @@ public class ChatMessageReplyInfoNode: ASDisplayNode { checkLayer.removeFromSuperlayer() } + 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 giftEmojiLayer: InlineStickerItemLayer + if let current = node.giftEmojiLayer { + 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) + node.giftEmojiLayer = giftEmojiLayer + node.contentNode.layer.addSublayer(giftEmojiLayer) + + giftEmojiLayer.frame = giftLayerFrame + } + + } else if let giftEmojiLayer = node.giftEmojiLayer { + node.giftEmojiLayer = nil + giftEmojiLayer.removeFromSuperlayer() + } + node.contentNode.frame = CGRect(origin: CGPoint(), size: size) return node diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift index 990c1fa9d8..176ef3ce7e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift @@ -532,7 +532,16 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { var secondaryColor: UIColor? = nil var tertiaryColor: UIColor? = nil - let nameColors = author?.nameColor.flatMap { item.context.peerNameColors.get($0, dark: item.presentationData.theme.theme.overallDarkAppearance) } + let nameColors: PeerNameColors.Colors? + switch author?.nameColor { + case let .preset(nameColor): + nameColors = item.context.peerNameColors.get(nameColor, dark: item.presentationData.theme.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: item.presentationData.theme.theme.overallDarkAppearance) + default: + nameColors = nil + } + let codeBlockTitleColor: UIColor let codeBlockAccentColor: UIColor let codeBlockBackgroundColor: UIColor diff --git a/submodules/TelegramUI/Components/Chat/MergedAvatarsNode/Sources/MergedAvatarsNode.swift b/submodules/TelegramUI/Components/Chat/MergedAvatarsNode/Sources/MergedAvatarsNode.swift index 184f571429..111a1d8640 100644 --- a/submodules/TelegramUI/Components/Chat/MergedAvatarsNode/Sources/MergedAvatarsNode.swift +++ b/submodules/TelegramUI/Components/Chat/MergedAvatarsNode/Sources/MergedAvatarsNode.swift @@ -10,7 +10,7 @@ import AvatarNode import AccountContext private enum PeerAvatarReference: Equatable { - case letters(PeerId, PeerNameColor?, [String]) + case letters(PeerId, PeerColor?, [String]) case image(PeerReference, TelegramMediaImageRepresentation) var peerId: PeerId { diff --git a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift index cdd992d223..6855559492 100644 --- a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift @@ -267,7 +267,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol public let openNoAdsDemo: () -> Void public let openAdsInfo: () -> Void public let displayGiveawayParticipationStatus: (EngineMessage.Id) -> Void - public let openPremiumStatusInfo: (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void + public let openPremiumStatusInfo: (EnginePeer.Id, UIView, Int64?, PeerColor) -> Void public let openRecommendedChannelContextMenu: (EnginePeer, UIView, ContextGesture?) -> Void public let openGroupBoostInfo: (EnginePeer.Id?, Int) -> Void public let openStickerEditor: () -> Void @@ -434,7 +434,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol openNoAdsDemo: @escaping () -> Void, openAdsInfo: @escaping () -> Void, displayGiveawayParticipationStatus: @escaping (EngineMessage.Id) -> Void, - openPremiumStatusInfo: @escaping (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void, + openPremiumStatusInfo: @escaping (EnginePeer.Id, UIView, Int64?, PeerColor) -> Void, openRecommendedChannelContextMenu: @escaping (EnginePeer, UIView, ContextGesture?) -> Void, openGroupBoostInfo: @escaping (EnginePeer.Id?, Int) -> Void, openStickerEditor: @escaping () -> Void, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 52f0cd6fb7..6a98d2d19e 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1212,8 +1212,15 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat 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 nameColor = peer.nameColor { + let nameColors: PeerNameColors.Colors + switch nameColor { + case let .preset(nameColor): + nameColors = context.peerNameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance) + case let .collectible(collectibleColor): + nameColors = collectibleColor.peerNameColors(dark: presentationData.theme.overallDarkAppearance) + } + colors.append(nameColors) } if let profileColor = peer.profileColor.flatMap({ context.peerNameColors.getProfile($0, dark: presentationData.theme.overallDarkAppearance, subject: .palette) }) { colors.append(profileColor) diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ChannelAppearanceScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ChannelAppearanceScreen.swift index 59e1b089eb..71c08f2fce 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ChannelAppearanceScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/ChannelAppearanceScreen.swift @@ -360,12 +360,12 @@ final class ChannelAppearanceScreenComponent: Component { let nameColor: PeerNameColor if let updatedPeerNameColor = self.updatedPeerNameColor { nameColor = updatedPeerNameColor - } else if let peerNameColor = peer.nameColor { - nameColor = peerNameColor + } else if let peerNameColor = peer.nameColor, case let .preset(nameColorValue) = peerNameColor { + nameColor = nameColorValue } else { nameColor = .blue } - if nameColor != peer.nameColor { + if .preset(nameColor) != peer.nameColor { changes.insert(.nameColor) } @@ -962,7 +962,7 @@ final class ChannelAppearanceScreenComponent: Component { if case let .user(user) = peer { peer = .user(user - .withUpdatedNameColor(resolvedState.nameColor) + .withUpdatedNameColor(.preset(resolvedState.nameColor)) .withUpdatedProfileColor(profileColor) .withUpdatedEmojiStatus(emojiStatus) .withUpdatedBackgroundEmojiId(replyFileId) @@ -1502,9 +1502,9 @@ final class ChannelAppearanceScreenComponent: Component { peerId: EnginePeer.Id(namespace: peer.id.namespace, id: PeerId.Id._internalFromInt64Value(0)), author: peer.compactDisplayTitle, photo: peer.profileImageRepresentations, - nameColor: resolvedState.nameColor, + nameColor: .preset(resolvedState.nameColor), backgroundEmojiId: replyFileId, - reply: (peer.compactDisplayTitle, environment.strings.Channel_Appearance_ExampleReplyText, resolvedState.nameColor), + reply: (peer.compactDisplayTitle, environment.strings.Channel_Appearance_ExampleReplyText, .preset(resolvedState.nameColor)), linkPreview: (environment.strings.Channel_Appearance_ExampleLinkWebsite, environment.strings.Channel_Appearance_ExampleLinkTitle, environment.strings.Channel_Appearance_ExampleLinkText), text: environment.strings.Channel_Appearance_ExampleText ) @@ -1639,9 +1639,9 @@ final class ChannelAppearanceScreenComponent: Component { peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(0)), author: environment.strings.Group_Appearance_PreviewAuthor, photo: [], - nameColor: .red, + nameColor: .preset(.red), backgroundEmojiId: 5301072507598550489, - reply: (environment.strings.Appearance_PreviewReplyAuthor, environment.strings.Appearance_PreviewReplyText, .violet), + reply: (environment.strings.Appearance_PreviewReplyAuthor, environment.strings.Appearance_PreviewReplyText, .preset(.violet)), linkPreview: nil, text: environment.strings.Appearance_PreviewIncomingText ) @@ -1651,7 +1651,7 @@ final class ChannelAppearanceScreenComponent: Component { peerId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(1)), author: peer.compactDisplayTitle, photo: peer.profileImageRepresentations, - nameColor: .blue, + nameColor: .preset(.blue), backgroundEmojiId: nil, reply: nil, linkPreview: nil, diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorChatPreviewItem.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorChatPreviewItem.swift index 98a113ffe3..f305e4f51d 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorChatPreviewItem.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorChatPreviewItem.swift @@ -55,9 +55,9 @@ final class PeerNameColorChatPreviewItem: ListViewItem, ItemListItem, ListItemCo let peerId: EnginePeer.Id let author: String let photo: [TelegramMediaImageRepresentation] - let nameColor: PeerNameColor + let nameColor: PeerColor let backgroundEmojiId: Int64? - let reply: (String, String, PeerNameColor)? + let reply: (String, String, PeerColor)? let linkPreview: (String, String, String)? let text: String } diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorProfilePreviewItem.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorProfilePreviewItem.swift index 770ea1d610..4ade38f76d 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorProfilePreviewItem.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorProfilePreviewItem.swift @@ -343,7 +343,7 @@ final class PeerNameColorProfilePreviewItemNode: ListViewItemNode { case .scam: emojiStatusContent = .text(color: item.theme.chat.message.incoming.scamColor, string: item.strings.Message_ScamAccount.uppercased()) case let .emojiStatus(emojiStatus): - emojiStatusContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 80.0, height: 80.0), placeholderColor: item.theme.list.mediaPlaceholderColor, themeColor: statusColor, loopMode: .forever) + emojiStatusContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 80.0, height: 80.0), placeholderColor: item.theme.list.mediaPlaceholderColor, themeColor: statusColor, loopMode: .count(2)) } let backgroundColor: UIColor diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift index 1bc64a2a86..1920156e41 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/UserApperanceScreen.swift @@ -114,7 +114,7 @@ final class UserAppearanceScreenComponent: Component { static let emojiStatus = Changes(rawValue: 1 << 4) } - var nameColor: PeerNameColor + var nameColor: PeerColor var profileColor: PeerNameColor? var replyFileId: Int64? var backgroundFileId: Int64? @@ -123,7 +123,7 @@ final class UserAppearanceScreenComponent: Component { var changes: Changes init( - nameColor: PeerNameColor, + nameColor: PeerColor, profileColor: PeerNameColor?, replyFileId: Int64?, backgroundFileId: Int64?, @@ -149,15 +149,20 @@ final class UserAppearanceScreenComponent: Component { private let backButton = PeerInfoHeaderNavigationButton() private let tabSelector = ComponentView() + enum Section: Int32 { + case profile + 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 wallpaperSection = ComponentView() private let resetColorSection = ComponentView() - private let giftsSection = ComponentView() - + private let profileGiftsSection = ComponentView() + private let nameGiftsSection = ComponentView() + private var isUpdating: Bool = false private var component: UserAppearanceScreenComponent? @@ -168,9 +173,13 @@ final class UserAppearanceScreenComponent: Component { private var contentsData: ContentsData? private var contentsDataDisposable: Disposable? + private var starGiftsContext: ProfileGiftsContext? + private var starGiftsDisposable: Disposable? + private var starGifts: [StarGift.UniqueGift] = [] + private var cachedIconFiles: [Int64: TelegramMediaFile] = [:] - private var updatedPeerNameColor: PeerNameColor? + private var updatedPeerNameColor: PeerColor? private var updatedPeerNameEmoji: Int64?? private var updatedPeerProfileColor: PeerNameColor?? @@ -225,6 +234,7 @@ final class UserAppearanceScreenComponent: Component { deinit { self.contentsDataDisposable?.dispose() + self.starGiftsDisposable?.dispose() self.applyDisposable?.dispose() self.resolvingCurrentTheme?.disposable.dispose() } @@ -297,10 +307,24 @@ final class UserAppearanceScreenComponent: Component { transition.setAlpha(view: self.bottomPanelBackgroundView, alpha: bottomNavigationAlpha) transition.setAlpha(layer: self.bottomPanelSeparator, alpha: bottomNavigationAlpha) - if let giftListView = self.giftsSection.findTaggedView(tag: giftListTag) as? GiftListItemComponent.View { - let rect = self.scrollView.convert(self.scrollView.bounds, to: giftListView) - let visibleRect = giftListView.bounds.intersection(rect) - giftListView.updateVisibleBounds(visibleRect) + switch self.currentSection { + case .profile: + if let giftListView = self.profileGiftsSection.findTaggedView(tag: giftListTag) as? GiftListItemComponent.View { + let rect = self.scrollView.convert(self.scrollView.bounds, to: giftListView) + let visibleRect = giftListView.bounds.intersection(rect) + giftListView.updateVisibleBounds(visibleRect) + } + case .name: + if let giftListView = self.nameGiftsSection.findTaggedView(tag: giftListTag) as? GiftListItemComponent.View { + let rect = self.scrollView.convert(self.scrollView.bounds, to: giftListView) + let visibleRect = giftListView.bounds.intersection(rect) + giftListView.updateVisibleBounds(visibleRect) + } + + let bottomContentOffset = max(0.0, self.scrollView.contentSize.height - self.scrollView.contentOffset.y - self.scrollView.frame.height) + if bottomContentOffset < 320.0 { + self.starGiftsContext?.loadMore() + } } } @@ -311,13 +335,13 @@ final class UserAppearanceScreenComponent: Component { var changes: ResolvedState.Changes = [] - let nameColor: PeerNameColor + let nameColor: PeerColor if let updatedPeerNameColor = self.updatedPeerNameColor { nameColor = updatedPeerNameColor } else if let peerNameColor = peer.nameColor { nameColor = peerNameColor } else { - nameColor = .blue + nameColor = .preset(.blue) } if nameColor != peer.nameColor { changes.insert(.nameColor) @@ -428,7 +452,14 @@ final class UserAppearanceScreenComponent: Component { var signals: [Signal] = [] if !resolvedState.changes.intersection([.nameColor, .replyFileId, .profileColor, .backgroundFileId]).isEmpty { - signals.append(component.context.engine.accountData.updateNameColorAndEmoji(nameColor: resolvedState.nameColor, backgroundEmojiId: resolvedState.replyFileId, profileColor: resolvedState.profileColor, profileBackgroundEmojiId: resolvedState.backgroundFileId) + let nameColor: UpdateNameColor + switch resolvedState.nameColor { + case let .preset(peerNameColor): + nameColor = .preset(color: peerNameColor, backgroundEmojiId: resolvedState.replyFileId) + case let .collectible(peerCollectibleColor): + nameColor = .collectible(peerCollectibleColor) + } + signals.append(component.context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor, profileColor: resolvedState.profileColor, profileBackgroundEmojiId: resolvedState.backgroundFileId) |> ignoreValues |> mapError { _ -> ApplyError in return .generic @@ -467,7 +498,8 @@ final class UserAppearanceScreenComponent: Component { valueAmount: nil, valueCurrency: nil, flags: [], - themePeerId: nil + themePeerId: nil, + peerColor: nil ) signal = component.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: emojiStatus.expirationDate) } else { @@ -662,6 +694,26 @@ final class UserAppearanceScreenComponent: Component { } self.isReady.set(true) }) + + let starGiftsContext = ProfileGiftsContext(account: component.context.account, peerId: component.context.account.peerId, collectionId: nil, filter: .peerColor, limit: 30) + self.starGiftsContext = starGiftsContext + self.starGiftsDisposable = (starGiftsContext.state + |> deliverOnMainQueue).start(next: { [weak self] state in + guard let self else { + return + } + var uniqueGifts: [StarGift.UniqueGift] = [] + for gift in state.gifts { + if case let .unique(uniqueGift) = gift.gift { + uniqueGifts.append(uniqueGift) + } + } + self.starGifts = uniqueGifts + + if !self.isUpdating { + self.state?.updated() + } + }) } guard let contentsData = self.contentsData, var peer = contentsData.peer, let resolvedState = self.resolveState() else { @@ -719,36 +771,54 @@ final class UserAppearanceScreenComponent: Component { .withUpdatedProfileBackgroundEmojiId(resolvedState.backgroundFileId) ) } - - let headerColor: UIColor - if let profileColor = resolvedState.profileColor { - let headerBackgroundColors = component.context.peerNameColors.getProfile(profileColor, dark: environment.theme.overallDarkAppearance, subject: .background) - headerColor = headerBackgroundColors.secondary ?? headerBackgroundColors.main - } else { - headerColor = .clear - } - self.topOverscrollLayer.backgroundColor = headerColor.cgColor - + let backSize = self.backButton.update(key: .back, presentationData: component.context.sharedContext.currentPresentationData.with { $0 }, height: 44.0) - var hasHeaderColor = false - if resolvedState.profileColor != nil { - hasHeaderColor = true - } - if case .starGift = resolvedState.emojiStatus?.content { - hasHeaderColor = true - } - if let controller = self.environment?.controller() as? UserAppearanceScreen { - controller.statusBar.updateStatusBarStyle(hasHeaderColor ? .White : .Ignore, animated: true) - } - - self.backButton.updateContentsColor(backgroundColor: hasHeaderColor ? UIColor(white: 1.0, alpha: 0.1) : .clear, contentsColor: hasHeaderColor ? .white : environment.theme.rootController.navigationBar.accentTextColor, canBeExpanded: !hasHeaderColor, transition: .animated(duration: 0.2, curve: .easeInOut)) + self.backButton.updateContentsColor(backgroundColor: .clear, contentsColor: environment.theme.rootController.navigationBar.accentTextColor, canBeExpanded: true, transition: .animated(duration: 0.2, curve: .easeInOut)) self.backButton.frame = CGRect(origin: CGPoint(x: environment.safeInsets.left + 16.0, y: environment.navigationHeight - 44.0), size: backSize) if self.backButton.view.superview == nil { if let controller = self.environment?.controller(), let navigationBar = controller.navigationBar { navigationBar.view.addSubview(self.backButton.view) } } + + //TODO:localize + let tabSelectorSize = self.tabSelector.update( + transition: transition, + component: AnyComponent( + TabSelectorComponent( + colors: TabSelectorComponent.Colors( + foreground: environment.theme.list.itemSecondaryTextColor, + selection: environment.theme.list.itemSecondaryTextColor.withMultipliedAlpha(0.15), + simple: true + ), + theme: environment.theme, + items: [ + TabSelectorComponent.Item(id: Section.profile.rawValue, title: "Profile"), + TabSelectorComponent.Item(id: Section.name.rawValue, title: "Name") + ], + selectedId: self.currentSection.rawValue, + setSelectedId: { [weak self] value in + guard let self else { + return + } + if let intValue = value.base as? Int32 { + self.currentSection = Section(rawValue: intValue) ?? .profile + self.state?.updated(transition: .immediate) + } + } + ) + ), + environment: {}, + containerSize: CGSize(width: availableSize.width, height: 44.0) + ) + let tabSelectorFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - tabSelectorSize.width) / 2.0), y: environment.statusBarHeight + floorToScreenPixels((environment.navigationHeight - environment.statusBarHeight - tabSelectorSize.height) / 2.0)), size: tabSelectorSize) + if let tabSelectorView = self.tabSelector.view { + if tabSelectorView.superview == nil { + self.addSubview(tabSelectorView) + } + transition.setFrame(view: tabSelectorView, frame: tabSelectorFrame) + } let bottomContentInset: CGFloat = 24.0 let bottomInset: CGFloat = 8.0 @@ -760,380 +830,483 @@ final class UserAppearanceScreenComponent: Component { var contentHeight: CGFloat = 0.0 let sectionTransition = transition - - 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: environment.statusBarHeight, - sectionId: 0, - peer: peer, - subtitleString: environment.strings.Presence_online, - files: self.cachedIconFiles, - nameDisplayOrder: presentationData.nameDisplayOrder, - showBackground: !self.scrolledUp - ), - params: ListViewItemLayoutParams(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true) - ))), - ], - displaySeparators: false, - extendsItemHighlightToSection: true - )), - environment: {}, - containerSize: CGSize(width: availableSize.width, height: 1000.0) - ) - let previewSectionFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: previewSectionSize) - if let previewSectionView = self.previewSection.view { - if previewSectionView.superview == nil { - self.addSubview(previewSectionView) - } - sectionTransition.setFrame(view: previewSectionView, frame: previewSectionFrame) - } - contentHeight += previewSectionSize.height - contentHeight += sectionSpacing - 15.0 + + let itemCornerRadius: CGFloat = 10.0 - var profileLogoContents: [AnyComponentWithIdentity] = [] - profileLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.NameColor_AddProfileIcons, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 0 - )))) - let bannerSectionSize = self.bannerSection.update( - transition: sectionTransition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - background: .all, - header: nil, - footer: nil, - items: [ - AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor( - itemGenerator: PeerNameColorItem( + switch self.currentSection { + case .profile: + if let replySectionView = self.replySection.view, replySectionView.superview != nil { + replySectionView.removeFromSuperview() + } + if let nameGiftsSectionView = self.nameGiftsSection.view, nameGiftsSectionView.superview != nil { + nameGiftsSectionView.removeFromSuperview() + } + + var hasHeaderColor = false + if resolvedState.profileColor != nil { + hasHeaderColor = true + } + 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 + )), + 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) + } + sectionTransition.setFrame(view: previewSectionView, frame: previewSectionFrame) + } + contentHeight += previewSectionSize.height + contentHeight += environment.navigationHeight + 12.0 + + var profileLogoContents: [AnyComponentWithIdentity] = [] + profileLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.NameColor_AddProfileIcons, + font: Font.regular(presentationData.listsFontSize.baseDisplaySize), + textColor: environment.theme.list.itemPrimaryTextColor + )), + maximumNumberOfLines: 0 + )))) + let bannerSectionSize = self.bannerSection.update( + transition: sectionTransition, + 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)), + header: nil, + footer: nil, + items: [ + AnyComponentWithIdentity(id: 1, component: AnyComponent(ListItemComponentAdaptor( + itemGenerator: PeerNameColorItem( + theme: environment.theme, + colors: component.context.peerNameColors, + mode: .profile, + currentColor: resolvedState.profileColor, + updated: { [weak self] value in + guard let self, let value, let resolvedState = self.resolveState() else { + return + } + self.updatedPeerProfileColor = value + if case .starGift = resolvedState.emojiStatus?.content { + self.updatedPeerStatus = .some(nil) + } + self.state?.updated(transition: .spring(duration: 0.4)) + }, + sectionId: 0 + ), + params: listItemParams + ))), + AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( theme: environment.theme, - colors: component.context.peerNameColors, - mode: .profile, - currentColor: resolvedState.profileColor, - updated: { [weak self] value in - guard let self, let value, let resolvedState = self.resolveState() else { + title: AnyComponent(HStack(profileLogoContents, spacing: 6.0)), + icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( + context: component.context, + color: resolvedState.profileColor.flatMap { profileColor in + component.context.peerNameColors.getProfile(profileColor, dark: environment.theme.overallDarkAppearance, subject: .palette).main + } ?? environment.theme.list.itemAccentColor, + fileId: resolvedState.backgroundFileId, + file: resolvedState.backgroundFileId.flatMap { self.cachedIconFiles[$0] } + )))), + action: { [weak self] view in + guard let self, let resolvedState = self.resolveState(), let view = view as? ListActionItemComponent.View, let iconView = view.iconView else { return } - self.updatedPeerProfileColor = value + + self.openEmojiSetup(sourceView: iconView, currentFileId: resolvedState.backgroundFileId, color: resolvedState.profileColor.flatMap { + component.context.peerNameColors.getProfile($0, dark: environment.theme.overallDarkAppearance, subject: .palette).main + } ?? environment.theme.list.itemAccentColor, subject: .profile) + } + ))) + ], + displaySeparators: true, + extendsItemHighlightToSection: false + )), + 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) + } + sectionTransition.setFrame(view: bannerSectionView, frame: bannerSectionFrame) + } + contentHeight += bannerSectionSize.height + contentHeight += sectionSpacing + + let resetColorSectionSize = self.resetColorSection.update( + transition: sectionTransition, + component: AnyComponent(ListSectionComponent( + theme: environment.theme, + header: nil, + footer: nil, + items: [ + AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( + theme: environment.theme, + title: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.Channel_Appearance_ResetProfileColor, + font: Font.regular(presentationData.listsFontSize.baseDisplaySize), + textColor: environment.theme.list.itemAccentColor + )), + maximumNumberOfLines: 0 + )), + icon: nil, + accessory: nil, + action: { [weak self] view in + guard let self, let resolvedState = self.resolveState() else { + return + } + + self.updatedPeerProfileColor = .some(nil) + self.updatedPeerProfileEmoji = .some(nil) if case .starGift = resolvedState.emojiStatus?.content { self.updatedPeerStatus = .some(nil) } self.state?.updated(transition: .spring(duration: 0.4)) - }, - sectionId: 0 - ), - params: listItemParams - ))), - AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, - title: AnyComponent(HStack(profileLogoContents, spacing: 6.0)), - icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( - context: component.context, - color: resolvedState.profileColor.flatMap { profileColor in - component.context.peerNameColors.getProfile(profileColor, dark: environment.theme.overallDarkAppearance, subject: .palette).main - } ?? environment.theme.list.itemAccentColor, - fileId: resolvedState.backgroundFileId, - file: resolvedState.backgroundFileId.flatMap { self.cachedIconFiles[$0] } - )))), - action: { [weak self] view in - guard let self, let resolvedState = self.resolveState(), let view = view as? ListActionItemComponent.View, let iconView = view.iconView else { - return } - - self.openEmojiSetup(sourceView: iconView, currentFileId: resolvedState.backgroundFileId, color: resolvedState.profileColor.flatMap { - component.context.peerNameColors.getProfile($0, dark: environment.theme.overallDarkAppearance, subject: .palette).main - } ?? environment.theme.list.itemAccentColor, subject: .profile) - } - ))) - ], - displaySeparators: true, - extendsItemHighlightToSection: false - )), - 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) + ))) + ], + displaySeparators: false, + extendsItemHighlightToSection: true + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + ) + + var displayResetProfileColor = resolvedState.profileColor != nil || resolvedState.backgroundFileId != nil + if case .starGift = resolvedState.emojiStatus?.content { + displayResetProfileColor = true } - sectionTransition.setFrame(view: bannerSectionView, frame: bannerSectionFrame) - } - contentHeight += bannerSectionSize.height - contentHeight += sectionSpacing - - let resetColorSectionSize = self.resetColorSection.update( - transition: sectionTransition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - header: nil, - footer: nil, - items: [ - AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( + + 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) + } + 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) + } + if displayResetProfileColor { + contentHeight += resetColorSectionSize.height + contentHeight += sectionSpacing + } + + if !contentsData.gifts.isEmpty { + var selectedGiftId: Int64? + if let status = resolvedState.emojiStatus, case let .starGift(id, _, _, _, _, _, _, _, _) = status.content { + selectedGiftId = id + } + let giftsSectionSize = self.profileGiftsSection.update( + transition: sectionTransition, + component: AnyComponent(ListSectionComponent( theme: environment.theme, - title: AnyComponent(MultilineTextComponent( + header: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: environment.strings.Channel_Appearance_ResetProfileColor, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemAccentColor + string: environment.strings.NameColor_GiftTitle, + font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: environment.theme.list.freeTextColor )), maximumNumberOfLines: 0 )), - icon: nil, - accessory: nil, - action: { [weak self] view in - guard let self, let resolvedState = self.resolveState() else { - return - } - - self.updatedPeerProfileColor = .some(nil) - self.updatedPeerProfileEmoji = .some(nil) - if case .starGift = resolvedState.emojiStatus?.content { - self.updatedPeerStatus = .some(nil) - } - self.state?.updated(transition: .spring(duration: 0.4)) - } - ))) - ], - displaySeparators: false, - extendsItemHighlightToSection: true - )), - environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) - ) - - var displayResetProfileColor = resolvedState.profileColor != nil || resolvedState.backgroundFileId != nil - if case .starGift = resolvedState.emojiStatus?.content { - 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) - } - 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) - } - if displayResetProfileColor { - contentHeight += resetColorSectionSize.height - contentHeight += sectionSpacing - } - - var chatPreviewTheme: PresentationTheme = environment.theme - var chatPreviewWallpaper: TelegramWallpaper = presentationData.chatWallpaper - if let resolvedCurrentTheme = self.resolvedCurrentTheme { - chatPreviewTheme = resolvedCurrentTheme.theme - if let wallpaper = resolvedCurrentTheme.wallpaper { - chatPreviewWallpaper = wallpaper - } - } - - let messageItem = PeerNameColorChatPreviewItem.MessageItem( - outgoing: false, - peerId: EnginePeer.Id(namespace: peer.id.namespace, id: PeerId.Id._internalFromInt64Value(0)), - author: peer.compactDisplayTitle, - photo: peer.profileImageRepresentations, - nameColor: resolvedState.nameColor, - backgroundEmojiId: resolvedState.replyFileId, - reply: (peer.compactDisplayTitle, environment.strings.NameColor_ChatPreview_ReplyText_Account, resolvedState.nameColor), - linkPreview: (environment.strings.NameColor_ChatPreview_LinkSite, environment.strings.NameColor_ChatPreview_LinkTitle, environment.strings.NameColor_ChatPreview_LinkText), - text: environment.strings.NameColor_ChatPreview_MessageText_Account - ) - - var replyLogoContents: [AnyComponentWithIdentity] = [] - replyLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.NameColor_AddRepliesIcons, - font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor - )), - maximumNumberOfLines: 0 - )))) - let replySectionSize = self.replySection.update( - transition: sectionTransition, - component: AnyComponent(ListSectionComponent( - theme: environment.theme, - header: nil, - footer: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.NameColor_ChatPreview_Description_Account, - font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), - textColor: environment.theme.list.freeTextColor + footer: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.NameColor_GiftInfo, + font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: environment.theme.list.freeTextColor + )), + maximumNumberOfLines: 0 + )), + items: [ + AnyComponentWithIdentity(id: 0, component: AnyComponent( + GiftListItemComponent( + context: component.context, + theme: environment.theme, + gifts: contentsData.gifts, + selectedId: selectedGiftId, + selectionUpdated: { [weak self] gift in + guard let self else { + return + } + var fileId: Int64? + var patternFileId: Int64? + var innerColor: Int32? + var outerColor: Int32? + var patternColor: Int32? + var textColor: Int32? + for attribute in gift.attributes { + switch attribute { + case let .model(_, file, _): + fileId = file.fileId.id + self.cachedIconFiles[file.fileId.id] = file + case let .pattern(_, file, _): + patternFileId = file.fileId.id + self.cachedIconFiles[file.fileId.id] = file + case let .backdrop(_, _, innerColorValue, outerColorValue, patternColorValue, textColorValue, _): + innerColor = innerColorValue + outerColor = outerColorValue + patternColor = patternColorValue + textColor = textColorValue + default: + break + } + } + if let fileId, let patternFileId, let innerColor, let outerColor, let patternColor, let textColor { + self.updatedPeerProfileColor = .some(nil) + self.updatedPeerProfileEmoji = .some(nil) + self.updatedPeerStatus = .some(PeerEmojiStatus(content: .starGift(id: gift.id, fileId: fileId, title: gift.title, slug: gift.slug, patternFileId: patternFileId, innerColor: innerColor, outerColor: outerColor, patternColor: patternColor, textColor: textColor), expirationDate: nil)) + self.state?.updated(transition: .spring(duration: 0.4)) + } + }, + tag: giftListTag + ) + )), + ], + displaySeparators: false )), - maximumNumberOfLines: 0 + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0) + ) + let giftsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: giftsSectionSize) + if let giftsSectionView = self.profileGiftsSection.view { + if giftsSectionView.superview == nil { + self.scrollView.addSubview(giftsSectionView) + } + sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) + } + contentHeight += giftsSectionSize.height + contentHeight += sectionSpacing + } + case .name: + if let previewSectionView = self.previewSection.view, previewSectionView.superview != nil { + previewSectionView.removeFromSuperview() + } + if let bannerSectionView = self.bannerSection.view, bannerSectionView.superview != nil { + bannerSectionView.removeFromSuperview() + } + if let resetColorSectionView = self.resetColorSection.view, resetColorSectionView.superview != nil { + resetColorSectionView.removeFromSuperview() + } + if let profileGiftsSectionView = self.profileGiftsSection.view, profileGiftsSectionView.superview != nil { + profileGiftsSectionView.removeFromSuperview() + } + + var chatPreviewTheme: PresentationTheme = environment.theme + var chatPreviewWallpaper: TelegramWallpaper = presentationData.chatWallpaper + if let resolvedCurrentTheme = self.resolvedCurrentTheme { + chatPreviewTheme = resolvedCurrentTheme.theme + if let wallpaper = resolvedCurrentTheme.wallpaper { + chatPreviewWallpaper = wallpaper + } + } + + let messageItem = PeerNameColorChatPreviewItem.MessageItem( + outgoing: false, + peerId: EnginePeer.Id(namespace: peer.id.namespace, id: PeerId.Id._internalFromInt64Value(0)), + author: peer.compactDisplayTitle, + photo: peer.profileImageRepresentations, + nameColor: resolvedState.nameColor, + backgroundEmojiId: resolvedState.replyFileId, + reply: (peer.compactDisplayTitle, environment.strings.NameColor_ChatPreview_ReplyText_Account, resolvedState.nameColor), + linkPreview: (environment.strings.NameColor_ChatPreview_LinkSite, environment.strings.NameColor_ChatPreview_LinkTitle, environment.strings.NameColor_ChatPreview_LinkText), + text: environment.strings.NameColor_ChatPreview_MessageText_Account + ) + + var replyLogoContents: [AnyComponentWithIdentity] = [] + replyLogoContents.append(AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.NameColor_AddRepliesIcons, + font: Font.regular(presentationData.listsFontSize.baseDisplaySize), + textColor: environment.theme.list.itemPrimaryTextColor )), - 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, - updated: { [weak self] value in - guard let self, let value else { - return - } - self.updatedPeerNameColor = value - self.state?.updated(transition: .spring(duration: 0.4)) - }, - sectionId: 0 - ), - params: listItemParams - ))), - AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, - title: AnyComponent(HStack(replyLogoContents, spacing: 6.0)), - icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( - context: component.context, - color: component.context.peerNameColors.get(resolvedState.nameColor, dark: environment.theme.overallDarkAppearance).main, - fileId: resolvedState.replyFileId, - file: resolvedState.replyFileId.flatMap { self.cachedIconFiles[$0] } - )))), - action: { [weak self] view in - guard let self, let resolvedState = self.resolveState(), let view = view as? ListActionItemComponent.View, let iconView = view.iconView else { - return - } - - self.openEmojiSetup(sourceView: iconView, currentFileId: resolvedState.replyFileId, color: component.context.peerNameColors.get(resolvedState.nameColor, dark: environment.theme.overallDarkAppearance).main, subject: .reply) - } - ))) - ], - displaySeparators: true, - extendsItemHighlightToSection: false - )), - 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) + maximumNumberOfLines: 0 + )))) + + + var replyColor: UIColor + switch resolvedState.nameColor { + case let .preset(nameColor): + replyColor = component.context.peerNameColors.get(nameColor, dark: environment.theme.overallDarkAppearance).main + case let .collectible(collectibleColor): + replyColor = collectibleColor.mainColor(dark: environment.theme.overallDarkAppearance) } - sectionTransition.setFrame(view: replySectionView, frame: replySectionFrame) - } - contentHeight += replySectionSize.height - contentHeight += sectionSpacing - - if !contentsData.gifts.isEmpty { - var selectedGiftId: Int64? - if let status = resolvedState.emojiStatus, case let .starGift(id, _, _, _, _, _, _, _, _) = status.content { - selectedGiftId = id - } - let giftsSectionSize = self.giftsSection.update( + + let replySectionSize = self.replySection.update( transition: sectionTransition, component: AnyComponent(ListSectionComponent( theme: environment.theme, - header: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString( - string: environment.strings.NameColor_GiftTitle, - font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), - textColor: environment.theme.list.freeTextColor - )), - maximumNumberOfLines: 0 - )), + header: nil, footer: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: environment.strings.NameColor_GiftInfo, + string: environment.strings.NameColor_ChatPreview_Description_Account, font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), textColor: environment.theme.list.freeTextColor )), maximumNumberOfLines: 0 )), items: [ - AnyComponentWithIdentity(id: 0, component: AnyComponent( - GiftListItemComponent( + 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, - gifts: contentsData.gifts, - selectedId: selectedGiftId, - selectionUpdated: { [weak self] gift in - guard let self else { + colors: component.context.peerNameColors, + mode: .name, + currentColor: resolvedState.nameColor.nameColor, + updated: { [weak self] value in + guard let self, let value else { return } - var fileId: Int64? - var patternFileId: Int64? - var innerColor: Int32? - var outerColor: Int32? - var patternColor: Int32? - var textColor: Int32? - for attribute in gift.attributes { - switch attribute { - case let .model(_, file, _): - fileId = file.fileId.id - self.cachedIconFiles[file.fileId.id] = file - case let .pattern(_, file, _): - patternFileId = file.fileId.id - self.cachedIconFiles[file.fileId.id] = file - case let .backdrop(_, _, innerColorValue, outerColorValue, patternColorValue, textColorValue, _): - innerColor = innerColorValue - outerColor = outerColorValue - patternColor = patternColorValue - textColor = textColorValue - default: - break - } - } - if let fileId, let patternFileId, let innerColor, let outerColor, let patternColor, let textColor { - self.updatedPeerProfileColor = .some(nil) - self.updatedPeerProfileEmoji = .some(nil) - self.updatedPeerStatus = .some(PeerEmojiStatus(content: .starGift(id: gift.id, fileId: fileId, title: gift.title, slug: gift.slug, patternFileId: patternFileId, innerColor: innerColor, outerColor: outerColor, patternColor: patternColor, textColor: textColor), expirationDate: nil)) - self.state?.updated(transition: .spring(duration: 0.4)) - } + self.updatedPeerNameColor = .preset(value) + self.state?.updated(transition: .spring(duration: 0.4)) }, - tag: giftListTag - ) - )), + sectionId: 0 + ), + params: listItemParams + ))), + AnyComponentWithIdentity(id: 2, component: AnyComponent(ListActionItemComponent( + theme: environment.theme, + title: AnyComponent(HStack(replyLogoContents, spacing: 6.0)), + icon: ListActionItemComponent.Icon(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(EmojiActionIconComponent( + context: component.context, + color: replyColor, + fileId: resolvedState.replyFileId, + file: resolvedState.replyFileId.flatMap { self.cachedIconFiles[$0] } + )))), + action: { [weak self] view in + guard let self, let resolvedState = self.resolveState(), let view = view as? ListActionItemComponent.View, let iconView = view.iconView else { + return + } + + self.openEmojiSetup(sourceView: iconView, currentFileId: resolvedState.replyFileId, color: replyColor, subject: .reply) + } + ))) ], - displaySeparators: false + displaySeparators: true, + extendsItemHighlightToSection: false )), environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0) + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) ) - let giftsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: giftsSectionSize) - if let giftsSectionView = self.giftsSection.view { - if giftsSectionView.superview == nil { - self.scrollView.addSubview(giftsSectionView) + 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) } - sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) + sectionTransition.setFrame(view: replySectionView, frame: replySectionFrame) } - contentHeight += giftsSectionSize.height + contentHeight += replySectionSize.height contentHeight += sectionSpacing + + if !self.starGifts.isEmpty { + var selectedGiftId: Int64? + if case let .collectible(collectibleColor) = resolvedState.nameColor { + selectedGiftId = collectibleColor.collectibleId + } + let giftsSectionSize = self.nameGiftsSection.update( + transition: sectionTransition, + component: AnyComponent(ListSectionComponent( + theme: environment.theme, + header: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.NameColor_GiftTitle, + font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: environment.theme.list.freeTextColor + )), + maximumNumberOfLines: 0 + )), + footer: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString( + string: environment.strings.NameColor_GiftInfo, + font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), + textColor: environment.theme.list.freeTextColor + )), + maximumNumberOfLines: 0 + )), + items: [ + AnyComponentWithIdentity(id: 0, component: AnyComponent( + GiftListItemComponent( + context: component.context, + theme: environment.theme, + gifts: self.starGifts, + selectedId: selectedGiftId, + selectionUpdated: { [weak self] gift in + guard let self, let peerColor = gift.peerColor else { + return + } + + self.updatedPeerNameColor = .collectible(peerColor) + self.state?.updated(transition: .spring(duration: 0.4)) + }, + tag: giftListTag + ) + )), + ], + displaySeparators: false + )), + environment: {}, + containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0) + ) + let giftsSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: giftsSectionSize) + if let giftsSectionView = self.nameGiftsSection.view { + if giftsSectionView.superview == nil { + self.scrollView.addSubview(giftsSectionView) + } + sectionTransition.setFrame(view: giftsSectionView, frame: giftsSectionFrame) + } + contentHeight += giftsSectionSize.height + contentHeight += sectionSpacing + } } - + contentHeight += bottomContentInset var buttonTitle = environment.strings.Channel_Appearance_ApplyButton @@ -1310,3 +1483,14 @@ public class UserAppearanceScreen: ViewControllerComponentContainer { } } } + +private extension PeerColor { + var nameColor: PeerNameColor? { + switch self { + case let .preset(nameColor): + return nameColor + default: + return nil + } + } +} diff --git a/submodules/TelegramUI/Components/Settings/QuickReactionSetupController/Sources/ReactionChatPreviewItem.swift b/submodules/TelegramUI/Components/Settings/QuickReactionSetupController/Sources/ReactionChatPreviewItem.swift index 301cbe8927..f4691ae880 100644 --- a/submodules/TelegramUI/Components/Settings/QuickReactionSetupController/Sources/ReactionChatPreviewItem.swift +++ b/submodules/TelegramUI/Components/Settings/QuickReactionSetupController/Sources/ReactionChatPreviewItem.swift @@ -304,7 +304,7 @@ class ReactionChatPreviewItemNode: ListViewItemNode { var peers = SimpleDictionary() let messages = SimpleDictionary() - peers[userPeerId] = TelegramUser(id: userPeerId, accessHash: nil, firstName: item.strings.Settings_QuickReactionSetup_DemoMessageAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[userPeerId] = TelegramUser(id: userPeerId, accessHash: nil, firstName: item.strings.Settings_QuickReactionSetup_DemoMessageAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) let messageText = item.strings.Settings_QuickReactionSetup_DemoMessageText diff --git a/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift b/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift index d1b3fb04d6..9f7668774b 100644 --- a/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift +++ b/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift @@ -1053,8 +1053,8 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, ASScrollViewDelegate let otherPeerId = self.context.account.peerId var peers = SimpleDictionary() var messages = SimpleDictionary() - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) - peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + peers[otherPeerId] = TelegramUser(id: otherPeerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) var sampleMessages: [Message] = [] diff --git a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryItem.swift b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryItem.swift index 5201e1ced0..8934df1050 100644 --- a/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryItem.swift +++ b/submodules/TelegramUI/Components/Settings/WallpaperGalleryScreen/Sources/WallpaperGalleryItem.swift @@ -1513,8 +1513,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode { let replyAuthor = self.presentationData.strings.Appearance_ThemePreview_Chat_2_ReplyName - var messageAuthor: Peer = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) - let otherAuthor = TelegramUser(id: otherPeerId, accessHash: nil, firstName: replyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + var messageAuthor: Peer = TelegramUser(id: peerId, accessHash: nil, firstName: self.presentationData.strings.Appearance_PreviewReplyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + let otherAuthor = TelegramUser(id: otherPeerId, accessHash: nil, firstName: replyAuthor, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) peers[otherPeerId] = otherAuthor var messageAttributes: [MessageAttribute] = [] diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContentCaptionComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContentCaptionComponent.swift index 2bfde6f260..0a40d81eb6 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContentCaptionComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContentCaptionComponent.swift @@ -616,7 +616,13 @@ final class StoryContentCaptionComponent: Component { var baseQuoteSecondaryTintColor: UIColor? var baseQuoteTertiaryTintColor: UIColor? if let nameColor = component.author.nameColor { - let resolvedColor = component.context.peerNameColors.get(nameColor) + let resolvedColor: PeerNameColors.Colors + switch nameColor { + case let .preset(nameColor): + resolvedColor = component.context.peerNameColors.get(nameColor) + case let .collectible(collectibleColor): + resolvedColor = collectibleColor.peerNameColors(dark: false) + } if resolvedColor.secondary != nil { baseQuoteSecondaryTintColor = .clear } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index e0d412926b..7f5082fe31 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4643,8 +4643,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } let controller = PremiumIntroScreen(context: self.context, source: source) controller.sourceView = sourceView - controller.containerView = self.navigationController?.view - controller.animationColor = self.context.peerNameColors.get(nameColor, dark: self.presentationData.theme.overallDarkAppearance).main + controller.containerView = self.navigationController?.view + let animationColor: UIColor + switch nameColor { + case let .preset(nameColor): + animationColor = self.context.peerNameColors.get(nameColor, dark: self.presentationData.theme.overallDarkAppearance).main + case let .collectible(collectibleColor): + animationColor = collectibleColor.mainColor(dark: self.presentationData.theme.overallDarkAppearance) + } + controller.animationColor = animationColor self.push(controller) }) @@ -5535,7 +5542,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G guard let self, let accountPeer, let chatPeer else { return } - var nameColor: PeerNameColor? + var nameColor: PeerColor? if case let .channel(channel) = chatPeer, case .broadcast = channel.info { nameColor = chatPeer.nameColor } else { @@ -5543,7 +5550,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } var accountPeerColor: ChatPresentationInterfaceState.AccountPeerColor? if let nameColor { - let colors = self.context.peerNameColors.get(nameColor) + let colors: PeerNameColors.Colors + switch nameColor { + case let .preset(nameColor): + colors = self.context.peerNameColors.get(nameColor) + case let .collectible(collectibleColor): + colors = collectibleColor.peerNameColors(dark: false) + } var style: ChatPresentationInterfaceState.AccountPeerColor.Style = .solid if colors.tertiary != nil { style = .tripleDashed diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 32e661f07c..d929b56901 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -613,7 +613,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { let author: Peer if link.isCentered { - author = TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) + author = TelegramUser(id: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "FirstName", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .preset(.blue), backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil, subscriberCount: nil, verificationIconFileId: nil) } else { author = accountPeer }