Various improvements

This commit is contained in:
Ilya Laktyushin 2025-03-11 18:48:35 +04:00
parent 80cd8f7b32
commit bafbe20063
38 changed files with 434 additions and 156 deletions

View File

@ -13996,3 +13996,13 @@ Sorry for the inconvenience.";
"Stars.AccountRevenue.Proceeds.Info" = "Stars from your total balance can be withdrawn as rewards 21 days after they are earned."; "Stars.AccountRevenue.Proceeds.Info" = "Stars from your total balance can be withdrawn as rewards 21 days after they are earned.";
"Stars.AccountRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment. You cannot withdraw less than 1000 stars. [Learn More >]()"; "Stars.AccountRevenue.Withdraw.Info" = "You can collect rewards for Stars using Fragment. You cannot withdraw less than 1000 stars. [Learn More >]()";
"Notification.PaidMessageRefund.Stars_1" = "%@ Star";
"Notification.PaidMessageRefund.Stars_any" = "%@ Stars";
"Notification.PaidMessageRefund" = "%1$@ refunded you %2$@";
"Notification.PaidMessageRefundYou" = "You refunded %1$@ to %2$@";
"Notification.PaidMessagePriceChanged.Stars_1" = "%@ Star";
"Notification.PaidMessagePriceChanged.Stars_any" = "%@ Stars";
"Notification.PaidMessagePriceChanged" = "%1$@ changed price to %2$@ per message";
"Notification.PaidMessagePriceChangedYou" = "You changed price to %1$@ per message";

View File

@ -1053,7 +1053,7 @@ public protocol SharedAccountContext: AnyObject {
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, dismissed: (() -> Void)?) -> ViewController func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, proceed: (() -> Void)?) -> ViewController
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, forceDark: Bool, action: @escaping () -> Void, dismissed: (() -> Void)?) -> ViewController func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, forceDark: Bool, action: @escaping () -> Void, dismissed: (() -> Void)?) -> ViewController
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, forceDark: Bool, cancel: @escaping () -> Void, action: @escaping () -> Bool) -> ViewController func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, forceDark: Bool, cancel: @escaping () -> Void, action: @escaping () -> Bool) -> ViewController
@ -1232,6 +1232,7 @@ public protocol AccountContext: AnyObject {
var availableMessageEffects: Signal<AvailableMessageEffects?, NoError> { get } var availableMessageEffects: Signal<AvailableMessageEffects?, NoError> { get }
var isPremium: Bool { get } var isPremium: Bool { get }
var isFrozen: Bool { get }
var userLimits: EngineConfiguration.UserLimits { get } var userLimits: EngineConfiguration.UserLimits { get }
var peerNameColors: PeerNameColors { get } var peerNameColors: PeerNameColors { get }

View File

@ -43,6 +43,7 @@ public enum PremiumIntroSource {
case animatedEmoji case animatedEmoji
case messageEffects case messageEffects
case paidMessages case paidMessages
case auth(String)
} }
public enum PremiumGiftSource: Equatable { public enum PremiumGiftSource: Equatable {

View File

@ -251,15 +251,17 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
iconName: "Premium/Authorization/Support", iconName: "Premium/Authorization/Support",
iconColor: linkColor, iconColor: linkColor,
action: { [weak self] in action: { [weak self] in
guard let self, let controller = self.environment?.controller() else { guard let self, let controller = self.environment?.controller(), let product = self.products.first(where: { $0.id == component.storeProduct }) else {
return return
} }
let introController = component.sharedContext.makePremiumIntroController( let introController = component.sharedContext.makePremiumIntroController(
sharedContext: component.sharedContext, sharedContext: component.sharedContext,
engine: component.engine, engine: component.engine,
inAppPurchaseManager: component.inAppPurchaseManager, inAppPurchaseManager: component.inAppPurchaseManager,
source: .about, source: .auth(product.price),
dismissed: nil proceed: { [weak self] in
self?.proceed()
}
) )
controller.push(introController) controller.push(introController)
} }
@ -274,11 +276,13 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height) containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: availableSize.height)
) )
let buttonHeight: CGFloat = 50.0
let bottomPanelPadding: CGFloat = 12.0
let titleSpacing: CGFloat = -24.0 let titleSpacing: CGFloat = -24.0
let listSpacing: CGFloat = 12.0 let listSpacing: CGFloat = 12.0
let totalHeight = animationSize.height + titleSpacing + titleSize.height + listSpacing + listSize.height let totalHeight = animationSize.height + titleSpacing + titleSize.height + listSpacing + listSize.height
var originY = floor((availableSize.height - totalHeight) / 2.0) var originY = floor((availableSize.height - buttonHeight - bottomPanelPadding * 2.0 - totalHeight) / 2.0)
if let animationView = self.animation.view { if let animationView = self.animation.view {
if animationView.superview == nil { if animationView.superview == nil {
@ -302,8 +306,6 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
listView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - listSize.width) / 2.0), y: originY), size: listSize) listView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - listSize.width) / 2.0), y: originY), size: listSize)
} }
let buttonHeight: CGFloat = 50.0
let bottomPanelPadding: CGFloat = 12.0
let bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding let bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding
let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset
@ -329,7 +331,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component {
component: AnyComponent( component: AnyComponent(
VStack([ VStack([
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))), AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))),
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Get Telegram Premium for 1 week", font: Font.regular(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center))))) AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Get Telegram Premium for 1 week", font: Font.medium(11.0), textColor: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7), paragraphAlignment: .center)))))
], spacing: 1.0) ], spacing: 1.0)
) )
), ),
@ -410,6 +412,10 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
override public func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@objc private func cancelPressed() { @objc private func cancelPressed() {
self.dismiss() self.dismiss()
} }

View File

