diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index b11c70abfb..dfb1db1922 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -13611,6 +13611,29 @@ Sorry for the inconvenience."; "Gift.View.Self.Title" = "Saved Gift"; "Gift.View.Self.Description" = "You can display this gift on your page or turn it into a unique collectible and send to others."; +"BotVerification.Verify.Placeholder" = "This page is verified by %@"; + +"BotVerification.Verify.Channel.Title" = "Verify Channel"; +"BotVerification.Verify.Channel.Text" = "Do you want to verify this channel with your verification mark and description?"; +"BotVerification.Verify.Group.Title" = "Verify Group"; +"BotVerification.Verify.Group.Text" = "Do you want to verify this group with your verification mark and description?"; +"BotVerification.Verify.User.Title" = "Verify Bot"; +"BotVerification.Verify.User.Text" = "Do you want to verify this user with your verification mark and description?"; +"BotVerification.Verify.Bot.Title" = "Verify Bot"; +"BotVerification.Verify.Bot.Text" = "Do you want to verify this bot with your verification mark and description?"; + +"BotVerification.Verify.Verify" = "Verify"; + +"BotVerification.Remove.Title" = "Remove Verification"; +"BotVerification.Remove.Channel.Text" = "This channel is already verified by you. Do you want to remove verification?"; +"BotVerification.Remove.Group.Text" = "This group is already verified by you. Do you want to remove verification?"; +"BotVerification.Remove.User.Text" = "This user is already verified by you. Do you want to remove verification?"; +"BotVerification.Remove.Bot.Text" = "This bot is already verified by you. Do you want to remove verification?"; +"BotVerification.Remove.Remove" = "Remove"; + "BotVerification.ChooseChat" = "Choose Chat to Verify"; "BotVerification.Added" = "**%@** has been notified and will receive your verification mark and description upon accepting."; "BotVerification.Removed" = "You have removed **%@'s** verification."; + +"Premium.Gift.ContactSelection.ThisIsYou" = "THIS IS YOU"; +"Premium.Gift.ContactSelection.BuySelf" = "buy yourself a gift"; diff --git a/submodules/ContactListUI/Sources/ContactListNode.swift b/submodules/ContactListUI/Sources/ContactListNode.swift index bee75c0ea5..65fe2836a5 100644 --- a/submodules/ContactListUI/Sources/ContactListNode.swift +++ b/submodules/ContactListUI/Sources/ContactListNode.swift @@ -98,7 +98,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { case permissionInfo(PresentationTheme, String, String, Bool) case permissionEnable(PresentationTheme, String) case option(Int, ContactListAdditionalOption, ListViewItemHeader?, PresentationTheme, PresentationStrings) - case peer(Int, ContactListPeer, EnginePeer.Presence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool, Bool, Bool, StoryData?, Bool) + case peer(Int, ContactListPeer, EnginePeer.Presence?, ListViewItemHeader?, ContactsPeerItemSelection, PresentationTheme, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, PresentationPersonNameOrder, Bool, Bool, Bool, StoryData?, Bool, String?) var stableId: ContactListNodeEntryId { switch self { @@ -112,7 +112,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { return .permission(action: true) case let .option(index, _, _, _, _): return .option(index: index) - case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, storyData, _): + case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _, _, storyData, _, _): switch peer { case let .peer(peer, _, _): return .peerId(peerId: peer.id.toInt64(), section: storyData != nil ? .stories : .contacts) @@ -152,7 +152,7 @@ private enum ContactListNodeEntry: Comparable, Identifiable { style = .generic } return ContactListActionItem(presentationData: ItemListPresentationData(presentationData), title: option.title, subtitle: option.subtitle, icon: option.icon, style: style, clearHighlightAutomatically: option.clearHighlightAutomatically, header: header, action: option.action) - case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, hasMoreButton, enabled, storyData, requiresPremiumForMessaging): + case let .peer(_, peer, presence, header, selection, _, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, displayCallIcons, hasMoreButton, enabled, storyData, requiresPremiumForMessaging, customSubtitle): var status: ContactsPeerItemStatus let itemPeer: ContactsPeerItemPeer var isContextActionEnabled = false @@ -221,8 +221,11 @@ private enum ContactListNodeEntry: Comparable, Identifiable { })] } + var storyStats: (total: Int, unseen: Int, hasUnseenCloseFriends: Bool)? - if let storyData = storyData { + if let customSubtitle { + status = .custom(string: NSAttributedString(string: customSubtitle), multiline: false, isActive: false, icon: nil) + } else if let storyData { storyStats = (storyData.count, storyData.unseenCount, storyData.hasUnseenCloseFriends) let text: String @@ -276,9 +279,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable { } else { return false } - case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsDisplayCallIcons, lhsHasMoreButton, lhsEnabled, lhsStoryData, lhsRequiresPremiumForMessaging): + case let .peer(lhsIndex, lhsPeer, lhsPresence, lhsHeader, lhsSelection, lhsTheme, lhsStrings, lhsTimeFormat, lhsSortOrder, lhsDisplayOrder, lhsDisplayCallIcons, lhsHasMoreButton, lhsEnabled, lhsStoryData, lhsRequiresPremiumForMessaging, lhsCustomSubtitle): switch rhs { - case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsDisplayCallIcons, rhsHasMoreButton, rhsEnabled, rhsStoryData, rhsRequiresPremiumForMessaging): + case let .peer(rhsIndex, rhsPeer, rhsPresence, rhsHeader, rhsSelection, rhsTheme, rhsStrings, rhsTimeFormat, rhsSortOrder, rhsDisplayOrder, rhsDisplayCallIcons, rhsHasMoreButton, rhsEnabled, rhsStoryData, rhsRequiresPremiumForMessaging, rhsCustomSubtitle): if lhsIndex != rhsIndex { return false } @@ -328,6 +331,9 @@ private enum ContactListNodeEntry: Comparable, Identifiable { if lhsRequiresPremiumForMessaging != rhsRequiresPremiumForMessaging { return false } + if lhsCustomSubtitle != rhsCustomSubtitle { + return false + } return true default: return false @@ -369,11 +375,11 @@ private enum ContactListNodeEntry: Comparable, Identifiable { case .peer: return true } - case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, lhsStoryData, _): + case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, lhsStoryData, _, _): switch rhs { case .search, .sort, .permissionInfo, .permissionEnable, .option: return false - case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, rhsStoryData, _): + case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, rhsStoryData, _, _): if (lhsStoryData == nil) != (rhsStoryData == nil) { if lhsStoryData != nil { return true @@ -567,15 +573,24 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis } let presence = presences[peer.id] - entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, nil, false)) + entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, nil, false, nil)) index += 1 } } - case let .custom(sections): + case let .custom(showSelf, sections): if !topPeers.isEmpty { var index: Int = 0 - var sectionId: Int = 1 + + if showSelf, let accountPeer { + if let peer = topPeers.first(where: { $0.id == accountPeer.id }) { + let header = ChatListSearchItemHeader(type: .text(strings.Premium_Gift_ContactSelection_ThisIsYou.uppercased(), AnyHashable(10)), theme: theme, strings: strings) + entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), nil, header, .none, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, nil, false, strings.Premium_Gift_ContactSelection_BuySelf)) + existingPeerIds.insert(.peer(peer.id)) + } + } + + var sectionId: Int = 2 for (title, peerIds, hasActions) in sections { var allSelected = true if let selectedPeerIndices = selectionState?.selectedPeerIndices, !selectedPeerIndices.isEmpty { @@ -624,7 +639,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis } let presence = presences[peer.id] - entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, hasActions, true, nil, false)) + entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, hasActions, true, nil, false, nil)) index += 1 } @@ -675,7 +690,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis let presence = presences[peer.id] entries.append(.peer(index, .peer(peer: peer._asPeer(), isGlobal: false, participantCount: nil), presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, false, false, true, peersWithStories[peer.id].flatMap { ContactListNodeEntry.StoryData(count: $0.totalCount, unseenCount: $0.unseenCount, hasUnseenCloseFriends: $0.hasUnseenCloseFriends) - }, false)) + }, false, nil)) index += 1 } @@ -726,7 +741,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis } } - entries.append(.peer(index, peer, presence, nil, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, storyData, false)) + entries.append(.peer(index, peer, presence, nil, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, storyData, false, nil)) index += 1 } } @@ -779,7 +794,7 @@ private func contactListNodeEntries(accountPeer: EnginePeer?, peers: [ContactLis } } - entries.append(.peer(index, peer, presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, storyData, requiresPremiumForMessaging)) + entries.append(.peer(index, peer, presence, header, selection, theme, strings, dateTimeFormat, sortOrder, displayOrder, displayCallIcons, false, enabled, storyData, requiresPremiumForMessaging, nil)) index += 1 } return entries @@ -803,7 +818,7 @@ private func preparedContactListNodeTransition(context: AccountContext, presenta case .search: //indexSections.apend(CollectionIndexNode.searchIndex) break - case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _): + case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _, _): if let header = header as? ContactListNameIndexHeader { if !existingSections.contains(header.letter) { existingSections.insert(header.letter) @@ -872,7 +887,7 @@ public enum ContactListPresentation { public enum TopPeers { case none case recent - case custom([(title: String, peerIds: [EnginePeer.Id], hasActions: Bool)]) + case custom(showSelf: Bool, sections: [(title: String, peerIds: [EnginePeer.Id], hasActions: Bool)]) } case orderedByPresence(options: [ContactListAdditionalOption]) @@ -1284,7 +1299,7 @@ public final class ContactListNode: ASDisplayNode { strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.PreferSynchronousDrawing, .PreferSynchronousResourceLoading], scrollToItem: ListViewScrollToItem(index: index, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: nil), directionHint: .Down), additionalScrollDistance: 0.0, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) break loop } - case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _): + case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _, _): if let header = header as? ContactListNameIndexHeader { if let scalar = UnicodeScalar(header.letter) { let title = "\(Character(scalar))" @@ -1718,8 +1733,11 @@ public final class ContactListNode: ASDisplayNode { return .single([]) } } - case let .custom(sections): + case let .custom(showSelf, sections): var peerIds: [EnginePeer.Id] = [] + if showSelf { + peerIds.append(context.account.peerId) + } for (_, sectionPeers, _) in sections { peerIds.append(contentsOf: sectionPeers) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index d3c1037d7f..3e2023347b 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -1729,10 +1729,18 @@ public class GiftViewScreen: ViewControllerComponentContainer { switch action.action { case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, _, upgradeMessageId): return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, nil, nil, upgradeMessageId) - case let .starGiftUnique(gift, isUpgrade, _, savedToProfile, canExportDate, transferStars, _): - var incoming = message.flags.contains(.Incoming) - if isUpgrade && message.author?.id != message.id.peerId { - incoming = true + case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _): + var incoming = false + if isUpgrade { + if message.author?.id != message.id.peerId { + incoming = true + } + } else if isTransferred { + if message.author?.id != message.id.peerId { + incoming = true + } + } else { + incoming = message.flags.contains(.Incoming) } return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, false, false, false, nil, transferStars, canExportDate, nil) default: diff --git a/submodules/TelegramUI/Components/PeerInfo/VerifyAlertController/Sources/VerifyAlertController.swift b/submodules/TelegramUI/Components/PeerInfo/VerifyAlertController/Sources/VerifyAlertController.swift index 57b81e1ac6..d807a4efb0 100644 --- a/submodules/TelegramUI/Components/PeerInfo/VerifyAlertController/Sources/VerifyAlertController.swift +++ b/submodules/TelegramUI/Components/PeerInfo/VerifyAlertController/Sources/VerifyAlertController.swift @@ -306,9 +306,8 @@ private final class VerifyAlertContentNode: AlertContentNode { } } - let placeholderText = self.verifierSettings.customDescription ?? "This page is verified by \(self.verifierSettings.companyName)" + let placeholderText = self.verifierSettings.customDescription ?? self.strings.BotVerification_Verify_Placeholder(self.verifierSettings.companyName).string - //TODO:localize let inputPlaceholderSize = self.inputPlaceholderView.update( transition: .immediate, component: AnyComponent( @@ -404,16 +403,32 @@ public func verifyAlertController(context: AccountContext, updatedPresentationDa var dismissImpl: ((Bool) -> Void)? var applyImpl: (() -> Void)? - //TODO:localize let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { dismissImpl?(true) - }), TextAlertAction(type: .defaultAction, title: "Verify", action: { + }), TextAlertAction(type: .defaultAction, title: presentationData.strings.BotVerification_Verify_Verify, action: { dismissImpl?(true) applyImpl?() })] - //TODO:localize - let contentNode = VerifyAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), presentationTheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: "Verify Account", text: "Do you want to verify this account with your verification mark and description?", peer: peer, verifierSettings: verifierSettings, verifierIcon: verifierIcon, hasInput: verifierSettings.canModifyDescription) + let title: String + let text: String + if case let .user(user) = peer { + if let _ = user.botInfo { + title = presentationData.strings.BotVerification_Verify_Bot_Title + text = presentationData.strings.BotVerification_Verify_Bot_Text + } else { + title = presentationData.strings.BotVerification_Verify_User_Title + text = presentationData.strings.BotVerification_Verify_User_Text + } + } else if case let .channel(channel) = peer, case .broadcast = channel.info { + title = presentationData.strings.BotVerification_Verify_Channel_Title + text = presentationData.strings.BotVerification_Verify_Channel_Text + } else { + title = presentationData.strings.BotVerification_Verify_Group_Title + text = presentationData.strings.BotVerification_Verify_Group_Text + } + + let contentNode = VerifyAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), presentationTheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: title, text: text, peer: peer, verifierSettings: verifierSettings, verifierIcon: verifierIcon, hasInput: verifierSettings.canModifyDescription) contentNode.complete = { applyImpl?() } @@ -454,16 +469,28 @@ public func removeVerificationAlertController(context: AccountContext, updatedPr var dismissImpl: ((Bool) -> Void)? var applyImpl: (() -> Void)? - //TODO:localize let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { dismissImpl?(true) - }), TextAlertAction(type: .defaultDestructiveAction, title: "Remove", action: { + }), TextAlertAction(type: .defaultDestructiveAction, title: presentationData.strings.BotVerification_Remove_Remove, action: { dismissImpl?(true) applyImpl?() })] - //TODO:localize - let contentNode = VerifyAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), presentationTheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: "Remove Verification", text: "This account is already verified by you. Do you want to remove verification?", peer: peer, verifierSettings: verifierSettings, verifierIcon: verifierIcon, hasInput: false) + let title = presentationData.strings.BotVerification_Remove_Title + let text: String + if case let .user(user) = peer { + if let _ = user.botInfo { + text = presentationData.strings.BotVerification_Remove_Bot_Text + } else { + text = presentationData.strings.BotVerification_Remove_User_Text + } + } else if case let .channel(channel) = peer, case .broadcast = channel.info { + text = presentationData.strings.BotVerification_Remove_Channel_Text + } else { + text = presentationData.strings.BotVerification_Remove_Group_Text + } + + let contentNode = VerifyAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), presentationTheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: title, text: text, peer: peer, verifierSettings: verifierSettings, verifierIcon: verifierIcon, hasInput: false) applyImpl = { completion() } diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift index 31d8a65a08..b136def091 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift @@ -226,7 +226,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { sections.append((presentationData.strings.Premium_Gift_ContactSelection_BirthdayTomorrow, tomorrowPeers, hasActions)) } - displayTopPeers = .custom(sections) + displayTopPeers = .custom(showSelf: false, sections: sections) } else { displayTopPeers = .recent } diff --git a/submodules/TelegramUI/Sources/ContactSelectionControllerNode.swift b/submodules/TelegramUI/Sources/ContactSelectionControllerNode.swift index 45d3dc3733..e83f215593 100644 --- a/submodules/TelegramUI/Sources/ContactSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/ContactSelectionControllerNode.swift @@ -96,7 +96,7 @@ final class ContactSelectionControllerNode: ASDisplayNode { sections.append((presentationData.strings.Premium_Gift_ContactSelection_BirthdayTomorrow, tomorrowPeers, hasActions)) } - displayTopPeers = .custom(sections) + displayTopPeers = .custom(showSelf: showSelf, sections: sections) } else { displayTopPeers = .recent }