Merge commit 'd40cf1023e3a508b2de2c1362dd463aa80bff961' into macos-11-release

This commit is contained in:
Mikhail Filimonov 2024-08-16 10:16:57 -03:00
commit f2399930af
13 changed files with 293 additions and 64 deletions

View File

@ -124,13 +124,14 @@ def load_codesigning_data_from_git(working_dir, repo_url, temp_key_path, branch,
encrypted_working_dir = working_dir + '/encrypted'
if os.path.exists(encrypted_working_dir):
original_working_dir = os.getcwd()
os.chdir(encrypted_working_dir)
if always_fetch:
original_working_dir = os.getcwd()
os.chdir(encrypted_working_dir)
check_run_system('GIT_SSH_COMMAND="{ssh_command}" git fetch'.format(ssh_command=ssh_command))
check_run_system('git checkout "{branch}"'.format(branch=branch))
check_run_system('git checkout "{branch}"'.format(branch=branch))
if always_fetch:
check_run_system('GIT_SSH_COMMAND="{ssh_command}" git pull'.format(ssh_command=ssh_command))
os.chdir(original_working_dir)
os.chdir(original_working_dir)
else:
os.makedirs(encrypted_working_dir, exist_ok=True)
original_working_dir = os.getcwd()

View File

@ -172,7 +172,7 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
|> ignoreValues
}
public func sendStarsReactionsInteractively(account: Account, messageId: MessageId, count: Int, isAnonymous: Bool) -> Signal<Never, NoError> {
public func sendStarsReactionsInteractively(account: Account, messageId: MessageId, count: Int, isAnonymous: Bool?) -> Signal<Never, NoError> {
return account.postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: SendStarsReactionsAction(randomId: Int64.random(in: Int64.min ... Int64.max)))
transaction.updateMessage(messageId, update: { currentMessage in
@ -182,15 +182,28 @@ public func sendStarsReactionsInteractively(account: Account, messageId: Message
}
var mappedCount = Int32(count)
var attributes = currentMessage.attributes
var resolvedIsAnonymous = false
for attribute in attributes {
if let attribute = attribute as? ReactionsMessageAttribute {
if let myReaction = attribute.topPeers.first(where: { $0.isMy }) {
resolvedIsAnonymous = myReaction.isAnonymous
}
}
}
loop: for j in 0 ..< attributes.count {
if let current = attributes[j] as? PendingStarsReactionsMessageAttribute {
mappedCount += current.count
resolvedIsAnonymous = current.isAnonymous
attributes.remove(at: j)
break loop
}
}
if let isAnonymous {
resolvedIsAnonymous = isAnonymous
}
attributes.append(PendingStarsReactionsMessageAttribute(accountPeerId: account.peerId, count: mappedCount, isAnonymous: isAnonymous))
attributes.append(PendingStarsReactionsMessageAttribute(accountPeerId: account.peerId, count: mappedCount, isAnonymous: resolvedIsAnonymous))
return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media))
})
@ -395,7 +408,6 @@ private func requestSendStarsReaction(postbox: Postbox, network: Network, stateM
}
|> mapToSignal { result -> Signal<Never, RequestUpdateMessageReactionError> in
stateManager.starsContext?.add(balance: Int64(-count), addTransaction: false)
//stateManager.starsContext?.load(force: true)
return postbox.transaction { transaction -> Void in
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: UpdateMessageReactionsAction())

View File

@ -334,7 +334,7 @@ public extension TelegramEngine {
).startStandalone()
}
public func sendStarsReaction(id: EngineMessage.Id, count: Int, isAnonymous: Bool) {
public func sendStarsReaction(id: EngineMessage.Id, count: Int, isAnonymous: Bool?) {
let _ = sendStarsReactionsInteractively(account: self.account, messageId: id, count: count, isAnonymous: isAnonymous).startStandalone()
}

View File

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

View File

@ -1550,7 +1550,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
}
}
if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, firstMessage.author?.id != channel.id {
if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info {
if info.flags.contains(.messagesShouldHaveProfiles) {
var allowAuthor = incoming
overrideEffectiveAuthor = true

View File

@ -75,6 +75,13 @@ private func messagesShouldBeMerged(accountPeerId: PeerId, _ lhs: Message, _ rhs
}
}
if let channel = lhs.peers[lhs.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info {
if info.flags.contains(.messagesShouldHaveProfiles) {
lhsEffectiveAuthor = lhs.author
rhsEffectiveAuthor = rhs.author
}
}
var sameChat = true
if lhs.id.peerId != rhs.id.peerId {
sameChat = false
@ -344,7 +351,7 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
if !hasActionMedia {
if !isBroadcastChannel {
hasAvatar = true
} else if let channel = message.peers[message.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, message.author?.id != channel.id {
} else if let channel = message.peers[message.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info {
if info.flags.contains(.messagesShouldHaveProfiles) {
hasAvatar = true
effectiveAuthor = message.author

View File

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

View File

@ -227,6 +227,14 @@ private final class BadgeComponent: Component {
required init(coder: NSCoder) {
preconditionFailure()
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if self.badgeView.frame.contains(point) {
return self
} else {
return nil
}
}
func update(component: BadgeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
if self.component == nil {
@ -471,14 +479,14 @@ private final class PeerComponent: Component {
let theme: PresentationTheme
let strings: PresentationStrings
let peer: EnginePeer?
let count: Int
let count: String
init(
context: AccountContext,
theme: PresentationTheme,
strings: PresentationStrings,
peer: EnginePeer?,
count: Int
count: String
) {
self.context = context
self.theme = theme
@ -547,7 +555,7 @@ private final class PeerComponent: Component {
transition: .immediate,
component: AnyComponent(PeerBadgeComponent(
theme: component.theme,
title: "\(component.count)"
title: component.count
)),
environment: {},
containerSize: CGSize(width: 200.0, height: 200.0)
@ -806,7 +814,7 @@ private final class SliderBackgroundComponent: Component {
topBackgroundTextView.layer.animateSpring(from: NSValue(cgPoint: CGPoint(x: animateTopTextAdditionalX, y: 0.0)), to: NSValue(cgPoint: CGPoint()), keyPath: "position", duration: 0.3, damping: 100.0, additive: true)
}
topForegroundTextView.isHidden = component.topCutoff == nil
topForegroundTextView.isHidden = component.topCutoff == nil || topLineFrame.maxX + topTextSize.width + 20.0 > availableSize.width
topBackgroundTextView.isHidden = topForegroundTextView.isHidden
self.topBackgroundLine.isHidden = topX < 10.0
self.topForegroundLine.isHidden = self.topBackgroundLine.isHidden
@ -915,6 +923,83 @@ private final class ChatSendStarsScreenComponent: Component {
}
}
private struct Amount: Equatable {
private let sliderSteps: [Int]
private let maxRealValue: Int
let maxSliderValue: Int
private let isLogarithmic: Bool
private(set) var realValue: Int
private(set) var sliderValue: Int
private static func makeSliderSteps(maxRealValue: Int, isLogarithmic: Bool) -> [Int] {
if isLogarithmic {
var sliderSteps: [Int] = [ 1, 10, 50, 100, 500, 1_000, 2_000, 5_000, 7_500, 10_000 ]
sliderSteps.removeAll(where: { $0 >= maxRealValue })
sliderSteps.append(maxRealValue)
return sliderSteps
} else {
return [1, maxRealValue]
}
}
private static func remapValueToSlider(realValue: Int, maxSliderValue: Int, steps: [Int]) -> Int {
guard realValue >= steps.first!, realValue <= steps.last! else { return 0 }
for i in 0 ..< steps.count - 1 {
if realValue >= steps[i] && realValue <= steps[i + 1] {
let range = steps[i + 1] - steps[i]
let relativeValue = realValue - steps[i]
let stepFraction = Float(relativeValue) / Float(range)
return Int(Float(i) * Float(maxSliderValue) / Float(steps.count - 1)) + Int(stepFraction * Float(maxSliderValue) / Float(steps.count - 1))
}
}
return maxSliderValue // Return max slider position if value equals the last step
}
private static func remapSliderToValue(sliderValue: Int, maxSliderValue: Int, steps: [Int]) -> Int {
guard sliderValue >= 0, sliderValue <= maxSliderValue else { return steps.first! }
let stepIndex = Int(Float(sliderValue) / Float(maxSliderValue) * Float(steps.count - 1))
let fraction = Float(sliderValue) / Float(maxSliderValue) * Float(steps.count - 1) - Float(stepIndex)
if stepIndex >= steps.count - 1 {
return steps.last!
} else {
let range = steps[stepIndex + 1] - steps[stepIndex]
return steps[stepIndex] + Int(fraction * Float(range))
}
}
init(realValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
self.maxRealValue = maxRealValue
self.maxSliderValue = maxSliderValue
self.isLogarithmic = isLogarithmic
self.realValue = realValue
self.sliderValue = Amount.remapValueToSlider(realValue: self.realValue, maxSliderValue: self.maxSliderValue, steps: self.sliderSteps)
}
init(sliderValue: Int, maxRealValue: Int, maxSliderValue: Int, isLogarithmic: Bool) {
self.sliderSteps = Amount.makeSliderSteps(maxRealValue: maxRealValue, isLogarithmic: isLogarithmic)
self.maxRealValue = maxRealValue
self.maxSliderValue = maxSliderValue
self.isLogarithmic = isLogarithmic
self.sliderValue = sliderValue
self.realValue = Amount.remapSliderToValue(sliderValue: self.sliderValue, maxSliderValue: self.maxSliderValue, steps: self.sliderSteps)
}
func withRealValue(_ realValue: Int) -> Amount {
return Amount(realValue: realValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
}
func withSliderValue(_ sliderValue: Int) -> Amount {
return Amount(sliderValue: sliderValue, maxRealValue: self.maxRealValue, maxSliderValue: self.maxSliderValue, isLogarithmic: self.isLogarithmic)
}
}
final class View: UIView, UIScrollViewDelegate {
private let dimView: UIView
private let backgroundLayer: SimpleLayer
@ -959,7 +1044,10 @@ private final class ChatSendStarsScreenComponent: Component {
private var topOffsetDistance: CGFloat?
private var balance: Int64?
private var amount: Int64 = 1
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 cachedStarImage: (UIImage, PresentationTheme)?
private var cachedCloseImage: UIImage?
@ -1058,6 +1146,12 @@ private final class ChatSendStarsScreenComponent: Component {
return result
}
if let badgeView = self.badge.view, badgeView.hitTest(self.convert(point, to: badgeView), with: event) != nil {
if let sliderView = self.slider.view as? SliderComponent.View, let hitTestTarget = sliderView.hitTestTarget {
return hitTestTarget
}
}
let result = super.hitTest(point, with: event)
return result
}
@ -1135,7 +1229,11 @@ private final class ChatSendStarsScreenComponent: Component {
if self.component == nil {
self.balance = component.balance
self.amount = 50
var isLogarithmic = true
if let data = component.context.currentAppConfiguration.with({ $0 }).data, let value = data["ios_stars_reaction_logarithmic_scale"] as? Double {
isLogarithmic = Int(value) != 0
}
self.amount = Amount(realValue: 50, maxRealValue: component.maxAmount, maxSliderValue: 999, isLogarithmic: isLogarithmic)
if let myTopPeer = component.myTopPeer {
self.isAnonymous = myTopPeer.isAnonymous
}
@ -1182,8 +1280,8 @@ private final class ChatSendStarsScreenComponent: Component {
let sliderSize = self.slider.update(
transition: transition,
component: AnyComponent(SliderComponent(
valueCount: component.maxAmount,
value: Int(self.amount),
valueCount: self.amount.maxSliderValue + 1,
value: self.amount.sliderValue,
markPositions: false,
trackBackgroundColor: .clear,
trackForegroundColor: .clear,
@ -1193,7 +1291,9 @@ private final class ChatSendStarsScreenComponent: Component {
guard let self, let component = self.component else {
return
}
self.amount = 1 + Int64(value)
self.amount = self.amount.withSliderValue(value)
self.didChangeAmount = true
self.state?.updated(transition: ComponentTransition(animation: .none).withUserData(IsAdjustingAmountHint()))
let sliderValue = Float(value) / Float(component.maxAmount)
@ -1250,7 +1350,7 @@ private final class ChatSendStarsScreenComponent: Component {
let sliderFrame = CGRect(origin: CGPoint(x: sliderInset, y: contentHeight + 127.0), size: sliderSize)
let sliderBackgroundFrame = CGRect(origin: CGPoint(x: sliderFrame.minX - 8.0, y: sliderFrame.minY + 7.0), size: CGSize(width: sliderFrame.width + 16.0, height: sliderFrame.height - 14.0))
let progressFraction: CGFloat = CGFloat(self.amount) / CGFloat(component.maxAmount - 1)
let progressFraction: CGFloat = CGFloat(self.amount.sliderValue) / CGFloat(self.amount.maxSliderValue)
let topOthersCount: Int? = component.topPeers.filter({ !$0.isMy }).max(by: { $0.count < $1.count })?.count
var topCount: Int?
@ -1310,7 +1410,7 @@ private final class ChatSendStarsScreenComponent: Component {
transition: transition,
component: AnyComponent(BadgeComponent(
theme: environment.theme,
title: "\(self.amount)",
title: "\(self.amount.realValue)",
inertiaDirection: effectiveInertiaDirection
)),
environment: {},
@ -1542,15 +1642,24 @@ private final class ChatSendStarsScreenComponent: Component {
if let index = mappedTopPeers.firstIndex(where: { $0.isMy }) {
mappedTopPeers.remove(at: index)
}
var myCount = Int(self.amount)
var myCount = 0
if let myTopPeer = component.myTopPeer {
myCount += myTopPeer.count
}
mappedTopPeers.append(ChatSendStarsScreen.TopPeer(
peer: self.isAnonymous ? nil : component.myPeer,
isMy: true,
count: myCount
))
var myCountAddition = 0
if self.didChangeAmount {
myCountAddition = Int(self.amount.realValue)
}
myCount += myCountAddition
if myCount != 0 {
mappedTopPeers.append(ChatSendStarsScreen.TopPeer(
randomIndex: -1,
peer: self.isAnonymous ? nil : component.myPeer,
isMy: true,
count: myCount
))
}
mappedTopPeers.sort(by: { $0.count > $1.count })
if mappedTopPeers.count > 3 {
mappedTopPeers = Array(mappedTopPeers.prefix(3))
@ -1578,6 +1687,11 @@ private final class ChatSendStarsScreenComponent: Component {
self.topPeerItems[topPeer.id] = itemView
}
let itemCountString = "\(topPeer.count)"
/*if topPeer.isMy && myCountAddition != 0 && topPeer.count > myCountAddition {
itemCountString = "\(topPeer.count - myCountAddition) +\(myCountAddition)"
}*/
let itemSize = itemView.update(
transition: .immediate,
component: AnyComponent(PlainButtonComponent(
@ -1586,7 +1700,7 @@ private final class ChatSendStarsScreenComponent: Component {
theme: environment.theme,
strings: environment.strings,
peer: topPeer.peer,
count: topPeer.count
count: itemCountString
)),
effectAlignment: .center,
action: { [weak self] in
@ -1747,7 +1861,7 @@ private final class ChatSendStarsScreenComponent: Component {
self.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: .white)!, environment.theme)
}
let buttonString = environment.strings.SendStarReactions_SendButtonTitle("\(self.amount)").string
let buttonString = environment.strings.SendStarReactions_SendButtonTitle("\(self.amount.realValue)").string
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: .white, paragraphAlignment: .center)
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.cachedStarImage?.0 {
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
@ -1778,7 +1892,7 @@ private final class ChatSendStarsScreenComponent: Component {
return
}
if balance < self.amount {
if balance < self.amount.realValue {
let _ = (component.context.engine.payments.starsTopUpOptions()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self] options in
@ -1789,7 +1903,7 @@ private final class ChatSendStarsScreenComponent: Component {
return
}
let purchaseScreen = component.context.sharedContext.makeStarsPurchaseScreen(context: component.context, starsContext: starsContext, options: options, purpose: .transfer(peerId: component.peer.id, requiredStars: self.amount), completion: { result in
let purchaseScreen = component.context.sharedContext.makeStarsPurchaseScreen(context: component.context, starsContext: starsContext, options: options, purpose: .transfer(peerId: component.peer.id, requiredStars: Int64(self.amount.realValue)), completion: { result in
let _ = result
//TODO:release
})
@ -1805,13 +1919,13 @@ private final class ChatSendStarsScreenComponent: Component {
}
let isBecomingTop: Bool
if let topCount {
isBecomingTop = self.amount > topCount
isBecomingTop = self.amount.realValue > topCount
} else {
isBecomingTop = true
}
component.completion(
self.amount,
Int64(self.amount.realValue),
self.isAnonymous,
isBecomingTop,
ChatSendStarsScreen.TransitionOut(
@ -1953,7 +2067,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
fileprivate final class TopPeer: Equatable {
enum Id: Hashable {
case anonymous
case anonymous(Int)
case my
case peer(EnginePeer.Id)
}
@ -1964,7 +2078,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
} else if let peer = self.peer {
return .peer(peer.id)
} else {
return .anonymous
return .anonymous(self.randomIndex)
}
}
@ -1972,17 +2086,22 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
return self.peer == nil
}
let randomIndex: Int
let peer: EnginePeer?
let isMy: Bool
let count: Int
init(peer: EnginePeer?, isMy: Bool, count: Int) {
init(randomIndex: Int, peer: EnginePeer?, isMy: Bool, count: Int) {
self.randomIndex = randomIndex
self.peer = peer
self.isMy = isMy
self.count = count
}
static func ==(lhs: TopPeer, rhs: TopPeer) -> Bool {
if lhs.randomIndex != rhs.randomIndex {
return false
}
if lhs.peer != rhs.peer {
return false
}
@ -2099,6 +2218,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
return nil
}
var nextRandomIndex = 0
return InitialData(
peer: peer,
myPeer: myPeer,
@ -2107,7 +2227,10 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
currentSentAmount: currentSentAmount,
topPeers: topPeers.compactMap { topPeer -> ChatSendStarsScreen.TopPeer? in
guard let topPeerId = topPeer.peerId else {
let randomIndex = nextRandomIndex
nextRandomIndex += 1
return ChatSendStarsScreen.TopPeer(
randomIndex: randomIndex,
peer: nil,
isMy: topPeer.isMy,
count: Int(topPeer.count)
@ -2119,7 +2242,10 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
guard let topPeerValue else {
return nil
}
let randomIndex = nextRandomIndex
nextRandomIndex += 1
return ChatSendStarsScreen.TopPeer(
randomIndex: randomIndex,
peer: topPeer.isAnonymous ? nil : topPeerValue,
isMy: topPeer.isMy,
count: Int(topPeer.count)
@ -2128,6 +2254,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
myTopPeer: myTopPeer.flatMap { topPeer -> ChatSendStarsScreen.TopPeer? in
guard let topPeerId = topPeer.peerId else {
return ChatSendStarsScreen.TopPeer(
randomIndex: -1,
peer: nil,
isMy: topPeer.isMy,
count: Int(topPeer.count)
@ -2140,6 +2267,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
return nil
}
return ChatSendStarsScreen.TopPeer(
randomIndex: -1,
peer: topPeer.isAnonymous ? nil : topPeerValue,
isMy: topPeer.isMy,
count: Int(topPeer.count)

View File

@ -70,6 +70,10 @@ public final class SliderComponent: Component {
private var component: SliderComponent?
private weak var state: EmptyComponentState?
public var hitTestTarget: UIView? {
return self.sliderView
}
override public init(frame: CGRect) {
super.init(frame: frame)
}

View File

@ -387,8 +387,46 @@ extension ChatControllerImpl {
}
}
self.context.engine.messages.sendStarsReaction(id: message.id, count: 1, isAnonymous: false)
self.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
guard let starsContext = self.context.starsContext else {
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: nil)
strongSelf.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
})
} else {
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction

View File

@ -1729,7 +1729,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
strongSelf.context.engine.messages.sendStarsReaction(id: message.id, count: 1, isAnonymous: false)
strongSelf.context.engine.messages.sendStarsReaction(id: message.id, count: 1, isAnonymous: nil)
strongSelf.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
})
} else {

View File

@ -29,6 +29,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private let elevatedLayout: Bool
private let placementPosition: UndoOverlayController.Position
private var statusNode: RadialStatusNode?
private var didStartStatusNode: Bool = false
private let timerTextNode: ImmediateTextNode
private let avatarNode: AvatarNode?
private let iconNode: ASImageNode?
@ -67,6 +68,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private var isTimeoutDisabled: Bool = false
private var originalRemainingSeconds: Double
private var remainingSeconds: Double
private let undoTextColor: UIColor
private var timer: SwiftSignalKit.Timer?
private var validLayout: ContainerViewLayout?
@ -413,8 +415,10 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.animatedTextItems = textItems
displayUndo = true
self.originalRemainingSeconds = 4.5
self.originalRemainingSeconds = 4.9
isUserInteractionEnabled = true
self.statusNode = RadialStatusNode(backgroundNodeColor: .clear)
case let .messagesUnpinned(title, text, undo, isHidden):
self.avatarNode = nil
self.iconNode = nil
@ -1246,6 +1250,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
}
self.remainingSeconds = self.originalRemainingSeconds
self.undoTextColor = undoTextColor
self.undoButtonTextNode = ImmediateTextNode()
self.undoButtonTextNode.displaysAsynchronously = false
@ -1271,7 +1276,15 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
switch content {
case .removedChat:
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 {
self.isUserInteractionEnabled = true
} else {
@ -1420,7 +1433,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let _ = self.action(.commit)
self.dismiss()
} 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() {
self.panelNode.view.insertSubview(snapshot, aboveSubview: self.timerTextNode.view)
snapshot.frame = self.timerTextNode.frame
@ -1431,7 +1445,13 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
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 {
self.containerLayoutUpdated(layout: validLayout, transition: .immediate)
}
@ -1450,6 +1470,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.timer?.invalidate()
self.timer = nil
self.remainingSeconds = self.originalRemainingSeconds
self.didStartStatusNode = false
self.checkTimer()
}
@ -1508,7 +1529,6 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
}
func containerLayoutUpdated(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
let firstLayout = self.validLayout == nil
self.validLayout = layout
var preferredSize: CGSize?
@ -1630,10 +1650,14 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
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)
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)
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.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))
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 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))
}
if let statusNode = self.statusNode {
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)))
if firstLayout {
statusNode.transitionToState(.secretTimeout(color: .white, icon: .none, beginTime: CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970, timeout: Double(self.remainingSeconds), sparks: false), completion: {})
var statusFrame = CGRect(origin: CGPoint(x: floor((leftInset - statusSize) / 2.0), y: floor((contentHeight - statusSize) / 2.0)), size: CGSize(width: statusSize, height: statusSize))
if case .starsSent = self.content {
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
}
}

View File

@ -1,5 +1,5 @@
{
"app": "11.0",
"app": "11.0.1",
"xcode": "15.2",
"bazel": "7.1.1",
"macos": "13.0"