@ -2794,6 +2794,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
private weak var storyCameraTooltip: TooltipScreen? private weak var storyCameraTooltip: TooltipScreen?
fileprivate func openStoryCamera(fromList: Bool) { fileprivate func openStoryCamera(fromList: Bool) {
guard !self.context.isFrozen else {
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
self.push(controller)
return
}
var reachedCountLimit = false var reachedCountLimit = false
var premiumNeeded = false var premiumNeeded = false
var hasActiveCall = false var hasActiveCall = false
@ -4641,6 +4647,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
} }
@objc fileprivate func composePressed() { @objc fileprivate func composePressed() {
guard !self.context.isFrozen else {
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
self.push(controller)
return
}
guard let navigationController = self.navigationController as? NavigationController else { guard let navigationController = self.navigationController as? NavigationController else {
return return
} }

View File

@ -9,6 +9,7 @@ public final class SolidRoundedButtonComponent: Component {
public typealias Theme = SolidRoundedButtonTheme public typealias Theme = SolidRoundedButtonTheme
public let title: String? public let title: String?
public let subtitle: String?
public let label: String? public let label: String?
public let badge: String? public let badge: String?
public let icon: UIImage? public let icon: UIImage?
@ -28,6 +29,7 @@ public final class SolidRoundedButtonComponent: Component {
public init( public init(
title: String? = nil, title: String? = nil,
subtitle: String? = nil,
label: String? = nil, label: String? = nil,
badge: String? = nil, badge: String? = nil,
icon: UIImage? = nil, icon: UIImage? = nil,
@ -46,6 +48,7 @@ public final class SolidRoundedButtonComponent: Component {
action: @escaping () -> Void action: @escaping () -> Void
) { ) {
self.title = title self.title = title
self.subtitle = subtitle
self.label = label self.label = label
self.badge = badge self.badge = badge
self.icon = icon self.icon = icon
@ -68,6 +71,9 @@ public final class SolidRoundedButtonComponent: Component {
if lhs.title != rhs.title { if lhs.title != rhs.title {
return false return false
} }
if lhs.subtitle != rhs.subtitle {
return false
}
if lhs.label != rhs.label { if lhs.label != rhs.label {
return false return false
} }
@ -147,6 +153,7 @@ public final class SolidRoundedButtonComponent: Component {
if let button = self.button { if let button = self.button {
button.title = component.title button.title = component.title
button.subtitle = component.subtitle
button.label = component.label button.label = component.label
button.badge = component.badge button.badge = component.badge
button.iconPosition = component.iconPosition button.iconPosition = component.iconPosition

View File

@ -242,6 +242,7 @@ open class ViewControllerComponentContainer: ViewController {
public private(set) var validLayout: ContainerViewLayout? public private(set) var validLayout: ContainerViewLayout?
public var wasDismissed: (() -> Void)? public var wasDismissed: (() -> Void)?
public var customProceed: (() -> Void)?
public init<C: Component>( public init<C: Component>(
context: AccountContext, context: AccountContext,

View File

@ -67,9 +67,7 @@
- (SSignal *)coverImageSignalForItem:(NSObject<TGMediaEditableItem> *)item; - (SSignal *)coverImageSignalForItem:(NSObject<TGMediaEditableItem> *)item;
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item; - (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
- (UIImage *)coverImageForItem:(NSObject<TGMediaEditableItem> *)item; - (UIImage *)coverImageForItem:(NSObject<TGMediaEditableItem> *)item;
- (NSNumber *)coverPositionForItem:(NSObject<TGMediaEditableItem> *)item; - (NSNumber *)coverPositionForItem:(NSObject<TGMediaEditableItem> *)item;
- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id<TGMediaEditableItem>)item;
- (void)setTemporaryRep:(id)rep forItem:(id<TGMediaEditableItem>)item; - (void)setTemporaryRep:(id)rep forItem:(id<TGMediaEditableItem>)item;

View File

@ -309,6 +309,12 @@ public enum PremiumSource: Equatable {
} else { } else {
return false return false
} }
case let .auth(lhsPrice):
if case let .auth(rhsPrice) = rhs, lhsPrice == rhsPrice {
return true
} else {
return false
}
} }
} }
@ -357,6 +363,7 @@ public enum PremiumSource: Equatable {
case folderTags case folderTags
case messageEffects case messageEffects
case paidMessages case paidMessages
case auth(String)
var identifier: String? { var identifier: String? {
switch self { switch self {
@ -452,6 +459,8 @@ public enum PremiumSource: Equatable {
return "effects" return "effects"
case .paidMessages: case .paidMessages:
return "paid_messages" return "paid_messages"
case .auth:
return "auth"
} }
} }
} }
@ -1214,6 +1223,7 @@ final class PerkComponent: CombinedComponent {
let subtitleColor: UIColor let subtitleColor: UIColor
let arrowColor: UIColor let arrowColor: UIColor
let accentColor: UIColor let accentColor: UIColor
let displayArrow: Bool
let badge: String? let badge: String?
init( init(
@ -1225,6 +1235,7 @@ final class PerkComponent: CombinedComponent {
subtitleColor: UIColor, subtitleColor: UIColor,
arrowColor: UIColor, arrowColor: UIColor,
accentColor: UIColor, accentColor: UIColor,
displayArrow: Bool = true,
badge: String? = nil badge: String? = nil
) { ) {
self.iconName = iconName self.iconName = iconName
@ -1235,6 +1246,7 @@ final class PerkComponent: CombinedComponent {
self.subtitleColor = subtitleColor self.subtitleColor = subtitleColor
self.arrowColor = arrowColor self.arrowColor = arrowColor
self.accentColor = accentColor self.accentColor = accentColor
self.displayArrow = displayArrow
self.badge = badge self.badge = badge
} }
@ -1263,6 +1275,9 @@ final class PerkComponent: CombinedComponent {
if lhs.accentColor != rhs.accentColor { if lhs.accentColor != rhs.accentColor {
return false return false
} }
if lhs.displayArrow != rhs.displayArrow {
return false
}
if lhs.badge != rhs.badge { if lhs.badge != rhs.badge {
return false return false
} }
@ -1306,15 +1321,6 @@ final class PerkComponent: CombinedComponent {
transition: context.transition transition: context.transition
) )
let arrow = arrow.update(
component: BundleIconComponent(
name: "Item List/DisclosureArrow",
tintColor: component.arrowColor
),
availableSize: context.availableSize,
transition: context.transition
)
let title = title.update( let title = title.update(
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain( text: .plain(
@ -1391,9 +1397,20 @@ final class PerkComponent: CombinedComponent {
) )
let size = CGSize(width: context.availableSize.width, height: textTopInset + title.size.height + spacing + subtitle.size.height + textBottomInset) let size = CGSize(width: context.availableSize.width, height: textTopInset + title.size.height + spacing + subtitle.size.height + textBottomInset)
if component.displayArrow {
let arrow = arrow.update(
component: BundleIconComponent(
name: "Item List/DisclosureArrow",
tintColor: component.arrowColor
),
availableSize: context.availableSize,
transition: context.transition
)
context.add(arrow context.add(arrow
.position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0)) .position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0))
) )
}
return size return size
} }
@ -2086,6 +2103,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
foregroundColor: .white, foregroundColor: .white,
iconName: perk.iconName iconName: perk.iconName
))), false), ))), false),
accessory: accountContext != nil ? .arrow : nil,
action: { [weak state] _ in action: { [weak state] _ in
guard let accountContext else { guard let accountContext else {
return return
@ -2162,7 +2180,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
updateIsFocused(true) updateIsFocused(true)
addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier]) addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier])
} },
highlighting: accountContext != nil ? .default : .disabled
)))) ))))
i += 1 i += 1
} }
@ -3660,7 +3679,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
if !buttonIsHidden { if !buttonIsHidden {
let buttonTitle: String let buttonTitle: String
if isUnusedGift { var buttonSubtitle: String?
if case let .auth(price) = context.component.source {
buttonTitle = "Sign up for \(price)"
buttonSubtitle = "Get Telegram Premium for 1 week"
} else if isUnusedGift {
buttonTitle = environment.strings.Premium_Gift_ApplyLink buttonTitle = environment.strings.Premium_Gift_ApplyLink
} else if state.isPremium == true && state.canUpgrade { } else if state.isPremium == true && state.canUpgrade {
buttonTitle = state.isAnnual ? environment.strings.Premium_UpgradeForAnnual(state.price ?? "").string : environment.strings.Premium_UpgradeFor(state.price ?? "").string buttonTitle = state.isAnnual ? environment.strings.Premium_UpgradeForAnnual(state.price ?? "").string : environment.strings.Premium_UpgradeFor(state.price ?? "").string
@ -3668,10 +3691,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
buttonTitle = state.isAnnual ? environment.strings.Premium_SubscribeForAnnual(state.price ?? "").string : environment.strings.Premium_SubscribeFor(state.price ?? "").string buttonTitle = state.isAnnual ? environment.strings.Premium_SubscribeForAnnual(state.price ?? "").string : environment.strings.Premium_SubscribeFor(state.price ?? "").string
} }
let controller = environment.controller
let sideInset: CGFloat = 16.0 let sideInset: CGFloat = 16.0
let button = button.update( let button = button.update(
component: SolidRoundedButtonComponent( component: SolidRoundedButtonComponent(
title: buttonTitle, title: buttonTitle,
subtitle: buttonSubtitle,
theme: SolidRoundedButtonComponent.Theme( theme: SolidRoundedButtonComponent.Theme(
backgroundColor: UIColor(rgb: 0x8878ff), backgroundColor: UIColor(rgb: 0x8878ff),
backgroundColors: [ backgroundColors: [
@ -3687,8 +3712,13 @@ private final class PremiumIntroScreenComponent: CombinedComponent {
gloss: true, gloss: true,
isLoading: state.inProgress, isLoading: state.inProgress,
action: { action: {
if let controller = controller() as? PremiumIntroScreen, let customProceed = controller.customProceed {
controller.dismiss()
customProceed()
} else {
state.buy() state.buy()
} }
}
), ),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0),
transition: context.transition) transition: context.transition)

View File

@ -315,7 +315,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati
entries.append(.footerItem(footer)) entries.append(.footerItem(footer))
} }
if !peers.isEmpty { if !peers.isEmpty || state.enableForPremium || state.enableForBots {
entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions)) entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions))
} }

