Stars reactions improvements

This commit is contained in:
Isaac 2024-08-13 21:14:59 +08:00
parent 524ce21f5e
commit da45de818a
5 changed files with 121 additions and 31 deletions

View File

@ -842,12 +842,11 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
case let .peer(peerId): case let .peer(peerId):
if peerId != item.context.account.peerId { if peerId != item.context.account.peerId {
if peerId.isGroupOrChannel && item.message.author != nil { if peerId.isGroupOrChannel && item.message.author != nil {
var isBroadcastChannel = false if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case let .broadcast(info) = peer.info {
if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { if item.message.author?.id != peer.id, info.flags.contains(.messagesShouldHaveProfiles) {
isBroadcastChannel = true hasAvatar = incoming
} }
} else {
if !isBroadcastChannel {
hasAvatar = true hasAvatar = true
} }
} }

View File

@ -464,14 +464,15 @@ public class ChatMessageStickerItemNode: ChatMessageItemView {
case let .peer(peerId): case let .peer(peerId):
if !peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) { if !peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
if peerId.isGroupOrChannel && item.message.author != nil { if peerId.isGroupOrChannel && item.message.author != nil {
var isBroadcastChannel = false if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case let .broadcast(info) = peer.info {
if let peer = item.message.peers[item.message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { if item.message.author?.id != peer.id, info.flags.contains(.messagesShouldHaveProfiles) {
isBroadcastChannel = true hasAvatar = incoming
}
} else {
hasAvatar = true
} }
if !isBroadcastChannel { if case .customChatContents = item.chatLocation {
hasAvatar = true
} else if case .customChatContents = item.chatLocation {
hasAvatar = false hasAvatar = false
} }
} }

View File

@ -479,14 +479,14 @@ private final class PeerComponent: Component {
let theme: PresentationTheme let theme: PresentationTheme
let strings: PresentationStrings let strings: PresentationStrings
let peer: EnginePeer? let peer: EnginePeer?
let count: Int let count: String
init( init(
context: AccountContext, context: AccountContext,
theme: PresentationTheme, theme: PresentationTheme,
strings: PresentationStrings, strings: PresentationStrings,
peer: EnginePeer?, peer: EnginePeer?,
count: Int count: String
) { ) {
self.context = context self.context = context
self.theme = theme self.theme = theme
@ -555,7 +555,7 @@ private final class PeerComponent: Component {
transition: .immediate, transition: .immediate,
component: AnyComponent(PeerBadgeComponent( component: AnyComponent(PeerBadgeComponent(
theme: component.theme, theme: component.theme,
title: "\(component.count)" title: component.count
)), )),
environment: {}, environment: {},
containerSize: CGSize(width: 200.0, height: 200.0) containerSize: CGSize(width: 200.0, height: 200.0)
@ -1046,6 +1046,7 @@ private final class ChatSendStarsScreenComponent: Component {
private var balance: Int64? private var balance: Int64?
private var amount: Amount = Amount(realValue: 1, maxRealValue: 1000, maxSliderValue: 1000, isLogarithmic: true) private var amount: Amount = Amount(realValue: 1, maxRealValue: 1000, maxSliderValue: 1000, isLogarithmic: true)
private var didChangeAmount: Bool = false
private var isAnonymous: Bool = false private var isAnonymous: Bool = false
private var cachedStarImage: (UIImage, PresentationTheme)? private var cachedStarImage: (UIImage, PresentationTheme)?
@ -1291,6 +1292,7 @@ private final class ChatSendStarsScreenComponent: Component {
return return
} }
self.amount = self.amount.withSliderValue(value) self.amount = self.amount.withSliderValue(value)
self.didChangeAmount = true
self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint())) self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint()))
@ -1640,10 +1642,16 @@ private final class ChatSendStarsScreenComponent: Component {
if let index = mappedTopPeers.firstIndex(where: { $0.isMy }) { if let index = mappedTopPeers.firstIndex(where: { $0.isMy }) {
mappedTopPeers.remove(at: index) mappedTopPeers.remove(at: index)
} }
var myCount = Int(self.amount.realValue)
var myCount = 0
if let myTopPeer = component.myTopPeer { if let myTopPeer = component.myTopPeer {
myCount += myTopPeer.count myCount += myTopPeer.count
} }
var myCountAddition = 0
if self.didChangeAmount {
myCountAddition = Int(self.amount.realValue)
}
myCount += myCountAddition
mappedTopPeers.append(ChatSendStarsScreen.TopPeer( mappedTopPeers.append(ChatSendStarsScreen.TopPeer(
peer: self.isAnonymous ? nil : component.myPeer, peer: self.isAnonymous ? nil : component.myPeer,
isMy: true, isMy: true,
@ -1676,6 +1684,11 @@ private final class ChatSendStarsScreenComponent: Component {
self.topPeerItems[topPeer.id] = itemView self.topPeerItems[topPeer.id] = itemView
} }
var itemCountString = "\(topPeer.count)"
if topPeer.isMy && myCountAddition != 0 && topPeer.count > myCountAddition {
itemCountString = "\(topPeer.count - myCountAddition) +\(myCountAddition)"
}
let itemSize = itemView.update( let itemSize = itemView.update(
transition: .immediate, transition: .immediate,
component: AnyComponent(PlainButtonComponent( component: AnyComponent(PlainButtonComponent(
@ -1684,7 +1697,7 @@ private final class ChatSendStarsScreenComponent: Component {
theme: environment.theme, theme: environment.theme,
strings: environment.strings, strings: environment.strings,
peer: topPeer.peer, peer: topPeer.peer,
count: topPeer.count count: itemCountString
)), )),
effectAlignment: .center, effectAlignment: .center,
action: { [weak self] in action: { [weak self] in

View File

@ -387,8 +387,46 @@ extension ChatControllerImpl {
} }
} }
self.context.engine.messages.sendStarsReaction(id: message.id, count: 1, isAnonymous: false) guard let starsContext = self.context.starsContext else {
self.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1) return
}
let _ = (starsContext.state
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] state in
guard let strongSelf = self, let balance = state?.balance else {
return
}
if balance < 1 {
controller?.dismiss(completion: {
guard let strongSelf = self else {
return
}
let _ = (strongSelf.context.engine.payments.starsTopUpOptions()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak strongSelf] options in
guard let strongSelf, let peerId = strongSelf.chatLocation.peerId else {
return
}
guard let starsContext = strongSelf.context.starsContext else {
return
}
let purchaseScreen = strongSelf.context.sharedContext.makeStarsPurchaseScreen(context: strongSelf.context, starsContext: starsContext, options: options, purpose: .transfer(peerId: peerId, requiredStars: 1), completion: { result in
let _ = result
//TODO:release
})
strongSelf.push(purchaseScreen)
})
})
return
}
strongSelf.context.engine.messages.sendStarsReaction(id: message.id, count: 1, isAnonymous: false)
strongSelf.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
})
} else { } else {
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction

View File

@ -29,6 +29,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let elevatedLayout: Bool private let elevatedLayout: Bool
private let placementPosition: UndoOverlayController.Position private let placementPosition: UndoOverlayController.Position
private var statusNode: RadialStatusNode? private var statusNode: RadialStatusNode?
private var didStartStatusNode: Bool = false
private let timerTextNode: ImmediateTextNode private let timerTextNode: ImmediateTextNode
private let avatarNode: AvatarNode? private let avatarNode: AvatarNode?
private let iconNode: ASImageNode? private let iconNode: ASImageNode?
@ -67,6 +68,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private var isTimeoutDisabled: Bool = false private var isTimeoutDisabled: Bool = false
private var originalRemainingSeconds: Double private var originalRemainingSeconds: Double
private var remainingSeconds: Double private var remainingSeconds: Double
private let undoTextColor: UIColor
private var timer: SwiftSignalKit.Timer? private var timer: SwiftSignalKit.Timer?
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
@ -413,8 +415,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animatedTextItems = textItems self.animatedTextItems = textItems
displayUndo = true displayUndo = true
self.originalRemainingSeconds = 4.5 self.originalRemainingSeconds = 4.9
isUserInteractionEnabled = true isUserInteractionEnabled = true
self.statusNode = RadialStatusNode(backgroundNodeColor: .clear)
case let .messagesUnpinned(title, text, undo, isHidden): case let .messagesUnpinned(title, text, undo, isHidden):
self.avatarNode = nil self.avatarNode = nil
self.iconNode = nil self.iconNode = nil
@ -1246,6 +1250,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} }
self.remainingSeconds = self.originalRemainingSeconds self.remainingSeconds = self.originalRemainingSeconds
self.undoTextColor = undoTextColor
self.undoButtonTextNode = ImmediateTextNode() self.undoButtonTextNode = ImmediateTextNode()
self.undoButtonTextNode.displaysAsynchronously = false self.undoButtonTextNode.displaysAsynchronously = false
@ -1271,7 +1276,15 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch content { switch content {
case .removedChat: case .removedChat:
self.panelWrapperNode.addSubnode(self.timerTextNode) self.panelWrapperNode.addSubnode(self.timerTextNode)
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .copy, .mediaSaved, .paymentSent, .starsSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal, .premiumPaywall, .peers, .messageTagged: case .starsSent:
self.panelWrapperNode.addSubnode(self.timerTextNode)
if self.textNode.tapAttributeAction != nil || displayUndo {
self.isUserInteractionEnabled = true
} else {
self.isUserInteractionEnabled = false
}
case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded, .universal, .premiumPaywall, .peers, .messageTagged:
if self.textNode.tapAttributeAction != nil || displayUndo { if self.textNode.tapAttributeAction != nil || displayUndo {
self.isUserInteractionEnabled = true self.isUserInteractionEnabled = true
} else { } else {
@ -1420,7 +1433,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let _ = self.action(.commit) let _ = self.action(.commit)
self.dismiss() self.dismiss()
} else { } else {
if Int(self.remainingSeconds) != previousRemainingSeconds || (self.timerTextNode.attributedText?.string ?? "").isEmpty { let remainingSecondsString = "\(Int(self.remainingSeconds))"
if Int(self.remainingSeconds) != previousRemainingSeconds || self.timerTextNode.attributedText?.string != remainingSecondsString {
if !self.timerTextNode.bounds.size.width.isZero, let snapshot = self.timerTextNode.view.snapshotContentTree() { if !self.timerTextNode.bounds.size.width.isZero, let snapshot = self.timerTextNode.view.snapshotContentTree() {
self.panelNode.view.insertSubview(snapshot, aboveSubview: self.timerTextNode.view) self.panelNode.view.insertSubview(snapshot, aboveSubview: self.timerTextNode.view)
snapshot.frame = self.timerTextNode.frame snapshot.frame = self.timerTextNode.frame
@ -1431,7 +1445,13 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
snapshot?.removeFromSuperview() snapshot?.removeFromSuperview()
}) })
} }
self.timerTextNode.attributedText = NSAttributedString(string: "\(Int(self.remainingSeconds))", font: Font.regular(16.0), textColor: .white) let timerColor: UIColor
if case .starsSent = self.content {
timerColor = self.undoTextColor
} else {
timerColor = .white
}
self.timerTextNode.attributedText = NSAttributedString(string: remainingSecondsString, font: Font.regular(16.0), textColor: timerColor)
if let validLayout = self.validLayout { if let validLayout = self.validLayout {
self.containerLayoutUpdated(layout: validLayout, transition: .immediate) self.containerLayoutUpdated(layout: validLayout, transition: .immediate)
} }
@ -1450,6 +1470,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.timer?.invalidate() self.timer?.invalidate()
self.timer = nil self.timer = nil
self.remainingSeconds = self.originalRemainingSeconds self.remainingSeconds = self.originalRemainingSeconds
self.didStartStatusNode = false
self.checkTimer() self.checkTimer()
} }
@ -1508,7 +1529,6 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} }
func containerLayoutUpdated(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { func containerLayoutUpdated(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
let firstLayout = self.validLayout == nil
self.validLayout = layout self.validLayout = layout
var preferredSize: CGSize? var preferredSize: CGSize?
@ -1630,10 +1650,14 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
transition.updateFrame(node: self.panelWrapperNode, frame: panelWrapperFrame) transition.updateFrame(node: self.panelWrapperNode, frame: panelWrapperFrame)
self.effectView.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width - leftMargin * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: contentHeight) self.effectView.frame = CGRect(x: 0.0, y: 0.0, width: layout.size.width - leftMargin * 2.0 - layout.safeInsets.left - layout.safeInsets.right, height: contentHeight)
let buttonTextFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - leftMargin * 2.0, y: floor((contentHeight - buttonTextSize.height) / 2.0)), size: buttonTextSize) var buttonTextFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - leftMargin * 2.0, y: floor((contentHeight - buttonTextSize.height) / 2.0)), size: buttonTextSize)
var undoButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - 8.0 - leftMargin * 2.0, y: 0.0), size: CGSize(width: layout.safeInsets.right + rightInset + buttonTextSize.width + 8.0 + leftMargin, height: contentHeight))
if case .starsSent = self.content {
let buttonOffset: CGFloat = -34.0
undoButtonFrame.origin.x += buttonOffset
buttonTextFrame.origin.x += buttonOffset
}
transition.updateFrame(node: self.undoButtonTextNode, frame: buttonTextFrame) transition.updateFrame(node: self.undoButtonTextNode, frame: buttonTextFrame)
let undoButtonFrame = CGRect(origin: CGPoint(x: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - buttonTextSize.width - 8.0 - leftMargin * 2.0, y: 0.0), size: CGSize(width: layout.safeInsets.right + rightInset + buttonTextSize.width + 8.0 + leftMargin, height: contentHeight))
self.undoButtonNode.frame = undoButtonFrame self.undoButtonNode.frame = undoButtonFrame
self.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.undoButtonNode.supernode == nil ? panelFrame.width : undoButtonFrame.minX, height: contentHeight)) self.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.undoButtonNode.supernode == nil ? panelFrame.width : undoButtonFrame.minX, height: contentHeight))
@ -1728,13 +1752,28 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
} }
let timerTextSize = self.timerTextNode.updateLayout(CGSize(width: 100.0, height: 100.0)) let timerTextSize = self.timerTextNode.updateLayout(CGSize(width: 100.0, height: 100.0))
if case .starsSent = self.content {
transition.updateFrame(node: self.timerTextNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset + floor((rightInset - timerTextSize.width) * 0.5) - 46.0)), y: floor((contentHeight - timerTextSize.height) / 2.0)), size: timerTextSize))
} else {
transition.updateFrame(node: self.timerTextNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - timerTextSize.width) / 2.0), y: floor((contentHeight - timerTextSize.height) / 2.0)), size: timerTextSize)) transition.updateFrame(node: self.timerTextNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - timerTextSize.width) / 2.0), y: floor((contentHeight - timerTextSize.height) / 2.0)), size: timerTextSize))
}
if let statusNode = self.statusNode { if let statusNode = self.statusNode {
let statusSize: CGFloat = 30.0 let statusSize: CGFloat = 30.0
transition.updateFrame(node: statusNode, frame: CGRect(origin: CGPoint(x: floor((leftInset - statusSize) / 2.0), y: floor((contentHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize))) var statusFrame = CGRect(origin: CGPoint(x: floor((leftInset - statusSize) / 2.0), y: floor((contentHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize))
if firstLayout { if case .starsSent = self.content {
statusNode.transitionToState(.secretTimeout(color: .white, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {}) statusFrame.origin.x = layout.size.width - layout.safeInsets.left - layout.safeInsets.right - rightInset - statusSize - 23.0
}
transition.updateFrame(node: statusNode, frame: statusFrame)
if !self.didStartStatusNode {
let statusColor: UIColor
if case .starsSent = self.content {
statusColor = self.undoTextColor
} else {
statusColor = .white
}
statusNode.transitionToState(.secretTimeout(color: statusColor, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
self.didStartStatusNode = true
} }
} }