diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 15a4b50bfe..13fe96953c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10150,11 +10150,15 @@ Sorry for the inconvenience."; "NameColor.UnsavedChanges.Discard" = "Discard"; "NameColor.UnsavedChanges.Apply" = "Apply"; +"NameColor.YourColorUpdated" = "Your name color has been updated."; +"NameColor.ChannelColorUpdated" = "Channel name color has been updated."; + "Chat.ErrorQuoteOutdatedTitle" = "Quote Outdated"; "Chat.ErrorQuoteOutdatedText" = "**%@** updated the message you are quoting. Edit your quote to make it up-to-date."; "Chat.ErrorQuoteOutdatedActionEdit" = "Edit"; "Premium.BoostByGiftDescription" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()"; +"Premium.BoostByGiftDescription2" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()"; "ChatContextMenu.QuoteSelectionTip" = "Hold on a word, then move cursor to select more| text to quote."; @@ -10413,3 +10417,5 @@ Sorry for the inconvenience."; "ChannelBoost.BoostAgain" = "Boost Again"; "Settings.New" = "NEW"; + +"ChannelBoost.Or" = "or"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 0cf6554a85..d0c1925ae3 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -968,6 +968,7 @@ public enum PremiumIntroSource { case storiesExpirationDurations case storiesSuggestedReactions case channelBoost(EnginePeer.Id) + case nameColor } public enum PremiumDemoSubject { diff --git a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift index 3547991b3a..1fe350d102 100644 --- a/submodules/PremiumUI/Sources/PremiumBoostScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumBoostScreen.swift @@ -175,23 +175,42 @@ public func PremiumBoostScreen( replaceController?.dismiss(animated: true) } } else if let boost = occupiedBoosts.first, let occupiedPeer = boost.peer { - let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: { - currentMyBoostCount += 1 - myBoostCount += 1 - let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot]) - |> deliverOnMainQueue).startStandalone(completed: { [weak controller] in - let _ = (updatedState.get() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { [weak controller] state in - guard let state else { - return - } - let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount) - controller?.updateSubject(subject, count: count) + if let cooldown = boost.cooldownUntil { + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + let timeout = cooldown - currentTime + let valueText = timeIntervalString(strings: presentationData.strings, value: timeout, usage: .afterTime, preferLowerValue: false) + let controller = textAlertController( + sharedContext: context.sharedContext, + updatedPresentationData: nil, + title: presentationData.strings.ChannelBoost_Error_BoostTooOftenTitle, + text: presentationData.strings.ChannelBoost_Error_BoostTooOftenText(valueText).string, + actions: [ + TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}) + ], + parseMarkdown: true + ) + presentController(controller) + } else { + let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: { + currentMyBoostCount += 1 + myBoostCount += 1 + let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot]) + |> deliverOnMainQueue).startStandalone(completed: { [weak controller] in + let _ = (updatedState.get() + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { [weak controller] state in + guard let state else { + return + } + let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount) + controller?.updateSubject(subject, count: count) + }) }) }) - }) - presentController(replaceController) + presentController(replaceController) + } + } else { + dismissImpl?() } } else { if isPremium { diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index ee8b744723..c206fedf59 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -233,6 +233,12 @@ public enum PremiumSource: Equatable { } else { return false } + case .nameColor: + if case .nameColor = rhs { + return true + } else { + return false + } } } @@ -270,6 +276,7 @@ public enum PremiumSource: Equatable { case storiesExpirationDurations case storiesSuggestedReactions case channelBoost(EnginePeer.Id) + case nameColor var identifier: String? { switch self { @@ -343,6 +350,8 @@ public enum PremiumSource: Equatable { return "stories__suggested_reactions" case let .channelBoost(peerId): return "channel_boost__\(peerId.id._internalGetInt64Value())" + case .nameColor: + return "name_color" } } } diff --git a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift index 653321026c..1fd9ad03ff 100644 --- a/submodules/PremiumUI/Sources/PremiumLimitScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumLimitScreen.swift @@ -1541,7 +1541,7 @@ private final class LimitSheetContent: CombinedComponent { var additionalContentHeight: CGFloat = 0.0 if case let .storiesChannelBoost(_, _, _, _, _, _, link, _, _) = component.subject, link != nil, let openGift = component.openGift { let orText = orText.update( - component: MultilineTextComponent(text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))), + component: MultilineTextComponent(text: .plain(NSAttributedString(string: environment.strings.ChannelBoost_Or, font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height), transition: .immediate ) @@ -1571,7 +1571,7 @@ private final class LimitSheetContent: CombinedComponent { state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, environment.theme) } - let giftString = environment.strings.Premium_BoostByGiftDescription + let giftString = environment.strings.Premium_BoostByGiftDescription2 let giftAttributedString = parseMarkdownIntoAttributedString(giftString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 { diff --git a/submodules/SettingsUI/Sources/ThemePickerController.swift b/submodules/SettingsUI/Sources/ThemePickerController.swift index 5ee5b81628..ea45e2a190 100644 --- a/submodules/SettingsUI/Sources/ThemePickerController.swift +++ b/submodules/SettingsUI/Sources/ThemePickerController.swift @@ -289,7 +289,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), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)])) + 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)])) 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 c4513612c6..c840a41700 100644 --- a/submodules/SettingsUI/Sources/Themes/EditThemeController.swift +++ b/submodules/SettingsUI/Sources/Themes/EditThemeController.swift @@ -283,7 +283,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), ChatPreviewMessageItem(outgoing: true, reply: nil, text: previewOutgoingText)])) + 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(.changeColors(presentationData.theme, presentationData.strings.EditTheme_ChangeColors)) if hasSettings { diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift index a329a970dc..fc90663f4d 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsChatPreviewItem.swift @@ -25,12 +25,20 @@ struct ChatPreviewMessageItem: Equatable { if lhs.text != rhs.text { return false } + if lhs.nameColor != rhs.nameColor { + return false + } + if lhs.backgroundEmojiId != rhs.backgroundEmojiId { + return false + } return true } let outgoing: Bool let reply: (String, String)? let text: String + let nameColor: PeerNameColor + let backgroundEmojiId: Int64? } class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem { @@ -155,7 +163,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode { let replyMessageId = MessageId(peerId: peerId, namespace: 0, id: 3) if let (author, text) = messageItem.reply { - peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: author, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: .blue, backgroundEmojiId: nil) + peers[peerId] = TelegramUser(id: peerId, accessHash: nil, firstName: author, lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: messageItem.nameColor, backgroundEmojiId: messageItem.backgroundEmojiId) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) } diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 81a873fc87..764e2e6c2b 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -375,16 +375,26 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, let strings = presentationData.strings let title = presentationData.autoNightModeTriggered ? strings.Appearance_ColorThemeNight.uppercased() : strings.Appearance_ColorTheme.uppercased() entries.append(.themeListHeader(presentationData.theme, title)) - 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), ChatPreviewMessageItem(outgoing: true, reply: nil, text: presentationData.strings.Appearance_PreviewOutgoingText)])) + + let nameColor: PeerNameColor + var authorName = presentationData.strings.Appearance_PreviewReplyAuthor + if let accountPeer { + nameColor = accountPeer.nameColor ?? .blue + if accountPeer._asPeer().hasCustomNameColor { + authorName = accountPeer.displayTitle(strings: strings, displayOrder: presentationData.nameDisplayOrder) + } + } else { + nameColor = .blue + } + + 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(.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)) - if let accountPeer { - let colors = nameColors.get(accountPeer.nameColor ?? .blue) - entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer.compactDisplayTitle, colors.main)) - } + let colors = nameColors.get(nameColor) + entries.append(.nameColor(presentationData.theme, strings.Appearance_NameColor, accountPeer?.compactDisplayTitle ?? "", colors.main)) entries.append(.autoNight(presentationData.theme, strings.Appearance_NightTheme, presentationThemeSettings.automaticThemeSwitchSetting.force, !presentationData.autoNightModeTriggered || presentationThemeSettings.automaticThemeSwitchSetting.force)) let autoNightMode: String diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 9f775e82cd..11d20ef720 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -236,6 +236,14 @@ public extension Peer { } } + var hasCustomNameColor: Bool { + let defaultNameColor = PeerNameColor(rawValue: Int32(self.id.id._internalGetInt64Value() % 7)) + if self.nameColor != defaultNameColor { + return true + } + return false + } + var backgroundEmojiId: Int64? { switch self { case let user as TelegramUser: diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift index edbd18161b..526ec4b719 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorItem.swift @@ -125,12 +125,12 @@ private func generateRingImage(nameColor: PeerNameColors.Colors) -> UIImage? { }) } -private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? { - return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in - let bounds = CGRect(origin: CGPoint(), size: size) +func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? { + return generateImage(bounds, rotatedContext: { contextSize, context in + let bounds = CGRect(origin: CGPoint(), size: contextSize) context.clear(bounds) - let circleBounds = bounds + let circleBounds = CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - size.width) / 2.0), y: floorToScreenPixels((bounds.height - size.height) / 2.0)), size: size) context.addEllipse(in: circleBounds) context.clip() @@ -139,24 +139,26 @@ private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? { context.fill(circleBounds) if let thirdColor = nameColor.tertiary { - context.move(to: CGPoint(x: size.width, y: 0.0)) - context.addLine(to: CGPoint(x: size.width, y: size.height)) - context.addLine(to: CGPoint(x: 0.0, y: size.height)) + context.move(to: CGPoint(x: contextSize.width, y: 0.0)) + context.addLine(to: CGPoint(x: contextSize.width, y: contextSize.height)) + context.addLine(to: CGPoint(x: 0.0, y: contextSize.height)) context.closePath() context.setFillColor(nameColor.main.cgColor) context.fillPath() context.setFillColor(thirdColor.cgColor) - context.translateBy(x: size.width / 2.0, y: size.height / 2.0) + context.translateBy(x: contextSize.width / 2.0, y: contextSize.height / 2.0) context.rotate(by: .pi / 4.0) - let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -9.0, y: -9.0), size: CGSize(width: 18.0, height: 18.0)), cornerRadius: 4.0) + let rectSide = size.width / 40.0 * 18.0 + let rectCornerRadius = round(size.width / 40.0 * 4.0) + let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -rectSide / 2.0, y: -rectSide / 2.0), size: CGSize(width: rectSide, height: rectSide)), cornerRadius: rectCornerRadius) context.addPath(path.cgPath) context.fillPath() } else { context.move(to: .zero) - context.addLine(to: CGPoint(x: size.width, y: 0.0)) - context.addLine(to: CGPoint(x: 0.0, y: size.height)) + context.addLine(to: CGPoint(x: contextSize.width, y: 0.0)) + context.addLine(to: CGPoint(x: 0.0, y: contextSize.height)) context.closePath() context.setFillColor(nameColor.main.cgColor) context.fillPath() @@ -230,7 +232,7 @@ private final class PeerNameColorIconItemNode : ListViewItemNode { strongSelf.item = item if updatedAccentColor { - strongSelf.fillNode.image = generateFillImage(nameColor: item.colors) + strongSelf.fillNode.image = generatePeerNameColorImage(nameColor: item.colors) strongSelf.ringNode.image = generateRingImage(nameColor: item.colors) } @@ -523,9 +525,9 @@ final class PeerNameColorItemNode: ListViewItemNode, ItemListItemNode { var i: Int = 0 for index in item.colors.displayOrder { let color = PeerNameColor(rawValue: index) - if let colors = item.colors.colors[index] { - entries.append(.color(i, color, colors, color == item.currentColor)) - } + let colors = item.colors.get(color, dark: item.theme.overallDarkAppearance) + entries.append(.color(i, color, colors, color == item.currentColor)) + i += 1 } diff --git a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift index 46dc8f2cf4..62e04985d5 100644 --- a/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift +++ b/submodules/TelegramUI/Components/Settings/PeerNameColorScreen/Sources/PeerNameColorScreen.swift @@ -280,6 +280,8 @@ public func PeerNameColorScreen( statePromise.set(stateValue.modify { f($0) }) } + let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + var presentImpl: ((ViewController) -> Void)? var pushImpl: ((ViewController) -> Void)? var dismissImpl: (() -> Void)? @@ -416,7 +418,7 @@ public func PeerNameColorScreen( elevatedLayout: false, action: { action in if case .info = action { - let controller = context.sharedContext.makePremiumIntroController(context: context, source: .storiesSuggestedReactions, forceDark: false, dismissed: nil) + let controller = context.sharedContext.makePremiumIntroController(context: context, source: .nameColor, forceDark: false, dismissed: nil) pushImpl?(controller) } return true @@ -550,7 +552,7 @@ public func PeerNameColorScreen( return attemptNavigationImpl?(f) ?? true } attemptNavigationImpl = { f in - if !context.isPremium { + if case .account = subject, !context.isPremium { f() return true } @@ -576,20 +578,33 @@ public func PeerNameColorScreen( return true } } - applyChangesImpl = { + applyChangesImpl = { [weak controller] in let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) |> deliverOnMainQueue).startStandalone(next: { peer in guard let peer else { return } let state = stateValue.with { $0 } + + let presentationData = context.sharedContext.currentPresentationData.with { $0 } let nameColor = state.updatedNameColor ?? peer.nameColor let backgroundEmojiId = state.updatedBackgroundEmojiId ?? peer.backgroundEmojiId + let colors = context.peerNameColors.get(nameColor ?? .blue, dark: presentationData.theme.overallDarkAppearance) switch subject { case .account: let _ = context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone() + + if let navigationController = controller?.navigationController as? NavigationController { + Queue.mainQueue().after(0.25) { + if let lastController = navigationController.viewControllers.last as? ViewController { + let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_YourColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }) + lastController.present(tipController, in: .window(.root)) + } + } + } + dismissImpl?() case let .channel(peerId): updateState { state in @@ -616,10 +631,10 @@ public func PeerNameColorScreen( let presentationData = context.sharedContext.currentPresentationData.with { $0 } presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })) return true - }, openStats: nil, openGift: { + }, openStats: nil, openGift: premiumConfiguration.giveawayGiftsPurchaseAvailable ? { let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic) pushImpl?(controller) - }) + } : nil) pushImpl?(controller) HapticFeedback().impact(.light) @@ -633,6 +648,15 @@ public func PeerNameColorScreen( return updatedState } }, completed: { + if let navigationController = controller?.navigationController as? NavigationController { + Queue.mainQueue().after(0.25) { + if let lastController = navigationController.viewControllers.last as? ViewController { + let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_ChannelColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }) + lastController.present(tipController, in: .window(.root)) + } + } + } + dismissImpl?() }) } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index 7f2e080d87..971f2684e8 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -514,7 +514,7 @@ private final class StoryContainerScreenComponent: Component { var apply = true let currentTime = CACurrentMediaTime() - if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.1 { + if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.15 { apply = false } if apply { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index 65d7a6cff0..e3d60a10fb 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -496,7 +496,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, let botsKey = ValueBoxKey(length: 8) botsKey.setInt64(0, value: 0) - var iconLoaded: [EnginePeer.Id: Bool] = [:] + let iconLoaded = Atomic<[EnginePeer.Id: Bool]>(value: [:]) let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey)) |> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? [] @@ -512,7 +512,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, if let peer = PeerReference(peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] { let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon) let signal: Signal - if let _ = iconLoaded[peer.id] { + if let _ = iconLoaded.with({ $0 })[peer.id] { signal = .single(resultBot) } else { signal = .single(nil) @@ -523,7 +523,11 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, return resultBot } |> afterNext { _ in - iconLoaded[peer.id] = true + let _ = iconLoaded.modify { current in + var updated = current + updated[peer.id] = true + return updated + } } ) } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index c76958656d..47c7f92c61 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1744,6 +1744,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { mappedSource = .storiesSuggestedReactions case let .channelBoost(peerId): mappedSource = .channelBoost(peerId) + case .nameColor: + mappedSource = .nameColor } let controller = PremiumIntroScreen(context: context, source: mappedSource, forceDark: forceDark) controller.wasDismissed = dismissed