View File

@ -1412,7 +1412,7 @@ public final class SolidRoundedButtonView: UIView {
} }
self.titleNode.attributedText = titleText self.titleNode.attributedText = titleText
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: theme.foregroundColor) self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.medium(11.0), textColor: theme.foregroundColor.withAlphaComponent(0.7))
self.iconNode.image = generateTintedImage(image: self.iconNode.image, color: theme.foregroundColor) self.iconNode.image = generateTintedImage(image: self.iconNode.image, color: theme.foregroundColor)
@ -1472,7 +1472,7 @@ public final class SolidRoundedButtonView: UIView {
} }
let titleSize = self.titleNode.updateLayout(buttonSize) let titleSize = self.titleNode.updateLayout(buttonSize)
let spacingOffset: CGFloat = 9.0 let spacingOffset: CGFloat = 7.0
let verticalInset: CGFloat = self.subtitle == nil ? floor((buttonFrame.height - titleSize.height) / 2.0) : floor((buttonFrame.height - titleSize.height) / 2.0) - spacingOffset let verticalInset: CGFloat = self.subtitle == nil ? floor((buttonFrame.height - titleSize.height) / 2.0) : floor((buttonFrame.height - titleSize.height) / 2.0) - spacingOffset
let iconSpacing: CGFloat = self.iconSpacing let iconSpacing: CGFloat = self.iconSpacing
let badgeSpacing: CGFloat = 6.0 let badgeSpacing: CGFloat = 6.0
@ -1533,11 +1533,11 @@ public final class SolidRoundedButtonView: UIView {
} }
if self.subtitle != self.subtitleNode.attributedText?.string { if self.subtitle != self.subtitleNode.attributedText?.string {
self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.regular(14.0), textColor: self.theme.foregroundColor) self.subtitleNode.attributedText = NSAttributedString(string: self.subtitle ?? "", font: Font.medium(11.0), textColor: self.theme.foregroundColor.withAlphaComponent(0.7))
} }
let subtitleSize = self.subtitleNode.updateLayout(buttonSize) let subtitleSize = self.subtitleNode.updateLayout(buttonSize)
let subtitleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - subtitleSize.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - titleSize.height) / 2.0) + spacingOffset + 2.0), size: subtitleSize) let subtitleFrame = CGRect(origin: CGPoint(x: buttonFrame.minX + floor((buttonFrame.width - subtitleSize.width) / 2.0), y: buttonFrame.minY + floor((buttonFrame.height - titleSize.height) / 2.0) + spacingOffset + 7.0), size: subtitleSize)
transition.updateFrame(view: self.subtitleNode, frame: subtitleFrame) transition.updateFrame(view: self.subtitleNode, frame: subtitleFrame)
if previousSubtitle == nil && self.subtitle != nil { if previousSubtitle == nil && self.subtitle != nil {

View File

@ -577,6 +577,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) } dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) } dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) } dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
dict[-1126755303] = { return Api.MessageAction.parse_messageActionPaidMessagesPrice($0) }
dict[-1407246387] = { return Api.MessageAction.parse_messageActionPaidMessagesRefunded($0) }
dict[1102307842] = { return Api.MessageAction.parse_messageActionPaymentRefunded($0) } dict[1102307842] = { return Api.MessageAction.parse_messageActionPaymentRefunded($0) }
dict[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) } dict[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) } dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }

View File

@ -363,6 +363,8 @@ public extension Api {
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32) case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
case messageActionHistoryClear case messageActionHistoryClear
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64]) case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
case messageActionPaidMessagesPrice(stars: Int64)
case messageActionPaidMessagesRefunded(count: Int32, stars: Int64)
case messageActionPaymentRefunded(flags: Int32, peer: Api.Peer, currency: String, totalAmount: Int64, payload: Buffer?, charge: Api.PaymentCharge) case messageActionPaymentRefunded(flags: Int32, peer: Api.Peer, currency: String, totalAmount: Int64, payload: Buffer?, charge: Api.PaymentCharge)
case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?, subscriptionUntilDate: Int32?) case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?, subscriptionUntilDate: Int32?)
case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge, subscriptionUntilDate: Int32?) case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge, subscriptionUntilDate: Int32?)
@ -595,6 +597,19 @@ public extension Api {
serializeInt64(item, buffer: buffer, boxed: false) serializeInt64(item, buffer: buffer, boxed: false)
} }
break break
case .messageActionPaidMessagesPrice(let stars):
if boxed {
buffer.appendInt32(-1126755303)
}
serializeInt64(stars, buffer: buffer, boxed: false)
break
case .messageActionPaidMessagesRefunded(let count, let stars):
if boxed {
buffer.appendInt32(-1407246387)
}
serializeInt32(count, buffer: buffer, boxed: false)
serializeInt64(stars, buffer: buffer, boxed: false)
break
case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge): case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge):
if boxed { if boxed {
buffer.appendInt32(1102307842) buffer.appendInt32(1102307842)
@ -847,6 +862,10 @@ public extension Api {
return ("messageActionHistoryClear", []) return ("messageActionHistoryClear", [])
case .messageActionInviteToGroupCall(let call, let users): case .messageActionInviteToGroupCall(let call, let users):
return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)]) return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)])
case .messageActionPaidMessagesPrice(let stars):
return ("messageActionPaidMessagesPrice", [("stars", stars as Any)])
case .messageActionPaidMessagesRefunded(let count, let stars):
return ("messageActionPaidMessagesRefunded", [("count", count as Any), ("stars", stars as Any)])
case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge): case .messageActionPaymentRefunded(let flags, let peer, let currency, let totalAmount, let payload, let charge):
return ("messageActionPaymentRefunded", [("flags", flags as Any), ("peer", peer as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("payload", payload as Any), ("charge", charge as Any)]) return ("messageActionPaymentRefunded", [("flags", flags as Any), ("peer", peer as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("payload", payload as Any), ("charge", charge as Any)])
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let subscriptionUntilDate): case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let subscriptionUntilDate):
@ -1277,6 +1296,31 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_messageActionPaidMessagesPrice(_ reader: BufferReader) -> MessageAction? {
var _1: Int64?
_1 = reader.readInt64()
let _c1 = _1 != nil
if _c1 {
return Api.MessageAction.messageActionPaidMessagesPrice(stars: _1!)
}
else {
return nil
}
}
public static func parse_messageActionPaidMessagesRefunded(_ reader: BufferReader) -> MessageAction? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageAction.messageActionPaidMessagesRefunded(count: _1!, stars: _2!)
}
else {
return nil
}
}
public static func parse_messageActionPaymentRefunded(_ reader: BufferReader) -> MessageAction? { public static func parse_messageActionPaymentRefunded(_ reader: BufferReader) -> MessageAction? {
var _1: Int32? var _1: Int32?
_1 = reader.readInt32() _1 = reader.readInt32()

View File

@ -227,7 +227,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] {
} }
switch action { switch action {
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique: case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction, .messageActionBotAllowed, .messageActionSecureValuesSent, .messageActionSecureValuesSentMe, .messageActionContactSignUp, .messageActionGroupCall, .messageActionSetMessagesTTL, .messageActionGroupCallScheduled, .messageActionSetChatTheme, .messageActionChatJoinedByRequest, .messageActionWebViewDataSent, .messageActionWebViewDataSentMe, .messageActionGiftPremium, .messageActionGiftStars, .messageActionTopicCreate, .messageActionTopicEdit, .messageActionSuggestProfilePhoto, .messageActionSetChatWallPaper, .messageActionGiveawayLaunch, .messageActionGiveawayResults, .messageActionBoostApply, .messageActionRequestedPeerSentMe, .messageActionStarGift, .messageActionStarGiftUnique, .messageActionPaidMessagesRefunded, .messageActionPaidMessagesPrice:
break break
case let .messageActionChannelMigrateFrom(_, chatId): case let .messageActionChannelMigrateFrom(_, chatId):
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))) result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId)))

