From 5d26ed41c46d351e3bba18aec94a749b74485d8c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 8 Nov 2023 16:44:46 +0400 Subject: [PATCH] Cherry-pick various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 19 +++- .../Sources/Node/ChatListItemStrings.swift | 13 +-- .../Sources/CreateGiveawayController.swift | 9 +- .../PremiumUI/Sources/GiftOptionItem.swift | 4 +- .../Sources/ChatMessageBubbleItemNode.swift | 2 +- ...ChatMessageGiveawayBubbleContentNode.swift | 15 ++- .../CountriesMultiselectionScreen.swift | 5 +- .../Info/StatsIcon.imageset/Contents.json | 12 +++ .../Chat/Info/StatsIcon.imageset/stats_30.pdf | Bin 0 -> 5844 bytes .../Sources/PeerInfo/PeerInfoScreen.swift | 88 +++++++++++------- 10 files changed, 110 insertions(+), 57 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/stats_30.pdf diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 11c3bd6079e..9afe3de581c 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10215,9 +10215,9 @@ Sorry for the inconvenience."; "ReassignBoost.ExpiresOn" = "Boost expires on %@"; "ReassignBoost.WaitForCooldown" = "Wait until the boost is available or get **%1$@** more boosts by gifting a **Telegram Premium** subscription."; -"ReassignBoost.Success" = "%1$@ are reassigned from %2$@."; -"ReassignBoost.Boosts_1" = "%@ boost"; -"ReassignBoost.Boosts_any" = "%@ boosts"; +"ReassignBoost.Success" = "%1$@ from %2$@."; +"ReassignBoost.Boosts_1" = "%@ boost is reassigned"; +"ReassignBoost.Boosts_any" = "%@ boosts are reassigned"; "ReassignBoost.OtherChannels_1" = "%@ other channel"; "ReassignBoost.OtherChannels_any" = "%@ other channels"; @@ -10433,6 +10433,10 @@ Sorry for the inconvenience."; "CountriesList.SaveCountries" = "Save Countries"; "CountriesList.SelectUpTo_1" = "select up to %@ country"; "CountriesList.SelectUpTo_any" = "select up to %@ countries"; +"CountriesList.Search" = "Search"; +"CountriesList.MaximumReached" = "You can select up to %@."; +"CountriesList.MaximumReached.Countries_1" = "%@ country"; +"CountriesList.MaximumReached.Countries_any" = "%@ countries"; "Message.GiveawayOngoing" = "Giveaway: %1$@ on %2$@"; "Message.GiveawayOngoing.Winners_1" = "%@ winner to be selected"; @@ -10442,6 +10446,9 @@ Sorry for the inconvenience."; "Message.GiveawayFinished.Winners_1" = "%@ winner was selected"; "Message.GiveawayFinished.Winners_any" = "%@ winners were selected"; +"Message.GiveawayStarted" = "Channel started a giveaway"; +"Message.GiveawayStartedOther" = "%@ started a giveaway"; + "Conversation.PinnedGiveaway" = "Giveaway"; "Conversation.PinnedGiveaway.Ongoing" = "%1$@ on %2$@"; @@ -10451,3 +10458,9 @@ Sorry for the inconvenience."; "Conversation.PinnedGiveaway.Finished" = "%1$@ on %2$@"; "Conversation.PinnedGiveaway.Finished.Winners_1" = "%@ winner was selected"; "Conversation.PinnedGiveaway.Finished.Winners_any" = "%@ winners were selected"; + +"BoostGift.StartConfirmation.Title" = "Start Giveaway"; +"BoostGift.StartConfirmation.Text" = "Are you sure you want to start giveaway now?"; +"BoostGift.StartConfirmation.Start" = "Start"; + +"Channel.Info.Stats" = "Statistics and Boosts"; diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index df85d40dd53..4778982f7b3 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -305,16 +305,11 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: } else { messageText = strings.Notification_Story } - case let giveaway as TelegramMediaGiveaway: - let dateString = stringForDateWithoutYear(date: Date(timeIntervalSince1970: TimeInterval(giveaway.untilDate)), timeZone: .current, strings: strings) - let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) - let isFinished = currentTime >= giveaway.untilDate - if isFinished { - let winnersString = strings.Message_GiveawayFinished_Winners(giveaway.quantity) - messageText = strings.Message_GiveawayFinished(winnersString, dateString).string + case _ as TelegramMediaGiveaway: + if let forwardInfo = message.forwardInfo, let author = forwardInfo.author { + messageText = strings.Message_GiveawayStartedOther(EnginePeer(author).compactDisplayTitle).string } else { - let winnersString = strings.Message_GiveawayOngoing_Winners(giveaway.quantity) - messageText = strings.Message_GiveawayOngoing(winnersString, dateString).string + messageText = strings.Message_GiveawayStarted } case let webpage as TelegramMediaWebpage: if messageText.isEmpty, case let .Loaded(content) = webpage.content { diff --git a/submodules/PremiumUI/Sources/CreateGiveawayController.swift b/submodules/PremiumUI/Sources/CreateGiveawayController.swift index 8eb6fa86889..4897e22b52a 100644 --- a/submodules/PremiumUI/Sources/CreateGiveawayController.swift +++ b/submodules/PremiumUI/Sources/CreateGiveawayController.swift @@ -837,7 +837,14 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio badgeCount = Int32(state.peers.count) * 4 } let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? presentationData.strings.BoostGift_GiftPremium : presentationData.strings.BoostGift_StartGiveaway, badgeCount: badgeCount, isLoading: state.updating, action: { - buyActionImpl?() + if case .prepaid = subject { + let alertController = textAlertController(context: context, title: presentationData.strings.BoostGift_StartConfirmation_Title, text: presentationData.strings.BoostGift_StartConfirmation_Text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BoostGift_StartConfirmation_Start, action: { + buyActionImpl?() + })], parseMarkdown: true) + presentControllerImpl?(alertController) + } else { + buyActionImpl?() + } }) let leftNavigationButton = ItemListNavigationButton(content: .none, style: .regular, enabled: false, action: {}) diff --git a/submodules/PremiumUI/Sources/GiftOptionItem.swift b/submodules/PremiumUI/Sources/GiftOptionItem.swift index 239293955af..b7fe236e663 100644 --- a/submodules/PremiumUI/Sources/GiftOptionItem.swift +++ b/submodules/PremiumUI/Sources/GiftOptionItem.swift @@ -304,12 +304,14 @@ class GiftOptionItemNode: ItemListRevealOptionsItemNode { let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: labelAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: .greatestFiniteMagnitude))) var textConstrainedWidth = params.width - leftInset - 8.0 - editingOffset - rightInset - labelLayout.size.width - avatarInset + var subtitleConstrainedWidth = textConstrainedWidth if let label = item.label, case .semitransparent = label { textConstrainedWidth -= 54.0 + subtitleConstrainedWidth -= 30.0 } let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: .greatestFiniteMagnitude))) - let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: subtitleConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (badgeLayout, badgeApply) = makeBadgeLayout(TextNodeLayoutArguments(attributedString: badgeAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: textConstrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift index d41bd85eb44..f8d08f6b638 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageBubbleItemNode/Sources/ChatMessageBubbleItemNode.swift @@ -1556,7 +1556,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI for contentNodeItemValue in contentNodeMessagesAndClasses { let contentNodeItem = contentNodeItemValue as (message: Message, type: AnyClass, attributes: ChatMessageEntryAttributes, bubbleAttributes: BubbleItemAttributes) if contentNodeItem.type == ChatMessageGiveawayBubbleContentNode.self { - maximumContentWidth = 260.0 + maximumContentWidth = min(305.0, maximumContentWidth) break } if contentNodeItem.type == ChatMessageInstantVideoBubbleContentNode.self, !contentNodeItem.bubbleAttributes.isAttachment { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift index 35fe59fd49d..d65462b819c 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiveawayBubbleContentNode/Sources/ChatMessageGiveawayBubbleContentNode.swift @@ -319,7 +319,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode let (participantsTitleLayout, participantsTitleApply) = makeParticipantsTitleLayout(TextNodeLayoutArguments(attributedString: participantsTitleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (participantsTextLayout, participantsTextApply) = makeParticipantsTextLayout(TextNodeLayoutArguments(attributedString: participantsTextString, backgroundColor: nil, maximumNumberOfLines: 5, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let (countriesTextLayout, countriesTextApply) = makeCountriesTextLayout(TextNodeLayoutArguments(attributedString: countriesTextString, backgroundColor: nil, maximumNumberOfLines: 5, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + let (countriesTextLayout, countriesTextApply) = makeCountriesTextLayout(TextNodeLayoutArguments(attributedString: countriesTextString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (dateTitleLayout, dateTitleApply) = makeDateTitleLayout(TextNodeLayoutArguments(attributedString: dateTitleString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let (dateTextLayout, dateTextApply) = makeDateTextLayout(TextNodeLayoutArguments(attributedString: dateTextString, backgroundColor: nil, maximumNumberOfLines: 5, truncationType: .end, constrainedSize: CGSize(width: maxTextWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) @@ -437,7 +437,7 @@ public class ChatMessageGiveawayBubbleContentNode: ChatMessageBubbleContentNode } } } - let (channelsWidth, continueChannelLayout) = makeChannelsLayout(item.context, 220.0, channelPeers, accentColor, accentColor.withAlphaComponent(0.1)) + let (channelsWidth, continueChannelLayout) = makeChannelsLayout(item.context, 220.0, channelPeers, accentColor, accentColor.withAlphaComponent(0.1), incoming, item.presentationData.theme.theme.overallDarkAppearance) maxContentWidth = max(maxContentWidth, channelsWidth) maxContentWidth += 30.0 @@ -649,11 +649,11 @@ private final class PeerButtonsStackNode: ASDisplayNode { var buttonNodes: [PeerButtonNode] = [] var openPeer: (EnginePeer) -> Void = { _ in } - static func asyncLayout(_ current: PeerButtonsStackNode) -> (_ context: AccountContext, _ width: CGFloat, _ peers: [EnginePeer], _ titleColor: UIColor, _ backgroundColor: UIColor) -> (CGFloat, (CGFloat) -> (CGSize, () -> PeerButtonsStackNode)) { + static func asyncLayout(_ current: PeerButtonsStackNode) -> (_ context: AccountContext, _ width: CGFloat, _ peers: [EnginePeer], _ titleColor: UIColor, _ backgroundColor: UIColor, _ incoming: Bool, _ dark: Bool) -> (CGFloat, (CGFloat) -> (CGSize, () -> PeerButtonsStackNode)) { let currentChannelButtons = current.buttonNodes.isEmpty ? nil : current.buttonNodes let maybeMakeChannelButtons = current.buttonNodes.map(PeerButtonNode.asyncLayout) - return { context, width, peers, titleColor, backgroundColor in + return { context, width, peers, titleColor, backgroundColor, incoming, dark in let targetNode = current var buttonNodes: [PeerButtonNode] = [] @@ -682,6 +682,13 @@ private final class PeerButtonsStackNode: ASDisplayNode { let peer = peers[i] let makeChannelButtonLayout = makeChannelButtonLayouts[i] + var titleColor = titleColor + var backgroundColor = backgroundColor + if incoming, let nameColor = peer.nameColor { + titleColor = context.peerNameColors.get(nameColor, dark: dark).main + backgroundColor = titleColor.withAlphaComponent(0.1) + } + let (buttonWidth, buttonContinue) = makeChannelButtonLayout(context, width, peer, titleColor, backgroundColor) sizes.append(CGSize(width: buttonWidth, height: buttonHeight)) buttonContinues.append(buttonContinue) diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift index db68431ac05..1559896c2fe 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift @@ -468,7 +468,8 @@ final class CountriesMultiselectionScreenComponent: Component { self.hapticFeedback.error() let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: "You can select maximum \(limit) countries.", timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) + let countriesValue = environment.strings.CountriesList_MaximumReached_Countries(limit) + controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: environment.strings.CountriesList_MaximumReached(countriesValue).string, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) return } toggleCountry() @@ -721,7 +722,7 @@ final class CountriesMultiselectionScreenComponent: Component { )) } - let placeholder: String = "Search" + let placeholder: String = environment.strings.CountriesList_Search self.navigationTextField.parentState = state let navigationTextFieldSize = self.navigationTextField.update( transition: transition, diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/Contents.json new file mode 100644 index 00000000000..b7a0fdc9123 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "stats_30.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/stats_30.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Info/StatsIcon.imageset/stats_30.pdf new file mode 100644 index 0000000000000000000000000000000000000000..019b3076778943e773f31f62574e9f28f4b88119 GIT binary patch literal 5844 zcmeHLO>f*b5WVYH@M0h-5Uogkkw9P|{zTCRalJhR2zrp$ioNN2<*wwy>96llBHxU> zZj)XM>tJ)A`0?h=a462f#mU(loz_XBRi?VDFNsob->Sv0U+-JB`1s-KOS>8fqi6AR zyS*81m7$K80XpAx5BFlg_v?eCjiyIp;qy+1q*Q!O8^hH=reZg&^3 z%eL5)?_#avTd8>Hu;=vlV84f zPgZd&)v-Z)5<7Ok;rArE>LL!hn}J1DI9n;%uX1%!I}eqb9z{c~rA=nZjyl!WS#6Xq z(;_P^ZRa{IU7=}X5oC3ytyMOqadkcRas>@`G}NYfW=caK457V{mzgdEMGc59w{lbVbWMlG+(`-83hBc#YKk!T+e>f^@5O;+V^E1+!Nst|MlJmg4v|mF zO@R+fNbxD|^<;@wE(Q}hZL);65!TUBRfb>-LzFEeLk10^5VM(yqmzr~kt3*45}P=J zejYgrBcYy+>j)&oxl6 z6IunzK)i#V#yDJtUT~~f5A?uFG(t*5_b`E(9R)GQ#WGK+Ku>Xm*cj|S#C=|$b{(=b z9STr7WGzaQ0*XmXK=35@!_t(q&=X=wDCR8c6;2HHCiM&Z26_<$dH6KhPa>3@!^|vD zx$i8TCg?>zt){Kxzfgl|1U-!pg2ofW`Cc(~Y5J6j`#Z9$SrRC&i1%iWG
    i4XxaA1LFTX2Wn!vjFnMgiuhH<&;pc6%efo_W)!k zN+>v6u8N>wb_gA|0U;)ArO&7z#_y=4-Cl<)5Via@FY(v7>AsieCi5LeI0yWVYhdwm z4fJm2Z8Tm3gXgig(0I8925I>E##bmhqHs+TcPPFP^4phdAjKS|zfeX%d{K(||6T*1 zNnbwwOzDfN8OUCAs)-_2C|`~BsgLxT=`$9Wkxn0n^X1SC?fCvwkN=kMoBsE)HC4d; z&sn{S%Ubi+;#~RE846?bcYD7UR1tf(xxa0`J$0;l?akqVP^N<=|1{m<;bb;V7V~^H zQ!149r~)-9^j+n$1!;EECkvAHq@&CFGhXr&PF^Z1EKOB1;iPxlZ8!AllP}b_hq;DxVD4vIc^Mo8%7p~(V&9{#kxCaTI? zaH%5WOKBFAz~&?XN8!`Ti9bow*0smnoV~zAN#m#KPR;Bbuwj9|5sHdeK#q> z!{Zn5kD`L(_~d0xO#Q=9mC-hsK~&M8$elx0lVmf9J_4WiD$RZ`las9Tfkj3dK7lOH zHSC)8rrjl8-XBj$+*f^f*S=P-*4M8mi5Hh$NBVmCMt?1q>%UsB1&P}a&2AXgDa#^H K4h~K~oc#@1)tmPK literal 0 HcmV?d00001 diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 05f743cb9d6..5978f96c9cc 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -529,6 +529,7 @@ private final class PeerInfoInteraction { let editingToggleMessageSignatures: (Bool) -> Void let openParticipantsSection: (PeerInfoParticipantsSection) -> Void let openRecentActions: () -> Void + let openStats: () -> Void let editingOpenPreHistorySetup: () -> Void let editingOpenAutoremoveMesages: () -> Void let openPermissions: () -> Void @@ -582,6 +583,7 @@ private final class PeerInfoInteraction { editingToggleMessageSignatures: @escaping (Bool) -> Void, openParticipantsSection: @escaping (PeerInfoParticipantsSection) -> Void, openRecentActions: @escaping () -> Void, + openStats: @escaping () -> Void, editingOpenPreHistorySetup: @escaping () -> Void, editingOpenAutoremoveMesages: @escaping () -> Void, openPermissions: @escaping () -> Void, @@ -634,6 +636,7 @@ private final class PeerInfoInteraction { self.editingToggleMessageSignatures = editingToggleMessageSignatures self.openParticipantsSection = openParticipantsSection self.openRecentActions = openRecentActions + self.openStats = openStats self.editingOpenPreHistorySetup = editingOpenPreHistorySetup self.editingOpenAutoremoveMesages = editingOpenAutoremoveMesages self.openPermissions = openPermissions @@ -1550,8 +1553,9 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL let ItemAdmins = 9 let ItemMembers = 10 let ItemMemberRequests = 11 - let ItemBanned = 12 - let ItemRecentActions = 13 + let ItemStats = 12 + let ItemBanned = 13 + let ItemRecentActions = 14 let isCreator = channel.flags.contains(.isCreator) @@ -1641,47 +1645,56 @@ private func editingItems(data: PeerInfoScreenData?, state: PeerInfoState, chatL } var canEditMembers = false - if channel.hasPermission(.banMembers) { + if channel.hasPermission(.banMembers) && (channel.adminRights != nil || channel.flags.contains(.isCreator)) { canEditMembers = true } if canEditMembers { - if channel.adminRights != nil || channel.flags.contains(.isCreator) { - let adminCount: Int32 - let memberCount: Int32 - let bannedCount: Int32 - if let cachedData = data.cachedData as? CachedChannelData { - adminCount = cachedData.participantsSummary.adminCount ?? 0 - memberCount = cachedData.participantsSummary.memberCount ?? 0 - bannedCount = cachedData.participantsSummary.kickedCount ?? 0 - } else { - adminCount = 0 - memberCount = 0 - bannedCount = 0 - } - - items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: .text("\(adminCount == 0 ? "" : "\(presentationStringsFormattedNumber(adminCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.GroupInfo_Administrators, icon: UIImage(bundleImageName: "Chat/Info/GroupAdminsIcon"), action: { - interaction.openParticipantsSection(.admins) - })) - items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemMembers, label: .text("\(memberCount == 0 ? "" : "\(presentationStringsFormattedNumber(memberCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.Channel_Info_Subscribers, icon: UIImage(bundleImageName: "Chat/Info/GroupMembersIcon"), action: { - interaction.openParticipantsSection(.members) - })) - - if let count = data.requests?.count, count > 0 { - items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemMemberRequests, label: .badge(presentationStringsFormattedNumber(count, presentationData.dateTimeFormat.groupingSeparator), presentationData.theme.list.itemAccentColor), text: presentationData.strings.GroupInfo_MemberRequests, icon: UIImage(bundleImageName: "Chat/Info/GroupRequestsIcon"), action: { - interaction.openParticipantsSection(.memberRequests) - })) - } - - items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemBanned, label: .text("\(bannedCount == 0 ? "" : "\(presentationStringsFormattedNumber(bannedCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.GroupInfo_Permissions_Removed, icon: UIImage(bundleImageName: "Chat/Info/GroupRemovedIcon"), action: { - interaction.openParticipantsSection(.banned) - })) - - items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemRecentActions, label: .none, text: presentationData.strings.Group_Info_AdminLog, icon: UIImage(bundleImageName: "Chat/Info/RecentActionsIcon"), action: { - interaction.openRecentActions() + let adminCount: Int32 + let memberCount: Int32 + if let cachedData = data.cachedData as? CachedChannelData { + adminCount = cachedData.participantsSummary.adminCount ?? 0 + memberCount = cachedData.participantsSummary.memberCount ?? 0 + } else { + adminCount = 0 + memberCount = 0 + } + + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemAdmins, label: .text("\(adminCount == 0 ? "" : "\(presentationStringsFormattedNumber(adminCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.GroupInfo_Administrators, icon: UIImage(bundleImageName: "Chat/Info/GroupAdminsIcon"), action: { + interaction.openParticipantsSection(.admins) + })) + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemMembers, label: .text("\(memberCount == 0 ? "" : "\(presentationStringsFormattedNumber(memberCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.Channel_Info_Subscribers, icon: UIImage(bundleImageName: "Chat/Info/GroupMembersIcon"), action: { + interaction.openParticipantsSection(.members) + })) + + if let count = data.requests?.count, count > 0 { + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemMemberRequests, label: .badge(presentationStringsFormattedNumber(count, presentationData.dateTimeFormat.groupingSeparator), presentationData.theme.list.itemAccentColor), text: presentationData.strings.GroupInfo_MemberRequests, icon: UIImage(bundleImageName: "Chat/Info/GroupRequestsIcon"), action: { + interaction.openParticipantsSection(.memberRequests) })) } } + if let cachedData = data.cachedData as? CachedChannelData, cachedData.flags.contains(.canViewStats) { + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemStats, label: .none, text: presentationData.strings.Channel_Info_Stats, icon: UIImage(bundleImageName: "Chat/Info/StatsIcon"), action: { + interaction.openStats() + })) + } + + if canEditMembers { + let bannedCount: Int32 + if let cachedData = data.cachedData as? CachedChannelData { + bannedCount = cachedData.participantsSummary.kickedCount ?? 0 + } else { + bannedCount = 0 + } + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemBanned, label: .text("\(bannedCount == 0 ? "" : "\(presentationStringsFormattedNumber(bannedCount, presentationData.dateTimeFormat.groupingSeparator))")"), text: presentationData.strings.GroupInfo_Permissions_Removed, icon: UIImage(bundleImageName: "Chat/Info/GroupRemovedIcon"), action: { + interaction.openParticipantsSection(.banned) + })) + + items[.peerAdditionalSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemRecentActions, label: .none, text: presentationData.strings.Group_Info_AdminLog, icon: UIImage(bundleImageName: "Chat/Info/RecentActionsIcon"), action: { + interaction.openRecentActions() + })) + } + if isCreator { //if let cachedData = data.cachedData as? CachedChannelData, cachedData.flags.contains(.canDeleteHistory) { items[.peerActions]!.append(PeerInfoScreenActionItem(id: ItemDeleteChannel, text: presentationData.strings.ChannelInfo_DeleteChannel, color: .destructive, icon: nil, alignment: .natural, action: { interaction.openDeletePeer() @@ -2304,6 +2317,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro openRecentActions: { [weak self] in self?.openRecentActions() }, + openStats: { [weak self] in + self?.openStats() + }, editingOpenPreHistorySetup: { [weak self] in self?.editingOpenPreHistorySetup() },