From 8acb1d12eeb56f95cc3ae77fb81746bd386720e7 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Sun, 11 Aug 2024 15:27:39 +0400 Subject: [PATCH] Stars reactions improvements --- .../ApiUtils/ReactionsMessageAttribute.swift | 4 +- .../SyncCore_ReactionsMessageAttribute.swift | 16 +- .../DefaultDarkPresentationTheme.swift | 12 +- .../DefaultDarkTintedPresentationTheme.swift | 12 +- .../Sources/DefaultDayPresentationTheme.swift | 24 +- .../Sources/ChatSendStarsScreen.swift | 106 +++++++-- .../Sources/PeerAllowedReactionsScreen.swift | 60 ++++- ...ChatControllerOpenMessageContextMenu.swift | 16 +- ...rollerOpenMessageReactionContextMenu.swift | 205 +++++++++--------- 9 files changed, 294 insertions(+), 161 deletions(-) diff --git a/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift b/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift index 15a9220c15..3515c36ff4 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ReactionsMessageAttribute.swift @@ -61,7 +61,7 @@ extension ReactionsMessageAttribute { switch item { case let .messageReactor(flags, peerId, count): topPeers.append(ReactionsMessageAttribute.TopPeer( - peerId: peerId.peerId, + peerId: peerId?.peerId, count: count, isTop: (flags & (1 << 0)) != 0, isMy: (flags & (1 << 1)) != 0) @@ -251,7 +251,7 @@ extension ReactionsMessageAttribute { switch item { case let .messageReactor(flags, peerId, count): topPeers.append(ReactionsMessageAttribute.TopPeer( - peerId: peerId.peerId, + peerId: peerId?.peerId, count: count, isTop: (flags & (1 << 0)) != 0, isMy: (flags & (1 << 1)) != 0) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift index ca2e16c90c..9db3fa1087 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReactionsMessageAttribute.swift @@ -329,12 +329,12 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute { } public struct TopPeer: Equatable, PostboxCoding { - public var peerId: PeerId + public var peerId: PeerId? public var count: Int32 public var isTop: Bool public var isMy: Bool - public init(peerId: PeerId, count: Int32, isTop: Bool, isMy: Bool) { + public init(peerId: PeerId?, count: Int32, isTop: Bool, isMy: Bool) { self.peerId = peerId self.count = count self.isMy = isMy @@ -342,14 +342,22 @@ public final class ReactionsMessageAttribute: Equatable, MessageAttribute { } public init(decoder: PostboxDecoder) { - self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) + if let peerId = decoder.decodeOptionalInt64ForKey("p") { + self.peerId = PeerId(peerId) + } else { + self.peerId = nil + } self.count = decoder.decodeInt32ForKey("c", orElse: 0) self.isTop = decoder.decodeBoolForKey("t", orElse: false) self.isMy = decoder.decodeBoolForKey("m", orElse: false) } public func encode(_ encoder: PostboxEncoder) { - encoder.encodeInt64(self.peerId.toInt64(), forKey: "p") + if let peerId = self.peerId { + encoder.encodeInt64(peerId.toInt64(), forKey: "p") + } else { + encoder.encodeNil(forKey: "p") + } encoder.encodeInt32(self.count, forKey: "c") encoder.encodeBool(self.isTop, forKey: "t") encoder.encodeBool(self.isMy, forKey: "m") diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift index 4749936845..d80705ed74 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkPresentationTheme.swift @@ -534,7 +534,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -550,7 +550,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) @@ -572,7 +572,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -588,7 +588,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) @@ -607,7 +607,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -623,7 +623,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) diff --git a/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift index 24cd2164c4..c3f7ff89ed 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDarkTintedPresentationTheme.swift @@ -747,7 +747,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -763,7 +763,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) @@ -783,7 +783,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -799,7 +799,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) @@ -818,7 +818,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ), @@ -834,7 +834,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1), reactionActiveMediaPlaceholder: UIColor(rgb: 0x000000, alpha: 0.1) ) diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index 6e8c85faa9..69b9a6813a 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -601,7 +601,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -617,7 +617,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) @@ -656,7 +656,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -672,7 +672,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) @@ -713,7 +713,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -729,7 +729,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) @@ -765,7 +765,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -781,7 +781,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) @@ -823,7 +823,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -839,7 +839,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) @@ -880,7 +880,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ), @@ -896,7 +896,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio reactionStarsInactiveBackground: UIColor(rgb: 0xFEF1D4, alpha: 1.0), reactionStarsInactiveForeground: UIColor(rgb: 0xD3720A), reactionStarsActiveBackground: UIColor(rgb: 0xD3720A, alpha: 1.0), - reactionStarsActiveForeground: .clear, + reactionStarsActiveForeground: .white, reactionInactiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2), reactionActiveMediaPlaceholder: UIColor(rgb: 0xffffff, alpha: 0.2) ) diff --git a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift index fd122e068e..01eaa356b0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift @@ -469,14 +469,14 @@ private final class PeerComponent: Component { let context: AccountContext let theme: PresentationTheme let strings: PresentationStrings - let peer: EnginePeer + let peer: EnginePeer? let count: Int init( context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, - peer: EnginePeer, + peer: EnginePeer?, count: Int ) { self.context = context @@ -535,7 +535,11 @@ private final class PeerComponent: Component { let avatarSize = CGSize(width: 60.0, height: 60.0) let avatarFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: avatarSize) avatarNode.frame = avatarFrame - avatarNode.setPeer(context: component.context, theme: component.theme, peer: component.peer) + if let peer = component.peer { + avatarNode.setPeer(context: component.context, theme: component.theme, peer: peer) + } else { + avatarNode.setPeer(context: component.context, theme: component.theme, peer: nil, overrideImage: .anonymousSavedMessagesIcon) + } avatarNode.updateSize(size: avatarFrame.size) let badgeSize = self.badge.update( @@ -557,10 +561,18 @@ private final class PeerComponent: Component { let titleSpacing: CGFloat = 8.0 + let peerTitle: String + if let peer = component.peer { + peerTitle = peer.compactDisplayTitle + } else { + //TODO:localize + peerTitle = "Anonymous" + } + let titleSize = self.title.update( transition: .immediate, component: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: component.peer.compactDisplayTitle, font: Font.regular(11.0), textColor: component.theme.list.itemPrimaryTextColor)) + text: .plain(NSAttributedString(string: peerTitle, font: Font.regular(11.0), textColor: component.theme.list.itemPrimaryTextColor)) )), environment: {}, containerSize: CGSize(width: avatarSize.width + 10.0 * 2.0, height: 100.0) @@ -647,7 +659,7 @@ private final class SliderBackgroundComponent: Component { self.sliderBackground.backgroundColor = UIColor(rgb: 0xEEEEEF) self.sliderForeground.backgroundColor = UIColor(rgb: 0xFFB10D) self.topForegroundLine.backgroundColor = component.theme.list.plainBackgroundColor.cgColor - self.topBackgroundLine.backgroundColor = UIColor(white: 0.0, alpha: 0.1).cgColor + self.topBackgroundLine.backgroundColor = component.theme.list.plainBackgroundColor.cgColor transition.setFrame(view: self.sliderBackground, frame: CGRect(origin: CGPoint(), size: availableSize)) @@ -817,7 +829,7 @@ private final class ChatSendStarsScreenComponent: Component { private var topPeersTitleBackground: SimpleLayer? private var topPeersTitle: ComponentView? - private var topPeerItems: [EnginePeer.Id: ComponentView] = [:] + private var topPeerItems: [ChatSendStarsScreen.TopPeer.Id: ComponentView] = [:] private let actionButton = ComponentView() private let buttonDescriptionText = ComponentView() @@ -1375,34 +1387,55 @@ private final class ChatSendStarsScreenComponent: Component { transition.setFrame(layer: topPeersLeftSeparator, frame: CGRect(origin: CGPoint(x: sideInset, y: separatorY), size: CGSize(width: max(0.0, topPeersBackgroundFrame.minX - separatorSpacing - sideInset), height: UIScreenPixel))) transition.setFrame(layer: topPeersRightSeparator, frame: CGRect(origin: CGPoint(x: topPeersBackgroundFrame.maxX + separatorSpacing, y: separatorY), size: CGSize(width: max(0.0, availableSize.width - sideInset - (topPeersBackgroundFrame.maxX + separatorSpacing)), height: UIScreenPixel))) - var validIds: [EnginePeer.Id] = [] + var validIds: [ChatSendStarsScreen.TopPeer.Id] = [] var items: [(itemView: ComponentView, size: CGSize)] = [] for topPeer in component.topPeers { - validIds.append(topPeer.peer.id) + validIds.append(topPeer.id) let itemView: ComponentView - if let current = self.topPeerItems[topPeer.peer.id] { + if let current = self.topPeerItems[topPeer.id] { itemView = current } else { itemView = ComponentView() - self.topPeerItems[topPeer.peer.id] = itemView + self.topPeerItems[topPeer.id] = itemView } let itemSize = itemView.update( transition: .immediate, - component: AnyComponent(PeerComponent( - context: component.context, - theme: environment.theme, - strings: environment.strings, - peer: topPeer.peer, - count: topPeer.count + component: AnyComponent(PlainButtonComponent( + content: AnyComponent(PeerComponent( + context: component.context, + theme: environment.theme, + strings: environment.strings, + peer: topPeer.peer, + count: topPeer.count + )), + effectAlignment: .center, + action: { [weak self] in + guard let self, let component = self.component, let peer = topPeer.peer else { + return + } + if let peerInfoController = component.context.sharedContext.makePeerInfoController( + context: component.context, + updatedPresentationData: nil, + peer: peer._asPeer(), + mode: .generic, + avatarInitiallyExpanded: false, + fromChat: false, + requestsContext: nil + ) { + self.environment?.controller()?.push(peerInfoController) + } + }, + isEnabled: topPeer.peer != nil && topPeer.peer?.id != component.context.account.peerId, + animateAlpha: false )), environment: {}, containerSize: CGSize(width: 200.0, height: 200.0) ) items.append((itemView, itemSize)) } - var removedIds: [EnginePeer.Id] = [] + var removedIds: [ChatSendStarsScreen.TopPeer.Id] = [] for (id, itemView) in self.topPeerItems { if !validIds.contains(id) { removedIds.append(id) @@ -1624,10 +1657,22 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { } fileprivate final class TopPeer: Equatable { - let peer: EnginePeer + struct Id: Hashable { + var value: EnginePeer.Id? + + init(_ value: EnginePeer.Id?) { + self.value = value + } + } + + var id: Id { + return Id(self.peer?.id) + } + + let peer: EnginePeer? let count: Int - init(peer: EnginePeer, count: Int) { + init(peer: EnginePeer?, count: Int) { self.peer = peer self.count = count } @@ -1653,6 +1698,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { private let context: AccountContext + private var didPlayAppearAnimation: Bool = false private var isDismissed: Bool = false private var presenceDisposable: Disposable? @@ -1693,8 +1739,12 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { self.view.disablesInteractiveModalDismiss = true - if let componentView = self.node.hostView.componentView as? ChatSendStarsScreenComponent.View { - componentView.animateIn() + if !self.didPlayAppearAnimation { + self.didPlayAppearAnimation = true + + if let componentView = self.node.hostView.componentView as? ChatSendStarsScreenComponent.View { + componentView.animateIn() + } } } @@ -1715,7 +1765,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { currentSentAmount = Int(myPeer.count) } - var topPeers = topPeers.sorted(by: { $0.count < $1.count }) + var topPeers = topPeers.sorted(by: { $0.count > $1.count }) if topPeers.count > 3 { topPeers = Array(topPeers.prefix(3)) } @@ -1723,7 +1773,9 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { return combineLatest( context.engine.data.get( TelegramEngine.EngineData.Item.Peer.Peer(id: peerId), - EngineDataMap(topPeers.map(\.peerId).map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))) + EngineDataMap(topPeers.map(\.peerId).compactMap { + $0.flatMap(TelegramEngine.EngineData.Item.Peer.Peer.init(id:)) + }) ), balance ) @@ -1738,7 +1790,13 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer { balance: balance, currentSentAmount: currentSentAmount, topPeers: topPeers.compactMap { topPeer -> ChatSendStarsScreen.TopPeer? in - guard let topPeerValue = topPeerMap[topPeer.peerId] else { + guard let topPeerId = topPeer.peerId else { + return ChatSendStarsScreen.TopPeer( + peer: nil, + count: Int(topPeer.count) + ) + } + guard let topPeerValue = topPeerMap[topPeerId] else { return nil } guard let topPeerValue else { diff --git a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift index 82fbea852e..825c9e4dd8 100644 --- a/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift +++ b/submodules/TelegramUI/Components/PeerAllowedReactionsScreen/Sources/PeerAllowedReactionsScreen.swift @@ -142,6 +142,9 @@ final class PeerAllowedReactionsScreenComponent: Component { if !self.isEnabled { enabledReactions.removeAll() } + + enabledReactions.removeAll(where: { $0.reaction == .stars }) + guard let availableReactions = self.availableReactions else { return true } @@ -209,6 +212,8 @@ final class PeerAllowedReactionsScreenComponent: Component { guard var enabledReactions = self.enabledReactions else { return } + enabledReactions.removeAll(where: { $0.reaction == .stars }) + if !self.isEnabled { enabledReactions.removeAll() } @@ -357,7 +362,20 @@ final class PeerAllowedReactionsScreenComponent: Component { if let current = self.enabledReactions { enabledReactions = current } else { - enabledReactions = component.initialContent.enabledReactions + if let value = component.initialContent.reactionSettings?.starsAllowed { + self.areStarsReactionsEnabled = value + } else { + self.areStarsReactionsEnabled = component.initialContent.isStarReactionAvailable + } + + var enabledReactionsValue = component.initialContent.enabledReactions + if self.areStarsReactionsEnabled { + if let item = component.initialContent.availableReactions?.reactions.first(where: { $0.value == .stars }) { + enabledReactionsValue.insert(EmojiComponentReactionItem(reaction: item.value, file: item.selectAnimation), at: 0) + } + } + + enabledReactions = enabledReactionsValue self.enabledReactions = enabledReactions self.availableReactions = component.initialContent.availableReactions self.isEnabled = component.initialContent.isEnabled @@ -369,11 +387,6 @@ final class PeerAllowedReactionsScreenComponent: Component { ) } self.allowedReactionCount = (component.initialContent.reactionSettings?.maxReactionCount).flatMap(Int.init) ?? 11 - if let value = component.initialContent.reactionSettings?.starsAllowed { - self.areStarsReactionsEnabled = value - } else { - self.areStarsReactionsEnabled = component.initialContent.isStarReactionAvailable - } } var caretPosition = self.caretPosition ?? enabledReactions.count caretPosition = max(0, min(enabledReactions.count, caretPosition)) @@ -578,6 +591,11 @@ final class PeerAllowedReactionsScreenComponent: Component { enabledReactions.append(EmojiComponentReactionItem(reaction: reactionItem.value, file: reactionItem.selectAnimation)) } } + if self.areStarsReactionsEnabled { + if let item = component.initialContent.availableReactions?.reactions.first(where: { $0.value == .stars }) { + enabledReactions.insert(EmojiComponentReactionItem(reaction: item.value, file: item.selectAnimation), at: 0) + } + } self.enabledReactions = enabledReactions self.caretPosition = enabledReactions.count } @@ -938,10 +956,33 @@ final class PeerAllowedReactionsScreenComponent: Component { title: "Enable Paid Reactions", value: self.areStarsReactionsEnabled, valueUpdated: { [weak self] value in - guard let self else { + guard let self, let component = self.component else { return } self.areStarsReactionsEnabled = value + + var enabledReactions = self.enabledReactions ?? [] + if self.areStarsReactionsEnabled { + if let item = component.initialContent.availableReactions?.reactions.first(where: { $0.value == .stars }) { + enabledReactions.insert(EmojiComponentReactionItem(reaction: item.value, file: item.selectAnimation), at: 0) + if let caretPosition = self.caretPosition { + self.caretPosition = min(enabledReactions.count, caretPosition + 1) + } + } + } else { + if let index = enabledReactions.firstIndex(where: { $0.reaction == .stars }) { + enabledReactions.remove(at: index) + if let caretPosition = self.caretPosition, caretPosition > index { + self.caretPosition = max(0, caretPosition - 1) + } + } + } + + self.enabledReactions = enabledReactions + + if !self.isUpdating { + self.state?.updated(transition: .spring(duration: 0.25)) + } } ))) ] @@ -1138,6 +1179,11 @@ final class PeerAllowedReactionsScreenComponent: Component { self.recenterOnCaret = true } self.enabledReactions = enabledReactions + + if !enabledReactions.contains(where: { $0.reaction == .stars }) { + self.areStarsReactionsEnabled = false + } + if !self.isUpdating { self.state?.updated(transition: .spring(duration: 0.25)) } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift index bbce431bf6..95e30d9470 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift @@ -332,6 +332,18 @@ extension ChatControllerImpl { controller?.view.endEditing(true) if case .stars = chosenUpdatedReaction.reaction { + if isLarge { + if let controller { + controller.dismiss(completion: { [weak self] in + guard let self else { + return + } + self.openMessageSendStarsScreen(message: message) + }) + } + return + } + let isFirst = !"".isEmpty self.chatDisplayNode.historyNode.forEachItemNode { itemNode in @@ -362,7 +374,9 @@ extension ChatControllerImpl { return } if let itemNode = itemNode, let targetView = itemNode.targetReactionView(value: chosenReaction) { - self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view)) + if !"".isEmpty { + self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view)) + } } }, completion: {}) } else { diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift index 1ad580542a..174045146e 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenMessageReactionContextMenu.swift @@ -164,107 +164,10 @@ extension ChatControllerImpl { self.window?.presentInGlobalOverlay(controller) }) } else { - if case .stars = value, let reactionsAttribute = mergedMessageReactions(attributes: message.attributes, isTags: false) { + if case .stars = value { gesture?.cancel() cancelParentGestures(view: sourceView) - let _ = (ChatSendStarsScreen.initialData(context: self.context, peerId: message.id.peerId, topPeers: reactionsAttribute.topPeers) - |> deliverOnMainQueue).start(next: { [weak self] initialData in - guard let self, let initialData else { - return - } - HapticFeedback().tap() - self.push(ChatSendStarsScreen(context: self.context, initialData: initialData, completion: { [weak self] amount, isBecomingTop, transitionOut in - guard let self, amount > 0 else { - return - } - - var sourceItemNode: ChatMessageItemView? - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - if itemNode.item?.message.id == message.id { - sourceItemNode = itemNode - return - } - } - } - - if let itemNode = sourceItemNode, let item = itemNode.item, let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: .stars) { - var reactionItem: ReactionItem? - - for reaction in availableReactions.reactions { - guard let centerAnimation = reaction.centerAnimation else { - continue - } - guard let aroundAnimation = reaction.aroundAnimation else { - continue - } - if reaction.value == .stars { - reactionItem = ReactionItem( - reaction: ReactionItem.Reaction(rawValue: reaction.value), - appearAnimation: reaction.appearAnimation, - stillAnimation: reaction.selectAnimation, - listAnimation: centerAnimation, - largeListAnimation: reaction.activateAnimation, - applicationAnimation: aroundAnimation, - largeApplicationAnimation: reaction.effectAnimation, - isCustom: false - ) - break - } - } - - if let reactionItem { - let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.chatDisplayNode.historyNode.takeGenericReactionEffect()) - - self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation) - - self.view.window?.addSubview(standaloneReactionAnimation.view) - standaloneReactionAnimation.frame = self.chatDisplayNode.bounds - standaloneReactionAnimation.animateOutToReaction( - context: self.context, - theme: self.presentationData.theme, - item: reactionItem, - value: .stars, - sourceView: transitionOut.sourceView, - targetView: targetView, - hideNode: false, - forceSwitchToInlineImmediately: false, - animateTargetContainer: nil, - addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in - guard let self else { - return - } - self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation) - standaloneReactionAnimation.frame = self.chatDisplayNode.bounds - self.chatDisplayNode.addSubnode(standaloneReactionAnimation) - }, - onHit: { [weak self, weak itemNode] in - guard let self else { - return - } - - if isBecomingTop { - self.chatDisplayNode.animateQuizCorrectOptionSelected() - } - - if let itemNode, let targetView = itemNode.targetReactionView(value: .stars) { - self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view)) - } - }, - completion: { [weak standaloneReactionAnimation] in - standaloneReactionAnimation?.view.removeFromSuperview() - } - ) - } - } - - #if !DEBUG - let _ = self.context.engine.messages.sendStarsReaction(id: message.id, count: Int(amount)) - #endif - - self.displayOrUpdateSendStarsUndo(messageId: message.id, count: Int(amount)) - })) - }) + self.openMessageSendStarsScreen(message: message) return } @@ -465,6 +368,110 @@ extension ChatControllerImpl { } } + func openMessageSendStarsScreen(message: Message) { + guard let reactionsAttribute = mergedMessageReactions(attributes: message.attributes, isTags: false) else { + return + } + let _ = (ChatSendStarsScreen.initialData(context: self.context, peerId: message.id.peerId, topPeers: reactionsAttribute.topPeers) + |> deliverOnMainQueue).start(next: { [weak self] initialData in + guard let self, let initialData else { + return + } + HapticFeedback().tap() + self.push(ChatSendStarsScreen(context: self.context, initialData: initialData, completion: { [weak self] amount, isBecomingTop, transitionOut in + guard let self, amount > 0 else { + return + } + + var sourceItemNode: ChatMessageItemView? + self.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + if itemNode.item?.message.id == message.id { + sourceItemNode = itemNode + return + } + } + } + + if let itemNode = sourceItemNode, let item = itemNode.item, let availableReactions = item.associatedData.availableReactions, let targetView = itemNode.targetReactionView(value: .stars) { + var reactionItem: ReactionItem? + + for reaction in availableReactions.reactions { + guard let centerAnimation = reaction.centerAnimation else { + continue + } + guard let aroundAnimation = reaction.aroundAnimation else { + continue + } + if reaction.value == .stars { + reactionItem = ReactionItem( + reaction: ReactionItem.Reaction(rawValue: reaction.value), + appearAnimation: reaction.appearAnimation, + stillAnimation: reaction.selectAnimation, + listAnimation: centerAnimation, + largeListAnimation: reaction.activateAnimation, + applicationAnimation: aroundAnimation, + largeApplicationAnimation: reaction.effectAnimation, + isCustom: false + ) + break + } + } + + if let reactionItem { + let standaloneReactionAnimation = StandaloneReactionAnimation(genericReactionEffect: self.chatDisplayNode.historyNode.takeGenericReactionEffect()) + + self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation) + + self.view.window?.addSubview(standaloneReactionAnimation.view) + standaloneReactionAnimation.frame = self.chatDisplayNode.bounds + standaloneReactionAnimation.animateOutToReaction( + context: self.context, + theme: self.presentationData.theme, + item: reactionItem, + value: .stars, + sourceView: transitionOut.sourceView, + targetView: targetView, + hideNode: false, + forceSwitchToInlineImmediately: false, + animateTargetContainer: nil, + addStandaloneReactionAnimation: { [weak self] standaloneReactionAnimation in + guard let self else { + return + } + self.chatDisplayNode.messageTransitionNode.addMessageStandaloneReactionAnimation(messageId: item.message.id, standaloneReactionAnimation: standaloneReactionAnimation) + standaloneReactionAnimation.frame = self.chatDisplayNode.bounds + self.chatDisplayNode.addSubnode(standaloneReactionAnimation) + }, + onHit: { [weak self, weak itemNode] in + guard let self else { + return + } + + if isBecomingTop { + self.chatDisplayNode.animateQuizCorrectOptionSelected() + } + + if let itemNode, let targetView = itemNode.targetReactionView(value: .stars) { + self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view)) + } + }, + completion: { [weak standaloneReactionAnimation] in + standaloneReactionAnimation?.view.removeFromSuperview() + } + ) + } + } + + #if !DEBUG + let _ = self.context.engine.messages.sendStarsReaction(id: message.id, count: Int(amount)) + #endif + + self.displayOrUpdateSendStarsUndo(messageId: message.id, count: Int(amount)) + })) + }) + } + func displayOrUpdateSendStarsUndo(messageId: EngineMessage.Id, count: Int) { if self.currentSendStarsUndoMessageId != messageId { if let current = self.currentSendStarsUndoController {