View File

@ -191,6 +191,10 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return nil return nil
} }
return TelegramMediaAction(action: .starGiftUnique(gift: gift, isUpgrade: (flags & (1 << 0)) != 0, isTransferred: (flags & (1 << 1)) != 0, savedToProfile: (flags & (1 << 2)) != 0, canExportDate: canExportAt, transferStars: transferStars, isRefunded: (flags & (1 << 5)) != 0, peerId: peer?.peerId, senderId: fromId?.peerId, savedId: savedId)) return TelegramMediaAction(action: .starGiftUnique(gift: gift, isUpgrade: (flags & (1 << 0)) != 0, isTransferred: (flags & (1 << 1)) != 0, savedToProfile: (flags & (1 << 2)) != 0, canExportDate: canExportAt, transferStars: transferStars, isRefunded: (flags & (1 << 5)) != 0, peerId: peer?.peerId, senderId: fromId?.peerId, savedId: savedId))
case let .messageActionPaidMessagesRefunded(count, stars):
return TelegramMediaAction(action: .paidMessagesRefunded(count: count, stars: stars))
case let .messageActionPaidMessagesPrice(stars):
return TelegramMediaAction(action: .paidMessagesPriceEdited(stars: stars))
} }
} }

View File

@ -132,6 +132,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case prizeStars(amount: Int64, isUnclaimed: Bool, boostPeerId: PeerId?, transactionId: String?, giveawayMessageId: MessageId?) case prizeStars(amount: Int64, isUnclaimed: Bool, boostPeerId: PeerId?, transactionId: String?, giveawayMessageId: MessageId?)
case starGift(gift: StarGift, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, isRefunded: Bool, upgradeMessageId: Int32?, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?) case starGift(gift: StarGift, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, isRefunded: Bool, upgradeMessageId: Int32?, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?)
case starGiftUnique(gift: StarGift, isUpgrade: Bool, isTransferred: Bool, savedToProfile: Bool, canExportDate: Int32?, transferStars: Int64?, isRefunded: Bool, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?) case starGiftUnique(gift: StarGift, isUpgrade: Bool, isTransferred: Bool, savedToProfile: Bool, canExportDate: Int32?, transferStars: Int64?, isRefunded: Bool, peerId: EnginePeer.Id?, senderId: EnginePeer.Id?, savedId: Int64?)
case paidMessagesRefunded(count: Int32, stars: Int64)
case paidMessagesPriceEdited(stars: Int64)
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
@ -256,6 +258,10 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeOptionalInt64ForKey("convertStars"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false), upgraded: decoder.decodeBoolForKey("upgraded", orElse: false), canUpgrade: decoder.decodeBoolForKey("canUpgrade", orElse: false), upgradeStars: decoder.decodeOptionalInt64ForKey("upgradeStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), upgradeMessageId: decoder.decodeOptionalInt32ForKey("upgradeMessageId"), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId")) self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeOptionalInt64ForKey("convertStars"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false), upgraded: decoder.decodeBoolForKey("upgraded", orElse: false), canUpgrade: decoder.decodeBoolForKey("canUpgrade", orElse: false), upgradeStars: decoder.decodeOptionalInt64ForKey("upgradeStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), upgradeMessageId: decoder.decodeOptionalInt32ForKey("upgradeMessageId"), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId"))
case 45: case 45:
self = .starGiftUnique(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, isUpgrade: decoder.decodeBoolForKey("isUpgrade", orElse: false), isTransferred: decoder.decodeBoolForKey("isTransferred", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), canExportDate: decoder.decodeOptionalInt32ForKey("canExportDate"), transferStars: decoder.decodeOptionalInt64ForKey("transferStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId")) self = .starGiftUnique(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, isUpgrade: decoder.decodeBoolForKey("isUpgrade", orElse: false), isTransferred: decoder.decodeBoolForKey("isTransferred", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), canExportDate: decoder.decodeOptionalInt32ForKey("canExportDate"), transferStars: decoder.decodeOptionalInt64ForKey("transferStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false), peerId: decoder.decodeOptionalInt64ForKey("peerId").flatMap { EnginePeer.Id($0) }, senderId: decoder.decodeOptionalInt64ForKey("senderId").flatMap { EnginePeer.Id($0) }, savedId: decoder.decodeOptionalInt64ForKey("savedId"))
case 46:
self = .paidMessagesRefunded(count: decoder.decodeInt32ForKey("count", orElse: 0), stars: decoder.decodeInt64ForKey("stars", orElse: 0))
case 47:
self = .paidMessagesPriceEdited(stars: decoder.decodeInt64ForKey("stars", orElse: 0))
default: default:
self = .unknown self = .unknown
} }
@ -626,6 +632,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
} else { } else {
encoder.encodeNil(forKey: "savedId") encoder.encodeNil(forKey: "savedId")
} }
case let .paidMessagesRefunded(count, stars):
encoder.encodeInt32(46, forKey: "_rawValue")
encoder.encodeInt32(count, forKey: "count")
encoder.encodeInt64(stars, forKey: "stars")
case let .paidMessagesPriceEdited(stars):
encoder.encodeInt32(47, forKey: "_rawValue")
encoder.encodeInt64(stars, forKey: "stars")
} }
} }

View File

@ -109,7 +109,14 @@ func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network,
return .single([]) return .single([])
} }
if let channel = peer as? TelegramChannel, case .group = channel.info { if let channel = peer as? TelegramChannel {
if case .group = channel.info {
} else if channel.adminRights != nil || channel.flags.contains(.isCreator) {
} else {
return .single([])
}
} else { } else {
return .single([]) return .single([])
} }

