mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +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'
|
||||
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()
|
||||
|
||||
@ -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())
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "11.0",
|
||||
"app": "11.0.1",
|
||||
"xcode": "15.2",
|
||||
"bazel": "7.1.1",
|
||||
"macos": "13.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user