mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 17:30:12 +00:00
Merge commit 'd40cf1023e3a508b2de2c1362dd463aa80bff961' into macos-11-release
This commit is contained in:
commit
f2399930af
@ -124,13 +124,14 @@ def load_codesigning_data_from_git(working_dir, repo_url, temp_key_path, branch,
|
|||||||
|
|
||||||
encrypted_working_dir = working_dir + '/encrypted'
|
encrypted_working_dir = working_dir + '/encrypted'
|
||||||
if os.path.exists(encrypted_working_dir):
|
if os.path.exists(encrypted_working_dir):
|
||||||
|
original_working_dir = os.getcwd()
|
||||||
|
os.chdir(encrypted_working_dir)
|
||||||
if always_fetch:
|
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_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))
|
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:
|
else:
|
||||||
os.makedirs(encrypted_working_dir, exist_ok=True)
|
os.makedirs(encrypted_working_dir, exist_ok=True)
|
||||||
original_working_dir = os.getcwd()
|
original_working_dir = os.getcwd()
|
||||||
|
|||||||
@ -172,7 +172,7 @@ public func updateMessageReactionsInteractively(account: Account, messageIds: [M
|
|||||||
|> ignoreValues
|
|> 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
|
return account.postbox.transaction { transaction -> Void in
|
||||||
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: SendStarsReactionsAction(randomId: Int64.random(in: Int64.min ... Int64.max)))
|
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: SendStarsReactionsAction(randomId: Int64.random(in: Int64.min ... Int64.max)))
|
||||||
transaction.updateMessage(messageId, update: { currentMessage in
|
transaction.updateMessage(messageId, update: { currentMessage in
|
||||||
@ -182,15 +182,28 @@ public func sendStarsReactionsInteractively(account: Account, messageId: Message
|
|||||||
}
|
}
|
||||||
var mappedCount = Int32(count)
|
var mappedCount = Int32(count)
|
||||||
var attributes = currentMessage.attributes
|
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 {
|
loop: for j in 0 ..< attributes.count {
|
||||||
if let current = attributes[j] as? PendingStarsReactionsMessageAttribute {
|
if let current = attributes[j] as? PendingStarsReactionsMessageAttribute {
|
||||||
mappedCount += current.count
|
mappedCount += current.count
|
||||||
|
resolvedIsAnonymous = current.isAnonymous
|
||||||
attributes.remove(at: j)
|
attributes.remove(at: j)
|
||||||
break loop
|
break loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.append(PendingStarsReactionsMessageAttribute(accountPeerId: account.peerId, count: mappedCount, isAnonymous: isAnonymous))
|
if let isAnonymous {
|
||||||
|
resolvedIsAnonymous = 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))
|
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
|
|> mapToSignal { result -> Signal<Never, RequestUpdateMessageReactionError> in
|
||||||
stateManager.starsContext?.add(balance: Int64(-count), addTransaction: false)
|
stateManager.starsContext?.add(balance: Int64(-count), addTransaction: false)
|
||||||
//stateManager.starsContext?.load(force: true)
|
|
||||||
|
|
||||||
return postbox.transaction { transaction -> Void in
|
return postbox.transaction { transaction -> Void in
|
||||||
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: UpdateMessageReactionsAction())
|
transaction.setPendingMessageAction(type: .sendStarsReaction, id: messageId, action: UpdateMessageReactionsAction())
|
||||||
|
|||||||
@ -334,7 +334,7 @@ public extension TelegramEngine {
|
|||||||
).startStandalone()
|
).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()
|
let _ = sendStarsReactionsInteractively(account: self.account, messageId: id, count: count, isAnonymous: isAnonymous).startStandalone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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 info.flags.contains(.messagesShouldHaveProfiles) {
|
||||||
isBroadcastChannel = true
|
hasAvatar = incoming
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if !isBroadcastChannel {
|
|
||||||
hasAvatar = true
|
hasAvatar = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
if info.flags.contains(.messagesShouldHaveProfiles) {
|
||||||
var allowAuthor = incoming
|
var allowAuthor = incoming
|
||||||
overrideEffectiveAuthor = true
|
overrideEffectiveAuthor = true
|
||||||
|
|||||||
@ -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
|
var sameChat = true
|
||||||
if lhs.id.peerId != rhs.id.peerId {
|
if lhs.id.peerId != rhs.id.peerId {
|
||||||
sameChat = false
|
sameChat = false
|
||||||
@ -344,7 +351,7 @@ public final class ChatMessageItemImpl: ChatMessageItem, CustomStringConvertible
|
|||||||
if !hasActionMedia {
|
if !hasActionMedia {
|
||||||
if !isBroadcastChannel {
|
if !isBroadcastChannel {
|
||||||
hasAvatar = true
|
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) {
|
if info.flags.contains(.messagesShouldHaveProfiles) {
|
||||||
hasAvatar = true
|
hasAvatar = true
|
||||||
effectiveAuthor = message.author
|
effectiveAuthor = message.author
|
||||||
|
|||||||
@ -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 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -228,6 +228,14 @@ private final class BadgeComponent: Component {
|
|||||||
preconditionFailure()
|
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 {
|
func update(component: BadgeComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||||
if self.component == nil {
|
if self.component == nil {
|
||||||
self.badgeIcon.image = UIImage(bundleImageName: "Premium/SendStarsStarSliderIcon")?.withRenderingMode(.alwaysTemplate)
|
self.badgeIcon.image = UIImage(bundleImageName: "Premium/SendStarsStarSliderIcon")?.withRenderingMode(.alwaysTemplate)
|
||||||
@ -471,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
|
||||||
@ -547,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)
|
||||||
@ -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)
|
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
|
topBackgroundTextView.isHidden = topForegroundTextView.isHidden
|
||||||
self.topBackgroundLine.isHidden = topX < 10.0
|
self.topBackgroundLine.isHidden = topX < 10.0
|
||||||
self.topForegroundLine.isHidden = self.topBackgroundLine.isHidden
|
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 {
|
final class View: UIView, UIScrollViewDelegate {
|
||||||
private let dimView: UIView
|
private let dimView: UIView
|
||||||
private let backgroundLayer: SimpleLayer
|
private let backgroundLayer: SimpleLayer
|
||||||
@ -959,7 +1044,10 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
private var topOffsetDistance: CGFloat?
|
private var topOffsetDistance: CGFloat?
|
||||||
|
|
||||||
private var balance: Int64?
|
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 isAnonymous: Bool = false
|
||||||
private var cachedStarImage: (UIImage, PresentationTheme)?
|
private var cachedStarImage: (UIImage, PresentationTheme)?
|
||||||
private var cachedCloseImage: UIImage?
|
private var cachedCloseImage: UIImage?
|
||||||
@ -1058,6 +1146,12 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
return result
|
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)
|
let result = super.hitTest(point, with: event)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -1135,7 +1229,11 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
|
|
||||||
if self.component == nil {
|
if self.component == nil {
|
||||||
self.balance = component.balance
|
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 {
|
if let myTopPeer = component.myTopPeer {
|
||||||
self.isAnonymous = myTopPeer.isAnonymous
|
self.isAnonymous = myTopPeer.isAnonymous
|
||||||
}
|
}
|
||||||
@ -1182,8 +1280,8 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
let sliderSize = self.slider.update(
|
let sliderSize = self.slider.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(SliderComponent(
|
component: AnyComponent(SliderComponent(
|
||||||
valueCount: component.maxAmount,
|
valueCount: self.amount.maxSliderValue + 1,
|
||||||
value: Int(self.amount),
|
value: self.amount.sliderValue,
|
||||||
markPositions: false,
|
markPositions: false,
|
||||||
trackBackgroundColor: .clear,
|
trackBackgroundColor: .clear,
|
||||||
trackForegroundColor: .clear,
|
trackForegroundColor: .clear,
|
||||||
@ -1193,7 +1291,9 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.amount = 1 + Int64(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()))
|
||||||
|
|
||||||
let sliderValue = Float(value) / Float(component.maxAmount)
|
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 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 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
|
let topOthersCount: Int? = component.topPeers.filter({ !$0.isMy }).max(by: { $0.count < $1.count })?.count
|
||||||
var topCount: Int?
|
var topCount: Int?
|
||||||
@ -1310,7 +1410,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(BadgeComponent(
|
component: AnyComponent(BadgeComponent(
|
||||||
theme: environment.theme,
|
theme: environment.theme,
|
||||||
title: "\(self.amount)",
|
title: "\(self.amount.realValue)",
|
||||||
inertiaDirection: effectiveInertiaDirection
|
inertiaDirection: effectiveInertiaDirection
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -1542,15 +1642,24 @@ 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)
|
|
||||||
|
var myCount = 0
|
||||||
if let myTopPeer = component.myTopPeer {
|
if let myTopPeer = component.myTopPeer {
|
||||||
myCount += myTopPeer.count
|
myCount += myTopPeer.count
|
||||||
}
|
}
|
||||||
mappedTopPeers.append(ChatSendStarsScreen.TopPeer(
|
var myCountAddition = 0
|
||||||
peer: self.isAnonymous ? nil : component.myPeer,
|
if self.didChangeAmount {
|
||||||
isMy: true,
|
myCountAddition = Int(self.amount.realValue)
|
||||||
count: myCount
|
}
|
||||||
))
|
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 })
|
mappedTopPeers.sort(by: { $0.count > $1.count })
|
||||||
if mappedTopPeers.count > 3 {
|
if mappedTopPeers.count > 3 {
|
||||||
mappedTopPeers = Array(mappedTopPeers.prefix(3))
|
mappedTopPeers = Array(mappedTopPeers.prefix(3))
|
||||||
@ -1578,6 +1687,11 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
self.topPeerItems[topPeer.id] = itemView
|
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(
|
let itemSize = itemView.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
component: AnyComponent(PlainButtonComponent(
|
component: AnyComponent(PlainButtonComponent(
|
||||||
@ -1586,7 +1700,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
|
||||||
@ -1747,7 +1861,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
self.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: .white)!, environment.theme)
|
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)
|
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 {
|
if let range = buttonAttributedString.string.range(of: "#"), let starImage = self.cachedStarImage?.0 {
|
||||||
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
||||||
@ -1778,7 +1892,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if balance < self.amount {
|
if balance < self.amount.realValue {
|
||||||
let _ = (component.context.engine.payments.starsTopUpOptions()
|
let _ = (component.context.engine.payments.starsTopUpOptions()
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] options in
|
|> deliverOnMainQueue).startStandalone(next: { [weak self] options in
|
||||||
@ -1789,7 +1903,7 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
return
|
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
|
let _ = result
|
||||||
//TODO:release
|
//TODO:release
|
||||||
})
|
})
|
||||||
@ -1805,13 +1919,13 @@ private final class ChatSendStarsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
let isBecomingTop: Bool
|
let isBecomingTop: Bool
|
||||||
if let topCount {
|
if let topCount {
|
||||||
isBecomingTop = self.amount > topCount
|
isBecomingTop = self.amount.realValue > topCount
|
||||||
} else {
|
} else {
|
||||||
isBecomingTop = true
|
isBecomingTop = true
|
||||||
}
|
}
|
||||||
|
|
||||||
component.completion(
|
component.completion(
|
||||||
self.amount,
|
Int64(self.amount.realValue),
|
||||||
self.isAnonymous,
|
self.isAnonymous,
|
||||||
isBecomingTop,
|
isBecomingTop,
|
||||||
ChatSendStarsScreen.TransitionOut(
|
ChatSendStarsScreen.TransitionOut(
|
||||||
@ -1953,7 +2067,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
|
|
||||||
fileprivate final class TopPeer: Equatable {
|
fileprivate final class TopPeer: Equatable {
|
||||||
enum Id: Hashable {
|
enum Id: Hashable {
|
||||||
case anonymous
|
case anonymous(Int)
|
||||||
case my
|
case my
|
||||||
case peer(EnginePeer.Id)
|
case peer(EnginePeer.Id)
|
||||||
}
|
}
|
||||||
@ -1964,7 +2078,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
} else if let peer = self.peer {
|
} else if let peer = self.peer {
|
||||||
return .peer(peer.id)
|
return .peer(peer.id)
|
||||||
} else {
|
} else {
|
||||||
return .anonymous
|
return .anonymous(self.randomIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1972,17 +2086,22 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
return self.peer == nil
|
return self.peer == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let randomIndex: Int
|
||||||
let peer: EnginePeer?
|
let peer: EnginePeer?
|
||||||
let isMy: Bool
|
let isMy: Bool
|
||||||
let count: Int
|
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.peer = peer
|
||||||
self.isMy = isMy
|
self.isMy = isMy
|
||||||
self.count = count
|
self.count = count
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: TopPeer, rhs: TopPeer) -> Bool {
|
static func ==(lhs: TopPeer, rhs: TopPeer) -> Bool {
|
||||||
|
if lhs.randomIndex != rhs.randomIndex {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.peer != rhs.peer {
|
if lhs.peer != rhs.peer {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -2099,6 +2218,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var nextRandomIndex = 0
|
||||||
return InitialData(
|
return InitialData(
|
||||||
peer: peer,
|
peer: peer,
|
||||||
myPeer: myPeer,
|
myPeer: myPeer,
|
||||||
@ -2107,7 +2227,10 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
currentSentAmount: currentSentAmount,
|
currentSentAmount: currentSentAmount,
|
||||||
topPeers: topPeers.compactMap { topPeer -> ChatSendStarsScreen.TopPeer? in
|
topPeers: topPeers.compactMap { topPeer -> ChatSendStarsScreen.TopPeer? in
|
||||||
guard let topPeerId = topPeer.peerId else {
|
guard let topPeerId = topPeer.peerId else {
|
||||||
|
let randomIndex = nextRandomIndex
|
||||||
|
nextRandomIndex += 1
|
||||||
return ChatSendStarsScreen.TopPeer(
|
return ChatSendStarsScreen.TopPeer(
|
||||||
|
randomIndex: randomIndex,
|
||||||
peer: nil,
|
peer: nil,
|
||||||
isMy: topPeer.isMy,
|
isMy: topPeer.isMy,
|
||||||
count: Int(topPeer.count)
|
count: Int(topPeer.count)
|
||||||
@ -2119,7 +2242,10 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
guard let topPeerValue else {
|
guard let topPeerValue else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
let randomIndex = nextRandomIndex
|
||||||
|
nextRandomIndex += 1
|
||||||
return ChatSendStarsScreen.TopPeer(
|
return ChatSendStarsScreen.TopPeer(
|
||||||
|
randomIndex: randomIndex,
|
||||||
peer: topPeer.isAnonymous ? nil : topPeerValue,
|
peer: topPeer.isAnonymous ? nil : topPeerValue,
|
||||||
isMy: topPeer.isMy,
|
isMy: topPeer.isMy,
|
||||||
count: Int(topPeer.count)
|
count: Int(topPeer.count)
|
||||||
@ -2128,6 +2254,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
myTopPeer: myTopPeer.flatMap { topPeer -> ChatSendStarsScreen.TopPeer? in
|
myTopPeer: myTopPeer.flatMap { topPeer -> ChatSendStarsScreen.TopPeer? in
|
||||||
guard let topPeerId = topPeer.peerId else {
|
guard let topPeerId = topPeer.peerId else {
|
||||||
return ChatSendStarsScreen.TopPeer(
|
return ChatSendStarsScreen.TopPeer(
|
||||||
|
randomIndex: -1,
|
||||||
peer: nil,
|
peer: nil,
|
||||||
isMy: topPeer.isMy,
|
isMy: topPeer.isMy,
|
||||||
count: Int(topPeer.count)
|
count: Int(topPeer.count)
|
||||||
@ -2140,6 +2267,7 @@ public class ChatSendStarsScreen: ViewControllerComponentContainer {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ChatSendStarsScreen.TopPeer(
|
return ChatSendStarsScreen.TopPeer(
|
||||||
|
randomIndex: -1,
|
||||||
peer: topPeer.isAnonymous ? nil : topPeerValue,
|
peer: topPeer.isAnonymous ? nil : topPeerValue,
|
||||||
isMy: topPeer.isMy,
|
isMy: topPeer.isMy,
|
||||||
count: Int(topPeer.count)
|
count: Int(topPeer.count)
|
||||||
|
|||||||
@ -70,6 +70,10 @@ public final class SliderComponent: Component {
|
|||||||
private var component: SliderComponent?
|
private var component: SliderComponent?
|
||||||
private weak var state: EmptyComponentState?
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
public var hitTestTarget: UIView? {
|
||||||
|
return self.sliderView
|
||||||
|
}
|
||||||
|
|
||||||
override public init(frame: CGRect) {
|
override public init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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: nil)
|
||||||
|
strongSelf.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction
|
let chosenReaction: MessageReaction.Reaction = chosenUpdatedReaction.reaction
|
||||||
|
|
||||||
|
|||||||
@ -1729,7 +1729,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
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)
|
strongSelf.displayOrUpdateSendStarsUndo(messageId: message.id, count: 1)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -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))
|
||||||
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 {
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"app": "11.0",
|
"app": "11.0.1",
|
||||||
"xcode": "15.2",
|
"xcode": "15.2",
|
||||||
"bazel": "7.1.1",
|
"bazel": "7.1.1",
|
||||||
"macos": "13.0"
|
"macos": "13.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user