View File

@ -170,6 +170,12 @@ public final class PrincipalThemeEssentialGraphics {
public let outgoingDateAndStatusRepliesIcon: UIImage public let outgoingDateAndStatusRepliesIcon: UIImage
public let mediaRepliesIcon: UIImage public let mediaRepliesIcon: UIImage
public let freeRepliesIcon: UIImage public let freeRepliesIcon: UIImage
public let incomingDateAndStatusStarsIcon: UIImage
public let outgoingDateAndStatusStarsIcon: UIImage
public let mediaStarsIcon: UIImage
public let freeStarsIcon: UIImage
public let incomingDateAndStatusPinnedIcon: UIImage public let incomingDateAndStatusPinnedIcon: UIImage
public let outgoingDateAndStatusPinnedIcon: UIImage public let outgoingDateAndStatusPinnedIcon: UIImage
public let mediaPinnedIcon: UIImage public let mediaPinnedIcon: UIImage
@ -358,6 +364,12 @@ public final class PrincipalThemeEssentialGraphics {
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)! self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)! self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
let starsImage = UIImage(bundleImageName: "Chat/Message/StarsCount")!
self.incomingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.incoming.secondaryTextColor)!
self.outgoingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.outgoing.secondaryTextColor)!
self.mediaStarsIcon = generateTintedImage(image: starsImage, color: .white)!
self.freeStarsIcon = generateTintedImage(image: starsImage, color: serviceColor.primaryText)!
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")! let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)! self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)! self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)!
@ -479,6 +491,12 @@ public final class PrincipalThemeEssentialGraphics {
self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)! self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)!
self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)! self.freeRepliesIcon = generateTintedImage(image: repliesImage, color: serviceColor.primaryText)!
let starsImage = UIImage(bundleImageName: "Chat/Message/StarsCount")!
self.incomingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.incoming.secondaryTextColor)!
self.outgoingDateAndStatusStarsIcon = generateTintedImage(image: starsImage, color: theme.message.outgoing.secondaryTextColor)!
self.mediaStarsIcon = generateTintedImage(image: starsImage, color: .white)!
self.freeStarsIcon = generateTintedImage(image: starsImage, color: serviceColor.primaryText)!
let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")! let pinnedImage = UIImage(bundleImageName: "Chat/Message/Pinned")!
self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)! self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)!
self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)! self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)!

View File

@ -1196,6 +1196,33 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} }
} }
} }
case let .paidMessagesRefunded(_, stars):
let starsString = strings.Notification_PaidMessageRefund_Stars(Int32(stars))
if message.author?.id == accountPeerId, let messagePeer = message.peers[message.id.peerId] {
let peerName = EnginePeer(messagePeer).compactDisplayTitle
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(1, messagePeer.id)])
attributes[0] = boldAttributes
let resultString = strings.Notification_PaidMessageRefundYou(starsString, peerName)
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
} else {
let peerName = message.author?.compactDisplayTitle ?? ""
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
attributes[1] = boldAttributes
let resultString = strings.Notification_PaidMessageRefund(peerName, starsString)
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
}
case let .paidMessagesPriceEdited(stars):
let starsString = strings.Notification_PaidMessagePriceChanged_Stars(Int32(stars))
if message.author?.id == accountPeerId {
let resultString = strings.Notification_PaidMessagePriceChangedYou(starsString)
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} else {
let peerName = message.author?.compactDisplayTitle ?? ""
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
attributes[1] = boldAttributes
let resultString = strings.Notification_PaidMessagePriceChanged(peerName, starsString)
attributedString = addAttributesToStringWithRanges(resultString._tuple, body: bodyAttributes, argumentAttributes: attributes)
}
case .unknown: case .unknown:
attributedString = nil attributedString = nil
} }

View File

@ -413,7 +413,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.incomingDateAndStatusPinnedIcon repliesImage = graphics.incomingDateAndStatusPinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.incomingDateAndStatusRepliesIcon starsImage = graphics.incomingDateAndStatusStarsIcon
} }
case let .BubbleOutgoing(status): case let .BubbleOutgoing(status):
dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor
@ -432,7 +432,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.outgoingDateAndStatusPinnedIcon repliesImage = graphics.outgoingDateAndStatusPinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.outgoingDateAndStatusRepliesIcon starsImage = graphics.outgoingDateAndStatusStarsIcon
} }
case .ImageIncoming: case .ImageIncoming:
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
@ -451,7 +451,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.mediaPinnedIcon repliesImage = graphics.mediaPinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.mediaRepliesIcon starsImage = graphics.mediaStarsIcon
} }
case let .ImageOutgoing(status): case let .ImageOutgoing(status):
dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor
@ -471,7 +471,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.mediaPinnedIcon repliesImage = graphics.mediaPinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.mediaRepliesIcon starsImage = graphics.mediaStarsIcon
} }
case .FreeIncoming: case .FreeIncoming:
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
@ -492,7 +492,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.freePinnedIcon repliesImage = graphics.freePinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.freeRepliesIcon starsImage = graphics.freeStarsIcon
} }
case let .FreeOutgoing(status): case let .FreeOutgoing(status):
let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper)
@ -513,7 +513,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode {
repliesImage = graphics.freePinnedIcon repliesImage = graphics.freePinnedIcon
} }
if (arguments.starsCount ?? 0) != 0 { if (arguments.starsCount ?? 0) != 0 {
starsImage = graphics.freeRepliesIcon starsImage = graphics.freeStarsIcon
} }
} }

View File

@ -516,7 +516,7 @@ public final class PeerInfoCoverComponent: Component {
let baseItemDistance: CGFloat = baseDistance + CGFloat(row) * baseRowDistance let baseItemDistance: CGFloat = baseDistance + CGFloat(row) * baseRowDistance
let itemDistanceFraction = max(0.0, min(1.0, baseItemDistance / (baseDistance * 2.0))) let itemDistanceFraction = max(0.0, min(1.0, baseItemDistance / (baseDistance * 2.0)))
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: itemDistanceFraction, reverse: false) let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, reverse: false)
let itemDistance = baseItemDistance * (1.0 - itemScaleFraction) + 20.0 * itemScaleFraction let itemDistance = baseItemDistance * (1.0 - itemScaleFraction) + 20.0 * itemScaleFraction
var itemAngle: CGFloat var itemAngle: CGFloat

View File

