From 711f8f7b467bc674549203bac0289a781baa65f3 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Tue, 29 Jul 2025 21:49:26 +0200 Subject: [PATCH] Various improvements --- .../Telegram-iOS/en.lproj/Localizable.strings | 2 + .../ChatMessageWebpageBubbleContentNode.swift | 3 +- .../Sources/PeerInfoPaneContainerNode.swift | 14 +- .../Sources/PeerInfoScreen.swift | 32 ++-- .../Sources/PeerInfoGiftsPaneNode.swift | 140 +++++++++++------- .../Sources/StarsWithdrawalScreen.swift | 7 +- 6 files changed, 123 insertions(+), 75 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 8b8efcda09..6b94f65e94 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14787,3 +14787,5 @@ Sorry for the inconvenience."; "Stars.SellGift.TonAmountTitle" = "PRICE IN TON"; "Stars.SellGift.OnlyTon" = "Only Accept TON"; "Stars.SellGift.OnlyTonInfo" = "If the buyer pays you in TON, there's no risk of refunds, unlike with Stars payments."; + +"Chat.ViewCollection" = "VIEW COLLECTION"; diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift index 2ee5c14240..cd1fe4afc6 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -477,8 +477,7 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent case "telegram_call": actionTitle = item.presentationData.strings.Chat_ViewGroupCall case "telegram_collection": - //TODO:localize - actionTitle = "VIEW COLLECTION" + actionTitle = item.presentationData.strings.Chat_ViewCollection default: break } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift index aa6594e25f..97512e4a65 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift @@ -537,7 +537,8 @@ private final class PeerInfoPendingPane { paneDidScroll: @escaping () -> Void, expandIfNeeded: @escaping () -> Void, ensureRectVisible: @escaping (UIView, CGRect) -> Void, - externalDataUpdated: @escaping (ContainedViewLayoutTransition) -> Void + externalDataUpdated: @escaping (ContainedViewLayoutTransition) -> Void, + openShareLink: @escaping (String) -> Void ) { var chatLocationPeerId = peerId var chatLocation = chatLocation @@ -578,7 +579,9 @@ private final class PeerInfoPendingPane { } } } - paneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGiftsCollections: data.profileGiftsCollectionsContext!, profileGifts: data.profileGiftsContext!, canManage: canManage, canGift: canGift, initialGiftCollectionId: initialGiftCollectionId) + let giftPaneNode = PeerInfoGiftsPaneNode(context: context, peerId: peerId, chatControllerInteraction: chatControllerInteraction, profileGiftsCollections: data.profileGiftsCollectionsContext!, profileGifts: data.profileGiftsContext!, canManage: canManage, canGift: canGift, initialGiftCollectionId: initialGiftCollectionId) + giftPaneNode.openShareLink = openShareLink + paneNode = giftPaneNode case .stories, .storyArchive, .botPreview: var canManage = false if let peer = data.peer { @@ -748,6 +751,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat var openMediaCalendar: (() -> Void)? var openAddStory: (() -> Void)? + var openShareLink: ((String) -> Void)? var paneDidScroll: (() -> Void)? var ensurePaneRectVisible: ((UIView, CGRect) -> Void)? @@ -1181,6 +1185,12 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat return } self.requestUpdate?(transition) + }, + openShareLink: { [weak self] url in + guard let self else { + return + } + self.openShareLink?(url) } ) self.pendingPanes[key] = pane diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 5a84b6a764..688408480f 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -4103,6 +4103,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } } + self.paneContainerNode.openShareLink = { [weak self] url in + guard let self else { + return + } + self.openShareLink(url: url) + } + self.headerNode.performButtonAction = { [weak self] key, gesture in self?.performButtonAction(key: key, gesture: gesture) } @@ -11392,17 +11399,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro pane.addGiftsToCollection(id: id) } }))) - - if let addressName = data.peer?.addressName, !addressName.isEmpty { - items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_ShareCollection, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - if let pane, case let .collection(id) = pane.currentCollection { - self?.openShareLink(url: "https://t.me/\(addressName)/c/\(id)") - } - }))) - } } if canReorder { @@ -11430,6 +11426,20 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } } + if let pane, case let .collection(id) = pane.currentCollection, let addressName = data.peer?.addressName, !addressName.isEmpty { + let shareAction: ContextMenuItem = .action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_ShareCollection, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + self?.openShareLink(url: "https://t.me/\(addressName)/c/\(id)") + })) + if items.isEmpty { + items.append(shareAction) + } else { + items.insert(shareAction, at: 1) + } + } + if !items.isEmpty { items.append(.separator) } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index 0596997045..3fba0f7132 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -70,6 +70,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr private let profileGifts: ProfileGiftsContext private let canManage: Bool private let canGift: Bool + private var peer: EnginePeer? private let initialGiftCollectionId: Int64? private var resultsAreEmpty = false @@ -130,6 +131,8 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr return self.giftsListView.profileGifts } + public var openShareLink: ((String) -> Void)? + private let collectionsMaxCount: Int public init(context: AccountContext, peerId: PeerId, chatControllerInteraction: ChatControllerInteraction, profileGiftsCollections: ProfileGiftsCollectionsContext, profileGifts: ProfileGiftsContext, canManage: Bool, canGift: Bool, initialGiftCollectionId: Int64?) { @@ -193,6 +196,15 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr if let initialGiftCollectionId { self.setCurrentCollection(collection: .collection(Int32(initialGiftCollectionId))) } + + let _ = (context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let self else { + return + } + self.peer = peer + self.updateScrolling(transition: .immediate) + }) } deinit { @@ -485,68 +497,78 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr return } + var canEditCollections = false + if self.peerId == self.context.account.peerId || self.canManage { + canEditCollections = true + } + var items: [ContextMenuItem] = [] - items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_AddGifts, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddGift"), color: theme.actionSheet.primaryTextColor) - }, action: { [weak self] _, f in - guard let self else { - return - } - f(.default) - - self.setCurrentCollection(collection: .collection(id)) - self.addGiftsToCollection(id: id) - }))) - - items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_RenameCollection, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) - }, action: { [weak self] _, f in - guard let self else { - return - } - f(.default) - - Queue.mainQueue().after(0.15) { - self.renameCollection(id: id) - } - }))) - - -// items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_ShareCollection, icon: { theme in -// return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor) -// }, action: { [weak self] _, f in -// guard let self else { -// return -// } -// f(.default) -// -// let _ = self -// }))) - - items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_Reorder, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.actionSheet.primaryTextColor) - }, action: { [weak self] c, f in - c?.dismiss(completion: { [weak self] in + if canEditCollections { + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_AddGifts, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/Gifts/AddGift"), color: theme.actionSheet.primaryTextColor) + }, action: { [weak self] _, f in guard let self else { return } - self.beginReordering() - }) - }))) - - items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_DeleteCollection, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) - }, action: { [weak self] _, f in - guard let self else { - return - } - f(.default) + f(.default) + + self.setCurrentCollection(collection: .collection(id)) + self.addGiftsToCollection(id: id) + }))) - Queue.mainQueue().after(0.15) { - self.deleteCollection(id: id) - } - }))) + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_RenameCollection, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.actionSheet.primaryTextColor) + }, action: { [weak self] _, f in + guard let self else { + return + } + f(.default) + + Queue.mainQueue().after(0.15) { + self.renameCollection(id: id) + } + }))) + } + + if let peer = self.peer, let addressName = peer.addressName, !addressName.isEmpty { + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_ShareCollection, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor) + }, action: { [weak self] _, f in + guard let self else { + return + } + f(.default) + + self.openShareLink?("https://t.me/\(addressName)/c/\(id)") + }))) + } + + if canEditCollections { + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_Reorder, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.actionSheet.primaryTextColor) + }, action: { [weak self] c, f in + c?.dismiss(completion: { [weak self] in + guard let self else { + return + } + self.beginReordering() + }) + }))) + + items.append(.action(ContextMenuActionItem(text: params.presentationData.strings.PeerInfo_Gifts_DeleteCollection, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + guard let self else { + return + } + f(.default) + + Queue.mainQueue().after(0.15) { + self.deleteCollection(id: id) + } + }))) + } let contextController = ContextController( presentationData: params.presentationData, @@ -568,6 +590,10 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr if self.peerId == self.context.account.peerId || self.canManage { canEditCollections = true } + var canShare = false + if let peer = self.peer, let addressName = peer.addressName, !addressName.isEmpty { + canShare = true + } let hasNonEmptyCollections = self.collections?.contains(where: { $0.count > 0 }) ?? false if let collections = self.collections, !collections.isEmpty && (hasNonEmptyCollections || canEditCollections) { @@ -607,7 +633,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr ) )), isReorderable: collections.count > 1, - contextAction: canEditCollections ? { [weak self] sourceNode, gesture in + contextAction: canEditCollections || canShare ? { [weak self] sourceNode, gesture in guard let self else { return } diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index 207c556cf0..5cf28288db 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -1037,15 +1037,16 @@ private final class SheetContent: CombinedComponent { } if case let .starGiftResell(giftToMatch, update, _) = self.mode { + let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) if update { if giftToMatch.resellForTonOnly { if let resellStars = giftToMatch.resellAmounts?.first(where: { $0.currency == .ton }) { - self.amount = resellStars.amount + self.amount = StarsAmount(value: max(resellStars.amount.value, resaleConfiguration.starGiftResaleMinTonAmount), nanos: 0) } self.currency = .ton } else { if let resellStars = giftToMatch.resellAmounts?.first(where: { $0.currency == .stars }) { - self.amount = resellStars.amount + self.amount = StarsAmount(value: max(resellStars.amount.value, resaleConfiguration.starGiftResaleMinStarsAmount), nanos: 0) } self.currency = .stars } @@ -1067,7 +1068,7 @@ private final class SheetContent: CombinedComponent { return } if case let .generic(genericGift) = matchingGift, let minResaleStars = genericGift.availability?.minResaleStars { - self.amount = StarsAmount(value: minResaleStars, nanos: 0) + self.amount = StarsAmount(value: max(minResaleStars, resaleConfiguration.starGiftResaleMinStarsAmount), nanos: 0) self.updated() } })