Stars reactions improvements

This commit is contained in:
Isaac 2024-08-11 15:27:39 +04:00
parent 099e813b62
commit 8acb1d12ee
9 changed files with 294 additions and 161 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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)
)

View File

@ -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)
)

View File

@ -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)
)

View File

@ -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<Empty>?
private var topPeerItems: [EnginePeer.Id: ComponentView<Empty>] = [:]
private var topPeerItems: [ChatSendStarsScreen.TopPeer.Id: ComponentView<Empty>] = [:]
private let actionButton = ComponentView<Empty>()
private let buttonDescriptionText = ComponentView<Empty>()
@ -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<Empty>, size: CGSize)] = []
for topPeer in component.topPeers {
validIds.append(topPeer.peer.id)
validIds.append(topPeer.id)
let itemView: ComponentView<Empty>
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(
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,10 +1739,14 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
self.view.disablesInteractiveModalDismiss = true
if !self.didPlayAppearAnimation {
self.didPlayAppearAnimation = true
if let componentView = self.node.hostView.componentView as? ChatSendStarsScreenComponent.View {
componentView.animateIn()
}
}
}
public static func initialData(context: AccountContext, peerId: EnginePeer.Id, topPeers: [ReactionsMessageAttribute.TopPeer]) -> Signal<InitialData?, NoError> {
let balance: Signal<Int64?, NoError>
@ -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 {

View File

@ -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))
}

View File

@ -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,8 +374,10 @@ extension ChatControllerImpl {
return
}
if let itemNode = itemNode, let targetView = itemNode.targetReactionView(value: chosenReaction) {
if !"".isEmpty {
self.chatDisplayNode.wrappingNode.triggerRipple(at: targetView.convert(targetView.bounds.center, to: self.chatDisplayNode.view))
}
}
}, completion: {})
} else {
controller.dismiss()

View File

@ -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 {