@ -19,6 +19,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
public let giftsContext: ProfileGiftsContext public let giftsContext: ProfileGiftsContext
public let hasBackground: Bool public let hasBackground: Bool
public let avatarCenter: CGPoint public let avatarCenter: CGPoint
public let avatarSize: CGSize
public let defaultHeight: CGFloat public let defaultHeight: CGFloat
public let avatarTransitionFraction: CGFloat public let avatarTransitionFraction: CGFloat
public let statusBarHeight: CGFloat public let statusBarHeight: CGFloat
@ -34,6 +35,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
giftsContext: ProfileGiftsContext, giftsContext: ProfileGiftsContext,
hasBackground: Bool, hasBackground: Bool,
avatarCenter: CGPoint, avatarCenter: CGPoint,
avatarSize: CGSize,
defaultHeight: CGFloat, defaultHeight: CGFloat,
avatarTransitionFraction: CGFloat, avatarTransitionFraction: CGFloat,
statusBarHeight: CGFloat, statusBarHeight: CGFloat,
@ -48,6 +50,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
self.giftsContext = giftsContext self.giftsContext = giftsContext
self.hasBackground = hasBackground self.hasBackground = hasBackground
self.avatarCenter = avatarCenter self.avatarCenter = avatarCenter
self.avatarSize = avatarSize
self.defaultHeight = defaultHeight self.defaultHeight = defaultHeight
self.avatarTransitionFraction = avatarTransitionFraction self.avatarTransitionFraction = avatarTransitionFraction
self.statusBarHeight = statusBarHeight self.statusBarHeight = statusBarHeight
@ -71,6 +74,9 @@ public final class PeerInfoGiftsCoverComponent: Component {
if lhs.avatarCenter != rhs.avatarCenter { if lhs.avatarCenter != rhs.avatarCenter {
return false return false
} }
if lhs.avatarSize != rhs.avatarSize {
return false
}
if lhs.defaultHeight != rhs.defaultHeight { if lhs.defaultHeight != rhs.defaultHeight {
return false return false
} }
@ -298,26 +304,25 @@ public final class PeerInfoGiftsCoverComponent: Component {
} }
iconLayer.glowing = component.hasBackground iconLayer.glowing = component.hasBackground
let centerPosition = component.avatarCenter let itemDistanceFraction = max(0.0, min(1.0, iconPosition.distance / 100.0))
let finalPosition = iconPosition.center.offsetBy(dx: component.avatarCenter.x, dy: component.avatarCenter.y) let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, reverse: false)
let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, reverse: false)
func interpolateRect(from: CGPoint, to: CGPoint, t: CGFloat) -> CGPoint { func interpolatePosition(from: PositionGenerator.Position, to: PositionGenerator.Position, t: CGFloat) -> PositionGenerator.Position {
let clampedT = max(0, min(1, t)) let clampedT = max(0, min(1, t))
let interpolatedX = from.x + (to.x - from.x) * clampedT let interpolatedDistance = from.distance + (to.distance - from.distance) * clampedT
let interpolatedY = from.y + (to.y - from.y) * clampedT let interpolatedAngle = from.angle + (to.angle - from.angle) * clampedT
return CGPoint( return PositionGenerator.Position(distance: interpolatedDistance, angle: interpolatedAngle, scale: from.scale)
x: interpolatedX,
y: interpolatedY
)
} }
let effectivePosition = interpolateRect(from: finalPosition, to: centerPosition, t: itemScaleFraction) let centerPosition = PositionGenerator.Position(distance: 0.0, angle: iconPosition.angle + .pi * 0.18, scale: iconPosition.scale)
let effectivePosition = interpolatePosition(from: iconPosition, to: centerPosition, t: itemScaleFraction)
let position = getAbsolutePosition(position: effectivePosition, centerPoint: component.avatarCenter)
iconTransition.setBounds(layer: iconLayer, bounds: CGRect(origin: .zero, size: iconSize)) iconTransition.setBounds(layer: iconLayer, bounds: CGRect(origin: .zero, size: iconSize))
iconTransition.setPosition(layer: iconLayer, position: effectivePosition) iconTransition.setPosition(layer: iconLayer, position: position)
iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction)) iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction))
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction) iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
@ -638,8 +643,16 @@ private class GiftIconLayer: SimpleLayer {
private struct PositionGenerator { private struct PositionGenerator {
struct Position { struct Position {
let center: CGPoint let distance: CGFloat
let angle: CGFloat
let scale: CGFloat let scale: CGFloat
var relativeCartesian: CGPoint {
return CGPoint(
x: self.distance * cos(self.angle),
y: self.distance * sin(self.angle)
)
}
} }
let containerSize: CGSize let containerSize: CGSize
@ -700,15 +713,14 @@ private struct PositionGenerator {
let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min
let orbitDistanceFactor = self.innerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next()) let orbitDistanceFactor = self.innerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
let orbitDistance = orbitDistanceFactor * centerRadius let distance = orbitDistanceFactor * centerRadius
let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2) let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next()) let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
let absoluteX = centerPoint.x + orbitDistance * cos(angle) // Get the absolute position to check boundaries and collisions
let absoluteY = centerPoint.y + orbitDistance * sin(angle) let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
if absolutePosition.x - itemSize.width/2 < self.edgePadding || if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding || absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
@ -717,11 +729,6 @@ private struct PositionGenerator {
continue continue
} }
let relativePosition = CGPoint(
x: absolutePosition.x - centerPoint.x,
y: absolutePosition.y - centerPoint.y
)
let itemRect = CGRect( let itemRect = CGRect(
x: absolutePosition.x - itemSize.width/2, x: absolutePosition.x - itemSize.width/2,
y: absolutePosition.y - itemSize.height/2, y: absolutePosition.y - itemSize.height/2,
@ -729,10 +736,12 @@ private struct PositionGenerator {
height: itemSize.height height: itemSize.height
) )
if self.isValidPosition(itemRect, existingPositions: positions.map { self.posToAbsolute($0.center, centerPoint: centerPoint) }, itemSize: itemSize) { if self.isValidPosition(itemRect, existingPositions: positions.map {
getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint)
}, itemSize: itemSize) {
let scaleRangeSize = max(self.scaleRange.min + 0.1, 0.75) - self.scaleRange.max let scaleRangeSize = max(self.scaleRange.min + 0.1, 0.75) - self.scaleRange.max
let scale = self.scaleRange.max + scaleRangeSize * CGFloat(self.lokiRng.next()) let scale = self.scaleRange.max + scaleRangeSize * CGFloat(self.lokiRng.next())
positions.append(Position(center: relativePosition, scale: scale)) positions.append(Position(distance: distance, angle: angle, scale: scale))
if absolutePosition.x < centerPoint.x { if absolutePosition.x < centerPoint.x {
leftPositions += 1 leftPositions += 1
@ -751,15 +760,14 @@ private struct PositionGenerator {
let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min
let orbitDistanceFactor = self.outerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next()) let orbitDistanceFactor = self.outerOrbitRange.min + orbitRangeSize * CGFloat(self.lokiRng.next())
let orbitDistance = orbitDistanceFactor * centerRadius let distance = orbitDistanceFactor * centerRadius
let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi let angleRange: CGFloat = placeOnLeftSide ? .pi : .pi
let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2) let angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2)
let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next()) let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next())
let absoluteX = centerPoint.x + orbitDistance * cos(angle) // Get the absolute position to check boundaries and collisions
let absoluteY = centerPoint.y + orbitDistance * sin(angle) let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint)
let absolutePosition = CGPoint(x: absoluteX, y: absoluteY)
if absolutePosition.x - itemSize.width/2 < self.edgePadding || if absolutePosition.x - itemSize.width/2 < self.edgePadding ||
absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding || absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding ||
@ -768,11 +776,6 @@ private struct PositionGenerator {
continue continue
} }
let relativePosition = CGPoint(
x: absolutePosition.x - centerPoint.x,
y: absolutePosition.y - centerPoint.y
)
let itemRect = CGRect( let itemRect = CGRect(
x: absolutePosition.x - itemSize.width/2, x: absolutePosition.x - itemSize.width/2,
y: absolutePosition.y - itemSize.height/2, y: absolutePosition.y - itemSize.height/2,
@ -780,12 +783,12 @@ private struct PositionGenerator {
height: itemSize.height height: itemSize.height
) )
if self.isValidPosition(itemRect, existingPositions: positions.map { self.posToAbsolute($0.center, centerPoint: centerPoint) }, itemSize: itemSize) { if self.isValidPosition(itemRect, existingPositions: positions.map {
let distance = hypot(absolutePosition.x - centerPoint.x, absolutePosition.y - centerPoint.y) getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint)
}, itemSize: itemSize) {
let normalizedDistance = min(distance / maxPossibleDistance, 1.0) let normalizedDistance = min(distance / maxPossibleDistance, 1.0)
let scale = self.scaleRange.max - normalizedDistance * (self.scaleRange.max - self.scaleRange.min) let scale = self.scaleRange.max - normalizedDistance * (self.scaleRange.max - self.scaleRange.min)
positions.append(Position(center: relativePosition, scale: scale)) positions.append(Position(distance: distance, angle: angle, scale: scale))
if absolutePosition.x < centerPoint.x { if absolutePosition.x < centerPoint.x {
leftPositions += 1 leftPositions += 1
@ -798,8 +801,11 @@ private struct PositionGenerator {
return positions return positions
} }
private func posToAbsolute(_ relativePos: CGPoint, centerPoint: CGPoint) -> CGPoint { func getAbsolutePosition(distance: CGFloat, angle: CGFloat, centerPoint: CGPoint) -> CGPoint {
return CGPoint(x: relativePos.x + centerPoint.x, y: relativePos.y + centerPoint.y) return CGPoint(
x: centerPoint.x + distance * cos(angle),
y: centerPoint.y + distance * sin(angle)
)
} }
private func isValidPosition(_ rect: CGRect, existingPositions: [CGPoint], itemSize: CGSize) -> Bool { private func isValidPosition(_ rect: CGRect, existingPositions: [CGPoint], itemSize: CGSize) -> Bool {
@ -827,6 +833,20 @@ private struct PositionGenerator {
} }
} }
private func getAbsolutePosition(position: PositionGenerator.Position, centerPoint: CGPoint) -> CGPoint {
return CGPoint(
x: centerPoint.x + position.distance * cos(position.angle),
y: centerPoint.y + position.distance * sin(position.angle)
)
}
private func getAbsolutePosition(distance: CGFloat, angle: CGFloat, centerPoint: CGPoint) -> CGPoint {
return CGPoint(
x: centerPoint.x + distance * cos(angle),
y: centerPoint.y + distance * sin(angle)
)
}
private func windowFunction(t: CGFloat) -> CGFloat { private func windowFunction(t: CGFloat) -> CGFloat {
return bezierPoint(0.6, 0.0, 0.4, 1.0, t) return bezierPoint(0.6, 0.0, 0.4, 1.0, t)
} }

View File

@ -2352,6 +2352,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
giftsContext: profileGiftsContext, giftsContext: profileGiftsContext,
hasBackground: hasBackground, hasBackground: hasBackground,
avatarCenter: apparentAvatarFrame.center, avatarCenter: apparentAvatarFrame.center,
avatarSize: apparentAvatarFrame.size,
defaultHeight: backgroundDefaultHeight, defaultHeight: backgroundDefaultHeight,
avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)), avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)),
statusBarHeight: statusBarHeight, statusBarHeight: statusBarHeight,

