From da08c69da28f07ea75e582287368b59417b922b7 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Sun, 16 Nov 2025 00:24:00 +0800 Subject: [PATCH 1/5] Fix typo (cherry picked from commit 53966b99a844af84e64737d6ea807bd4900a7eea) --- .../Sources/LiveChatReactionStreamView.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/LiveChatReactionStreamView.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/LiveChatReactionStreamView.swift index 2b8caaa9bc..c80f66635f 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/LiveChatReactionStreamView.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/LiveChatReactionStreamView.swift @@ -94,8 +94,6 @@ private func avatarViewLettersImage(size: CGSize, peerId: EnginePeer.Id, letters } private func makePeerBadgeImage(engine: TelegramEngine, peer: EnginePeer, count: Int) async -> UIImage { - let count = 123 - let avatarSize: CGFloat = 16.0 let avatarInset: CGFloat = 2.0 let avatarIconSpacing: CGFloat = 2.0 From c7556cedf921956eeff0e7b0f8ad2049aeca8732 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 15 Nov 2025 20:47:37 +0400 Subject: [PATCH 2/5] Remove story live mode in groups --- .../CameraScreen/Sources/CameraScreen.swift | 16 ++++++++-- .../CameraScreen/Sources/ModeComponent.swift | 29 +++++++++++++++---- .../Sources/ShareWithPeersScreenState.swift | 7 +++++ 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift index 4f265f9d87..b29f30a514 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift @@ -46,7 +46,7 @@ let collageGrids: [Camera.CollageGrid] = [ Camera.CollageGrid(rows: [Camera.CollageGrid.Row(columns: 2), Camera.CollageGrid.Row(columns: 2), Camera.CollageGrid.Row(columns: 2)]) ] -enum CameraMode: Equatable { +enum CameraMode: Int32, Equatable { case photo case video case live @@ -318,6 +318,7 @@ private final class CameraScreenComponent: CombinedComponent { fileprivate var sendAsPeerId: EnginePeer.Id? fileprivate var isCustomTarget = false + fileprivate var canLivestream = true private var privacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: []) private var allowComments = true @@ -388,6 +389,17 @@ private final class CameraScreenComponent: CombinedComponent { if let customTarget = controller.customTarget { self.sendAsPeerId = customTarget self.isCustomTarget = true + + let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: customTarget)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let self else { + return + } + if case let .channel(channel) = peer, case .group = channel.info { + self.canLivestream = false + self.updated() + } + }) } let _ = (mediaEditorStoredState(engine: self.context.engine) @@ -2091,7 +2103,7 @@ private final class CameraScreenComponent: CombinedComponent { } var availableModes: [CameraMode] = [.photo, .video] - if !isTablet { + if !isTablet && state.canLivestream { availableModes.append(.live) } diff --git a/submodules/TelegramUI/Components/CameraScreen/Sources/ModeComponent.swift b/submodules/TelegramUI/Components/CameraScreen/Sources/ModeComponent.swift index 55a2094898..cfb581ad45 100644 --- a/submodules/TelegramUI/Components/CameraScreen/Sources/ModeComponent.swift +++ b/submodules/TelegramUI/Components/CameraScreen/Sources/ModeComponent.swift @@ -115,7 +115,7 @@ final class ModeComponent: Component { private var backgroundView = UIView() private var glassContainerView = GlassBackgroundContainerView() private var selectionView = GlassBackgroundView() - private var itemViews: [ItemView] = [] + private var itemViews: [Int32: ItemView] = [:] public func matches(tag: Any) -> Bool { if let component = self.component, let componentTag = component.tag { @@ -179,14 +179,19 @@ final class ModeComponent: Component { var itemFrame = CGRect(origin: isTablet ? .zero : CGPoint(x: inset, y: 0.0), size: buttonSize) var selectedCenter = itemFrame.minX var selectedFrame = itemFrame + + var validKeys: Set = Set() for mode in component.availableModes.reversed() { + let id = mode.rawValue + validKeys.insert(id) + let itemView: ItemView - if self.itemViews.count == i { + if let current = self.itemViews[id] { + itemView = current + } else { itemView = ItemView() self.backgroundView.addSubview(itemView) - self.itemViews.append(itemView) - } else { - itemView = self.itemViews[i] + self.itemViews[id] = itemView } itemView.pressed = { updatedMode(mode) @@ -216,6 +221,20 @@ final class ModeComponent: Component { i += 1 } + var removeKeys: [Int32] = [] + for (id, itemView) in self.itemViews { + if !validKeys.contains(id) { + removeKeys.append(id) + + transition.setAlpha(view: itemView, alpha: 0.0, completion: { _ in + itemView.removeFromSuperview() + }) + } + } + for id in removeKeys { + self.itemViews.removeValue(forKey: id) + } + let totalSize: CGSize let size: CGSize if isTablet { diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreenState.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreenState.swift index b5450629a1..5bc9be69da 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreenState.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreenState.swift @@ -101,6 +101,13 @@ public extension ShareWithPeersScreen { switch subject { case let .peers(peers, _): + let peers = peers.filter { peer in + if liveStream, case let .channel(channel) = peer, case .group = channel.info { + return false + } else { + return true + } + } self.stateDisposable = (.single(peers) |> mapToSignal { peers -> Signal<([EnginePeer], [EnginePeer.Id: Optional]), NoError> in return context.engine.data.subscribe( From 3a4031b5c52e70fb44fa0228c35024a3378ea906 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 15 Nov 2025 22:31:03 +0400 Subject: [PATCH 3/5] Various fixes --- .../Sources/GiftSetupScreen.swift | 76 +++++++++++-------- .../Sources/GiftAuctionBidScreen.swift | 12 +-- 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index c96ea271cf..f1bfb091a7 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -887,6 +887,8 @@ private final class GiftSetupScreenComponent: Component { let environment = environment[ViewControllerComponentContainer.Environment.self].value let themeUpdated = self.environment?.theme !== environment.theme + let theme = environment.theme.withModalBlocksBackground() + let resetScrolling = self.scrollView.bounds.width != availableSize.width let fillingSize: CGFloat @@ -1093,7 +1095,7 @@ private final class GiftSetupScreenComponent: Component { if themeUpdated { self.dimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5) - self.backgroundLayer.backgroundColor = environment.theme.list.blocksBackgroundColor.cgColor + self.backgroundLayer.backgroundColor = theme.list.blocksBackgroundColor.cgColor } transition.setFrame(view: self.dimView, frame: CGRect(origin: CGPoint(), size: availableSize)) @@ -1382,18 +1384,18 @@ private final class GiftSetupScreenComponent: Component { let resaleSectionSize = self.resaleSection.update( transition: transition, component: AnyComponent(ListSectionComponent( - theme: environment.theme, + theme: theme, style: .glass, header: nil, footer: nil, items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, + theme: theme, style: .glass, title: AnyComponent(VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent( MultilineTextComponent( - text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: theme.list.itemPrimaryTextColor)) ) )), ], alignment: .left, spacing: 2.0)), @@ -1401,7 +1403,7 @@ private final class GiftSetupScreenComponent: Component { text: .plain(NSAttributedString( string: presentationStringsFormattedNumber(Int32(availability.resale), environment.dateTimeFormat.groupingSeparator), font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemSecondaryTextColor + textColor: theme.list.itemSecondaryTextColor )), maximumNumberOfLines: 0 ))), insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 16.0))), @@ -1444,7 +1446,7 @@ private final class GiftSetupScreenComponent: Component { let starsFooterText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(starsFooterRawString, attributes: footerAttributes)) if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme { - self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme) + self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: theme.list.itemAccentColor)!, environment.theme) } if let range = starsFooterText.string.range(of: "#") { starsFooterText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: starsFooterText.string)) @@ -1454,7 +1456,7 @@ private final class GiftSetupScreenComponent: Component { } let priceString = presentationStringsFormattedNumber(Int32(starsPrice), environment.dateTimeFormat.groupingSeparator) - let starsAttributedText = NSMutableAttributedString(string: environment.strings.Gift_Send_PayWithStars("#\(priceString)").string, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor) + let starsAttributedText = NSMutableAttributedString(string: environment.strings.Gift_Send_PayWithStars("#\(priceString)").string, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: theme.list.itemPrimaryTextColor) let range = (starsAttributedText.string as NSString).range(of: "#") if range.location != NSNotFound { starsAttributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: range) @@ -1464,7 +1466,7 @@ private final class GiftSetupScreenComponent: Component { let starsSectionSize = self.starsSection.update( transition: transition, component: AnyComponent(ListSectionComponent( - theme: environment.theme, + theme: theme, style: .glass, header: nil, footer: AnyComponent(MultilineTextWithEntitiesComponent( @@ -1474,7 +1476,7 @@ private final class GiftSetupScreenComponent: Component { placeholderColor: .clear, text: .plain(starsFooterText), maximumNumberOfLines: 0, - highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1), + highlightColor: theme.list.itemAccentColor.withAlphaComponent(0.1), highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), highlightAction: { attributes in if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { @@ -1500,7 +1502,7 @@ private final class GiftSetupScreenComponent: Component { )), items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, + theme: theme, style: .glass, title: AnyComponent(VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent( @@ -1508,7 +1510,7 @@ private final class GiftSetupScreenComponent: Component { context: component.context, animationCache: component.context.animationCache, animationRenderer: component.context.animationRenderer, - placeholderColor: environment.theme.list.mediaPlaceholderColor, + placeholderColor: theme.list.mediaPlaceholderColor, text: .plain(starsAttributedText) ) )), @@ -1554,13 +1556,13 @@ private final class GiftSetupScreenComponent: Component { let upgradeFooterText = NSMutableAttributedString(attributedString: parsedString) if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme { - self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme) + self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: theme.list.itemAccentColor)!, environment.theme) } if let range = upgradeFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 { upgradeFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: upgradeFooterText.string)) } - let upgradeAttributedText = NSMutableAttributedString(string: environment.strings.Gift_Send_Upgrade("#\(upgradeStars)").string, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor) + let upgradeAttributedText = NSMutableAttributedString(string: environment.strings.Gift_Send_Upgrade("#\(upgradeStars)").string, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: theme.list.itemPrimaryTextColor) let range = (upgradeAttributedText.string as NSString).range(of: "#") if range.location != NSNotFound { upgradeAttributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: range) @@ -1570,13 +1572,13 @@ private final class GiftSetupScreenComponent: Component { let upgradeSectionSize = self.upgradeSection.update( transition: transition, component: AnyComponent(ListSectionComponent( - theme: environment.theme, + theme: theme, style: .glass, header: nil, footer: AnyComponent(MultilineTextComponent( text: .plain(upgradeFooterText), maximumNumberOfLines: 0, - highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1), + highlightColor: theme.list.itemAccentColor.withAlphaComponent(0.1), highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), highlightAction: { attributes in if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { @@ -1605,7 +1607,7 @@ private final class GiftSetupScreenComponent: Component { )), items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, + theme: theme, style: .glass, title: AnyComponent(VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent( @@ -1613,7 +1615,7 @@ private final class GiftSetupScreenComponent: Component { context: component.context, animationCache: component.context.animationCache, animationRenderer: component.context.animationRenderer, - placeholderColor: environment.theme.list.mediaPlaceholderColor, + placeholderColor: theme.list.mediaPlaceholderColor, text: .plain(upgradeAttributedText) ) )), @@ -1654,27 +1656,27 @@ private final class GiftSetupScreenComponent: Component { let hideSectionSize = self.hideSection.update( transition: transition, component: AnyComponent(ListSectionComponent( - theme: environment.theme, + theme: theme, style: .glass, header: nil, footer: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: hideSectionFooterString, font: Font.regular(presentationData.listsFontSize.itemListBaseHeaderFontSize), - textColor: environment.theme.list.freeTextColor + textColor: theme.list.freeTextColor )), maximumNumberOfLines: 0 )), items: [ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( - theme: environment.theme, + theme: theme, style: .glass, title: AnyComponent(VStack([ AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( string: isSelfGift ? environment.strings.Gift_SendSelf_HideMyName : environment.strings.Gift_Send_HideMyName, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), - textColor: environment.theme.list.itemPrimaryTextColor + textColor: theme.list.itemPrimaryTextColor )), maximumNumberOfLines: 1 ))), @@ -1708,18 +1710,26 @@ private final class GiftSetupScreenComponent: Component { contentHeight -= 77.0 contentHeight += 16.0 - let remains: Int32 = availability.remains + var remains: Int32 = availability.remains + if let auctionState = self.giftAuctionState { + switch auctionState.auctionState { + case let .ongoing(_, _, _, _, _, _, _, giftsLeft, _, _): + remains = giftsLeft + case .finished: + remains = 0 + } + } let total: Int32 = availability.total let position = CGFloat(remains) / CGFloat(total) let sold = total - remains let remainingCountSize = self.remainingCount.update( transition: transition, component: AnyComponent(RemainingCountComponent( - inactiveColor: environment.theme.list.itemBlocksBackgroundColor, + inactiveColor: theme.list.itemBlocksBackgroundColor, activeColors: [UIColor(rgb: 0x72d6ff), UIColor(rgb: 0x32a0f9)], inactiveTitle: environment.strings.Gift_Send_Remains(remains), inactiveValue: "", - inactiveTitleColor: environment.theme.list.itemSecondaryTextColor, + inactiveTitleColor: theme.list.itemSecondaryTextColor, activeTitle: "", activeValue: environment.strings.Gift_Send_Sold(sold), activeTitleColor: .white, @@ -1748,7 +1758,7 @@ private final class GiftSetupScreenComponent: Component { let auctionFooterText = NSMutableAttributedString(attributedString: parsedString) if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme { - self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme) + self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: theme.list.itemAccentColor)!, environment.theme) } if let range = auctionFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 { auctionFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: auctionFooterText.string)) @@ -1759,7 +1769,7 @@ private final class GiftSetupScreenComponent: Component { component: AnyComponent(MultilineTextComponent( text: .plain(auctionFooterText), maximumNumberOfLines: 0, - highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1), + highlightColor: theme.list.itemAccentColor.withAlphaComponent(0.1), highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), highlightAction: { attributes in if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { @@ -1824,7 +1834,7 @@ private final class GiftSetupScreenComponent: Component { var buttonTitleItems: [AnyComponentWithIdentity] = [] if let _ = self.giftAuction { - let buttonAttributedString = NSMutableAttributedString(string: environment.strings.Gift_Setup_PlaceBid, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center) + let buttonAttributedString = NSMutableAttributedString(string: environment.strings.Gift_Setup_PlaceBid, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center) buttonTitleItems.append(AnyComponentWithIdentity(id: "bid", component: AnyComponent( MultilineTextComponent(text: .plain(buttonAttributedString)) ))) @@ -1880,10 +1890,10 @@ private final class GiftSetupScreenComponent: Component { } } } else { - let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center) + let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center) if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.cachedStarImage?.0 { buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string)) - buttonAttributedString.addAttribute(.foregroundColor, value: environment.theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string)) + buttonAttributedString.addAttribute(.foregroundColor, value: theme.list.itemCheckColors.foregroundColor, range: NSRange(range, in: buttonAttributedString.string)) buttonAttributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: buttonAttributedString.string)) buttonAttributedString.addAttribute(.kern, value: 2.0, range: NSRange(range, in: buttonAttributedString.string)) } @@ -1900,9 +1910,9 @@ private final class GiftSetupScreenComponent: Component { component: AnyComponent(ButtonComponent( background: ButtonComponent.Background( style: .glass, - color: environment.theme.list.itemCheckColors.fillColor, - foreground: environment.theme.list.itemCheckColors.foregroundColor, - pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), + color: theme.list.itemCheckColors.fillColor, + foreground: theme.list.itemCheckColors.foregroundColor, + pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9), isShimmering: true ), content: AnyComponentWithIdentity( @@ -1923,7 +1933,7 @@ private final class GiftSetupScreenComponent: Component { let bottomEdgeEffectHeight: CGFloat = bottomPanelHeight let bottomEdgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: availableSize.height - bottomEdgeEffectHeight), size: CGSize(width: fillingSize, height: bottomEdgeEffectHeight)) transition.setFrame(view: self.bottomEdgeEffectView, frame: bottomEdgeEffectFrame) - self.bottomEdgeEffectView.update(content: environment.theme.actionSheet.opaqueItemBackgroundColor, blur: true, alpha: 1.0, rect: bottomEdgeEffectFrame, edge: .bottom, edgeSize: bottomEdgeEffectFrame.height, transition: transition) + self.bottomEdgeEffectView.update(content: theme.list.blocksBackgroundColor, blur: true, alpha: 1.0, rect: bottomEdgeEffectFrame, edge: .bottom, edgeSize: bottomEdgeEffectFrame.height, transition: transition) if self.bottomEdgeEffectView.superview == nil { self.containerView.addSubview(self.bottomEdgeEffectView) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift index fb61d0f35f..9554fb74d3 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift @@ -681,7 +681,7 @@ private final class PeerComponent: Component { } if let icon = self.amountStar.image { - self.amountStar.frame = CGRect(origin: CGPoint(x: amountFrame.minX - icon.size.width, y: floorToScreenPixels((size.height - icon.size.height) / 2.0) - UIScreenPixel), size: icon.size) + self.amountStar.frame = CGRect(origin: CGPoint(x: amountFrame.minX - icon.size.width - 2.0, y: floorToScreenPixels((size.height - icon.size.height) / 2.0) - UIScreenPixel), size: icon.size) } self.separator.backgroundColor = component.theme.list.itemPlainSeparatorColor.cgColor @@ -1335,10 +1335,6 @@ private final class GiftAuctionBidScreenComponent: Component { let previous = self.giftAuctionAcquiredGifts self.giftAuctionAcquiredGifts = acquiredGifts - if let previous, previous.count < acquiredGifts.count { - self.resetSliderValue() - self.addSubview(ConfettiView(frame: self.bounds)) - } self.state?.updated(transition: .easeInOut(duration: 0.25)) })) } @@ -1997,6 +1993,10 @@ private final class GiftAuctionBidScreenComponent: Component { Queue.mainQueue().justDispatch { self.loadAcquiredGifts() } + if !isFirstTime { + self.resetSliderValue() + self.addSubview(ConfettiView(frame: self.bounds)) + } } if case .finished = auctionState?.auctionState, let controller = self.environment?.controller() { @@ -2299,7 +2299,7 @@ private final class GiftAuctionBidScreenComponent: Component { break } } - topBidsComponents.append((peer.id, AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: i, amount: bid, isLast: i == topBidders.count, action: peer.id != component.context.account.peerId ? { [weak self] in self?.openPeer(peer, dismiss: false) } : nil)))) + topBidsComponents.append((peer.id, AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: i, amount: bid, isLast: i == topBidders.count, action: nil)))) i += 1 } From eb7f575bda2a1acea967bc5f09840f5367bdf9cc Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 15 Nov 2025 22:34:08 +0400 Subject: [PATCH 4/5] Fix build --- .../Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift index 9554fb74d3..6f4df0325d 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift @@ -1332,9 +1332,7 @@ private final class GiftAuctionBidScreenComponent: Component { guard let self else { return } - let previous = self.giftAuctionAcquiredGifts self.giftAuctionAcquiredGifts = acquiredGifts - self.state?.updated(transition: .easeInOut(duration: 0.25)) })) } From 74b761c53f95c30c5eef8dedb0d2c80d816e8f09 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 16 Nov 2025 01:22:06 +0400 Subject: [PATCH 5/5] Various improvements --- .../Sources/AccountContext.swift | 4 +- .../Payments/StarGiftsAuctions.swift | 2 +- .../Sources/GiftSetupScreen.swift | 6 +-- .../Sources/GiftAuctionBidScreen.swift | 41 +++++++++++-------- .../Sources/GiftAuctionViewScreen.swift | 8 ++-- .../Sources/SharedAccountContext.swift | 4 +- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index aee3426f80..fa23c3e2f2 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1423,8 +1423,8 @@ public protocol SharedAccountContext: AnyObject { func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController func makeGiftAuctionInfoScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: (() -> Void)?) -> ViewController - func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, text: String?, entities: [MessageTextEntity]?, hideName: Bool, auctionContext: GiftAuctionContext, acquiredGifts: [GiftAuctionAcquiredGift]?) -> ViewController - func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: @escaping ([GiftAuctionAcquiredGift]?) -> Void) -> ViewController + func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, text: String?, entities: [MessageTextEntity]?, hideName: Bool, auctionContext: GiftAuctionContext, acquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>?) -> ViewController + func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: @escaping (Signal<[GiftAuctionAcquiredGift], NoError>) -> Void) -> ViewController func makeGiftAuctionActiveBidsScreen(context: AccountContext) -> ViewController func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift index ef110c3a38..f213cc72b7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGiftsAuctions.swift @@ -272,7 +272,7 @@ extension GiftAuctionContext.State.MyState { } } -public struct GiftAuctionAcquiredGift { +public struct GiftAuctionAcquiredGift: Equatable { public var nameHidden: Bool public let peer: EnginePeer public let date: Int32 diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index f1bfb091a7..1a22c8d6c0 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -46,14 +46,14 @@ private final class GiftSetupScreenComponent: Component { let context: AccountContext let peerId: EnginePeer.Id let subject: GiftSetupScreen.Subject - let auctionAcquiredGifts: [GiftAuctionAcquiredGift]? + let auctionAcquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>? let completion: (() -> Void)? init( context: AccountContext, peerId: EnginePeer.Id, subject: GiftSetupScreen.Subject, - auctionAcquiredGifts: [GiftAuctionAcquiredGift]?, + auctionAcquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>?, completion: (() -> Void)? = nil ) { self.context = context @@ -2034,7 +2034,7 @@ public class GiftSetupScreen: ViewControllerComponentContainer { context: AccountContext, peerId: EnginePeer.Id, subject: Subject, - auctionAcquiredGifts: [GiftAuctionAcquiredGift]? = nil, + auctionAcquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>? = nil, completion: (() -> Void)? = nil ) { self.context = context diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift index 6f4df0325d..e43362ea18 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionBidScreen.swift @@ -957,7 +957,7 @@ private final class GiftAuctionBidScreenComponent: Component { let hideName: Bool let gift: StarGift let auctionContext: GiftAuctionContext - let acquiredGifts: [GiftAuctionAcquiredGift]? + let acquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>? init( context: AccountContext, @@ -967,7 +967,7 @@ private final class GiftAuctionBidScreenComponent: Component { hideName: Bool, gift: StarGift, auctionContext: GiftAuctionContext, - acquiredGifts: [GiftAuctionAcquiredGift]? + acquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>? ) { self.context = context self.toPeerId = toPeerId @@ -1922,8 +1922,6 @@ private final class GiftAuctionBidScreenComponent: Component { } if self.component == nil { - self.giftAuctionAcquiredGifts = component.acquiredGifts - if let starsContext = component.context.starsContext { self.balanceDisposable = (starsContext.state |> deliverOnMainQueue).startStrict(next: { [weak self] state in @@ -1957,6 +1955,18 @@ private final class GiftAuctionBidScreenComponent: Component { peerIds.append(context.account.peerId) self.resetSliderValue(component: component) transition = .immediate + + if let acquiredGifts = component.acquiredGifts { + self.giftAuctionAcquiredGiftsDisposable.set((acquiredGifts + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] acquiredGifts in + self?.giftAuctionAcquiredGifts = acquiredGifts + })) + } else if let acquiredCount = auctionState?.myState.acquiredCount, acquiredCount > 0 { + Queue.mainQueue().justDispatch { + self.loadAcquiredGifts() + } + } } if !peerIds.isEmpty { @@ -1981,13 +1991,7 @@ private final class GiftAuctionBidScreenComponent: Component { } self.state?.updated(transition: transition) - let previousAcquiredCount: Int32 - if let previousState { - previousAcquiredCount = previousState.myState.acquiredCount - } else { - previousAcquiredCount = Int32(component.acquiredGifts?.count ?? 0) - } - if let acquiredCount = auctionState?.myState.acquiredCount, acquiredCount > previousAcquiredCount { + if let acquiredCount = auctionState?.myState.acquiredCount, let previousAcquiredCount = previousState?.myState.acquiredCount, acquiredCount > previousAcquiredCount { Queue.mainQueue().justDispatch { self.loadAcquiredGifts() } @@ -2310,7 +2314,6 @@ private final class GiftAuctionBidScreenComponent: Component { var perks: [([AnimatedTextComponent.Item], String)] = [] - var minBidIsSmall = false var minBidAnimatedItems: [AnimatedTextComponent.Item] = [] var untilNextDropAnimatedItems: [AnimatedTextComponent.Item] = [] var dropsLeftAnimatedItems: [AnimatedTextComponent.Item] = [] @@ -2321,11 +2324,13 @@ private final class GiftAuctionBidScreenComponent: Component { if let myMinBidAmmount = self.giftAuctionState?.myState.minBidAmount { minBidAmount = myMinBidAmmount } - var minBidString = "# \(presentationStringsFormattedNumber(Int32(clamping: minBidAmount), environment.dateTimeFormat.groupingSeparator))" - if minBidAmount > 999999 { - minBidString = "# \(minBidAmount)" - minBidIsSmall = true + var minBidString: String + if minBidAmount > 99999 { + minBidString = compactNumericCountString(Int(minBidAmount), decimalSeparator: environment.dateTimeFormat.decimalSeparator, showDecimalPart: false) + } else { + minBidString = presentationStringsFormattedNumber(Int32(clamping: minBidAmount), environment.dateTimeFormat.groupingSeparator) } + minBidString = "# \(minBidString)" if let hashIndex = minBidString.firstIndex(of: "#") { var prefix = String(minBidString[..?) { self.context = context super.init(context: context, component: GiftAuctionBidScreenComponent( diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionViewScreen.swift index 04adb98839..b461cf3f60 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftAuctionViewScreen.swift @@ -69,6 +69,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent { private var giftAuctionTimer: SwiftSignalKit.Timer? fileprivate var giftAuctionAcquiredGifts: [GiftAuctionAcquiredGift] = [] + private var giftAuctionAcquiredGiftsPromise = ValuePromise<[GiftAuctionAcquiredGift]>() private var giftAuctionAcquiredGiftsDisposable = MetaDisposable() var cachedStarImage: (UIImage, PresentationTheme)? @@ -122,6 +123,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent { return } self.giftAuctionAcquiredGifts = acquiredGifts + self.giftAuctionAcquiredGiftsPromise.set(acquiredGifts) self.updated(transition: .easeInOut(duration: 0.25)) })) } @@ -169,7 +171,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent { } self.dismiss(animated: true) - controller.completion(self.giftAuctionAcquiredGifts) + controller.completion(self.giftAuctionAcquiredGiftsPromise.get()) } func openPeer(_ peer: EnginePeer, dismiss: Bool = true) { @@ -975,12 +977,12 @@ final class GiftAuctionViewSheetComponent: CombinedComponent { } public final class GiftAuctionViewScreen: ViewControllerComponentContainer { - fileprivate let completion: ([GiftAuctionAcquiredGift]?) -> Void + fileprivate let completion: (Signal<[GiftAuctionAcquiredGift], NoError>) -> Void public init( context: AccountContext, auctionContext: GiftAuctionContext, - completion: @escaping ([GiftAuctionAcquiredGift]?) -> Void + completion: @escaping (Signal<[GiftAuctionAcquiredGift], NoError>) -> Void ) { self.completion = completion diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 0997683de1..716f336389 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -3846,11 +3846,11 @@ public final class SharedAccountContextImpl: SharedAccountContext { return GiftAuctionInfoScreen(context: context, auctionContext: auctionContext, completion: completion) } - public func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, text: String?, entities: [MessageTextEntity]?, hideName: Bool, auctionContext: GiftAuctionContext, acquiredGifts: [GiftAuctionAcquiredGift]?) -> ViewController { + public func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, text: String?, entities: [MessageTextEntity]?, hideName: Bool, auctionContext: GiftAuctionContext, acquiredGifts: Signal<[GiftAuctionAcquiredGift], NoError>?) -> ViewController { return GiftAuctionBidScreen(context: context, toPeerId: toPeerId, text: text, entities: entities, hideName: hideName, auctionContext: auctionContext, acquiredGifts: acquiredGifts) } - public func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: @escaping ([GiftAuctionAcquiredGift]?) -> Void) -> ViewController { + public func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: @escaping (Signal<[GiftAuctionAcquiredGift], NoError>) -> Void) -> ViewController { return GiftAuctionViewScreen(context: context, auctionContext: auctionContext, completion: completion) }