View File

@ -165,9 +165,9 @@ private final class SheetContent: CombinedComponent {
iconName: "Account Freeze/Appeal", iconName: "Account Freeze/Appeal",
iconColor: linkColor, iconColor: linkColor,
action: { action: {
component.submitAppeal()
Queue.mainQueue().after(1.0) {
component.dismiss() component.dismiss()
Queue.mainQueue().after(0.5) {
component.submitAppeal()
} }
} }
)) ))
@ -201,9 +201,9 @@ private final class SheetContent: CombinedComponent {
isEnabled: true, isEnabled: true,
displaysProgress: false, displaysProgress: false,
action: { action: {
component.submitAppeal()
Queue.mainQueue().after(1.0) {
component.dismiss() component.dismiss()
Queue.mainQueue().after(0.5) {
component.submitAppeal()
} }
} }
), ),

View File

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "hand_30.pdf", "filename" : "sandtimer_30.pdf",
"idiom" : "universal" "idiom" : "universal"
} }
], ],

View File

@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "sandtimer_30.pdf", "filename" : "hand_30.pdf",
"idiom" : "universal" "idiom" : "universal"
} }
], ],

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "msgstar.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -266,6 +266,9 @@ public final class AccountContextImpl: AccountContext {
public private(set) var isPremium: Bool public private(set) var isPremium: Bool
private var isFrozenDisposable: Disposable?
public private(set) var isFrozen: Bool
public let imageCache: AnyObject? public let imageCache: AnyObject?
public init(sharedContext: SharedAccountContextImpl, account: Account, limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, appConfiguration: AppConfiguration, availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions, temp: Bool = false) public init(sharedContext: SharedAccountContextImpl, account: Account, limitsConfiguration: LimitsConfiguration, contentSettings: ContentSettings, appConfiguration: AppConfiguration, availableReplyColors: EngineAvailableColorOptions, availableProfileColors: EngineAvailableColorOptions, temp: Bool = false)
@ -280,6 +283,7 @@ public final class AccountContextImpl: AccountContext {
self.peerNameColors = PeerNameColors.with(availableReplyColors: availableReplyColors, availableProfileColors: availableProfileColors) self.peerNameColors = PeerNameColors.with(availableReplyColors: availableReplyColors, availableProfileColors: availableProfileColors)
self.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue self.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue
self.isPremium = false self.isPremium = false
self.isFrozen = false
self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager) self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager)
@ -452,6 +456,18 @@ public final class AccountContextImpl: AccountContext {
} }
self.audioTranscriptionTrial = audioTranscriptionTrial self.audioTranscriptionTrial = audioTranscriptionTrial
}) })
self.isFrozenDisposable = (self.appConfiguration
|> map { appConfiguration in
return AccountFreezeConfiguration.with(appConfiguration: appConfiguration).freezeUntilDate != nil
}
|> distinctUntilChanged
|> deliverOnMainQueue).startStrict(next: { [weak self] isFrozen in
guard let self = self else {
return
}
self.isFrozen = isFrozen
})
} }
deinit { deinit {
@ -464,6 +480,7 @@ public final class AccountContextImpl: AccountContext {
self.animatedEmojiStickersDisposable?.dispose() self.animatedEmojiStickersDisposable?.dispose()
self.userLimitsConfigurationDisposable?.dispose() self.userLimitsConfigurationDisposable?.dispose()
self.peerNameColorsConfigurationDisposable?.dispose() self.peerNameColorsConfigurationDisposable?.dispose()
self.isFrozenDisposable?.dispose()
} }
public func storeSecureIdPassword(password: String) { public func storeSecureIdPassword(password: String) {

View File

@ -0,0 +1,32 @@
import Foundation
import UIKit
import SwiftSignalKit
import Postbox
import TelegramCore
import AsyncDisplayKit
import Display
import ContextUI
import UndoUI
import AccountContext
import ChatControllerInteraction
import AnimatedTextComponent
import ChatMessagePaymentAlertController
import TelegramPresentationData
import TelegramNotices
extension ChatControllerImpl {
func presentAccountFrozenInfoIfNeeded() -> Bool {
if self.context.isFrozen {
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
if let freezeAppealUrl = accountFreezeConfiguration.freezeAppealUrl {
let components = freezeAppealUrl.components(separatedBy: "/")
if let username = components.last, let peer = self.presentationInterfaceState.renderedPeer?.peer, peer.addressName == username {
return false
}
}
self.push(self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context))
return true
}
return false
}
}

View File

@ -1865,6 +1865,12 @@ extension ChatControllerImpl {
guard let strongSelf = self, strongSelf.isNodeLoaded else { guard let strongSelf = self, strongSelf.isNodeLoaded else {
return return
} }
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
completion(.immediate, {})
return
}
if let messageId = messageId { if let messageId = messageId {
let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState) let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState)
var canSendMessagesHere = intrinsicCanSendMessagesHere var canSendMessagesHere = intrinsicCanSendMessagesHere
@ -2114,6 +2120,11 @@ extension ChatControllerImpl {
}) })
}, deleteMessages: { [weak self] messages, contextController, completion in }, deleteMessages: { [weak self] messages, contextController, completion in
if let strongSelf = self, !messages.isEmpty { if let strongSelf = self, !messages.isEmpty {
guard !strongSelf.presentAccountFrozenInfoIfNeeded() else {
completion(.default)
return
}
let messageIds = Set(messages.map { $0.id }) let messageIds = Set(messages.map { $0.id })
strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds, keepUpdated: false) strongSelf.messageContextDisposable.set((strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: messageIds, keepUpdated: false)
|> deliverOnMainQueue).startStrict(next: { actions in |> deliverOnMainQueue).startStrict(next: { actions in
@ -4416,10 +4427,7 @@ extension ChatControllerImpl {
return return
} }
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) guard !self.presentAccountFrozenInfoIfNeeded() else {
if let _ = accountFreezeConfiguration.freezeUntilDate {
let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context)
self.push(controller)
return return
} }

View File

@ -333,6 +333,9 @@ extension ChatControllerImpl {
} }
controller?.dismissWithoutContent() controller?.dismissWithoutContent()
guard !self.presentAccountFrozenInfoIfNeeded() else {
return
}
self.presentTagPremiumPaywall() self.presentTagPremiumPaywall()
} }
@ -341,6 +344,11 @@ extension ChatControllerImpl {
return return
} }
guard !self.presentAccountFrozenInfoIfNeeded() else {
controller?.dismiss(completion: {})
return
}
guard let message = messages.first else { guard let message = messages.first else {
return return
} }

View File

@ -3399,8 +3399,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
}, scheduleCurrentMessage: { [weak self] params in }, scheduleCurrentMessage: { [weak self] params in
if let strongSelf = self { guard let self else {
strongSelf.presentScheduleTimePicker(completion: { [weak self] time in return
}
guard !self.presentAccountFrozenInfoIfNeeded() else {
return
}
self.presentScheduleTimePicker(completion: { [weak self] time in
if let strongSelf = self { if let strongSelf = self {
if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState { if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState {
strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap { strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap {
@ -3424,17 +3429,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
}) })
}
}, sendScheduledMessagesNow: { [weak self] messageIds in }, sendScheduledMessagesNow: { [weak self] messageIds in
if let strongSelf = self { guard let self else {
if let _ = strongSelf.presentationInterfaceState.slowmodeState { return
if let rect = strongSelf.chatDisplayNode.frameForInputActionButton() { }
strongSelf.interfaceInteraction?.displaySlowmodeTooltip(strongSelf.chatDisplayNode.view, rect) guard !self.presentAccountFrozenInfoIfNeeded() else {
return
}
if let _ = self.presentationInterfaceState.slowmodeState {
if let rect = self.chatDisplayNode.frameForInputActionButton() {
self.interfaceInteraction?.displaySlowmodeTooltip(self.chatDisplayNode.view, rect)
} }
return return
} else { } else {
let _ = strongSelf.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone() let _ = self.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone()
}
} }
}, editScheduledMessagesTime: { [weak self] messageIds in }, editScheduledMessagesTime: { [weak self] messageIds in
if let strongSelf = self, let messageId = messageIds.first { if let strongSelf = self, let messageId = messageIds.first {

View File

@ -21,8 +21,16 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
return (nil, nil) return (nil, nil)
} }
if context.isFrozen {
var isActuallyFrozen = true
let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
if let _ = accountFreezeConfiguration.freezeUntilDate { if let freezeAppealUrl = accountFreezeConfiguration.freezeAppealUrl {
let components = freezeAppealUrl.components(separatedBy: "/")
if let username = components.last, let peer = chatPresentationInterfaceState.renderedPeer?.peer, peer.addressName == username {
isActuallyFrozen = false
}
}
if isActuallyFrozen {
if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) {
return (currentPanel, nil) return (currentPanel, nil)
} else { } else {
@ -32,6 +40,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
return (panel, nil) return (panel, nil)
} }
} }
}
if let _ = chatPresentationInterfaceState.search { if let _ = chatPresentationInterfaceState.search {
var selectionPanel: ChatMessageSelectionInputPanelNode? var selectionPanel: ChatMessageSelectionInputPanelNode?

View File

@ -644,7 +644,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
return self.actionButtons.micButton return self.actionButtons.micButton
} }
private let startingBotDisposable = MetaDisposable()
private let statusDisposable = MetaDisposable() private let statusDisposable = MetaDisposable()
override var interfaceInteraction: ChatPanelInterfaceInteraction? { override var interfaceInteraction: ChatPanelInterfaceInteraction? {
didSet { didSet {
@ -655,25 +654,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
self?.updateIsProcessingInlineRequest(value) self?.updateIsProcessingInlineRequest(value)
}).strict()) }).strict())
} }
if let startingBot = self.interfaceInteraction?.statuses?.startingBot {
self.startingBotDisposable.set((startingBot |> deliverOnMainQueue).startStrict(next: { [weak self] value in
if let strongSelf = self {
strongSelf.startingBotProgress = value
}
}).strict())
}
}
}
private var startingBotProgress = false {
didSet {
// if self.startingBotProgress != oldValue {
// if self.startingBotProgress {
// self.startButton.transitionToProgress()
// } else {
// self.startButton.transitionFromProgress()
// }
// }
} }
} }
@ -1130,7 +1110,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
deinit { deinit {
self.statusDisposable.dispose() self.statusDisposable.dispose()
self.startingBotDisposable.dispose()
self.tooltipController?.dismiss() self.tooltipController?.dismiss()
self.currentEmojiSuggestion?.disposable.dispose() self.currentEmojiSuggestion?.disposable.dispose()
} }

View File

@ -2451,6 +2451,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
mappedSource = .animatedEmoji mappedSource = .animatedEmoji
case .paidMessages: case .paidMessages:
mappedSource = .paidMessages mappedSource = .paidMessages
case let .auth(price):
mappedSource = .auth(price)
} }
return mappedSource return mappedSource
} }
@ -2465,13 +2467,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return controller return controller
} }
public func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, dismissed: (() -> Void)?) -> ViewController { public func makePremiumIntroController(sharedContext: SharedAccountContext, engine: TelegramEngineUnauthorized, inAppPurchaseManager: InAppPurchaseManager, source: PremiumIntroSource, proceed: (() -> Void)?) -> ViewController {
var modal = true var modal = true
if case .settings = source { if case .settings = source {
modal = false modal = false
} }
let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal) let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal)
controller.wasDismissed = dismissed controller.customProceed = proceed
return controller return controller
} }