diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 272447cd7e..c232c208da 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -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.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"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index aaa6ae47f3..958b1beef7 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1053,7 +1053,7 @@ public protocol SharedAccountContext: AnyObject { func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> 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 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 { get } var isPremium: Bool { get } + var isFrozen: Bool { get } var userLimits: EngineConfiguration.UserLimits { get } var peerNameColors: PeerNameColors { get } diff --git a/submodules/AccountContext/Sources/Premium.swift b/submodules/AccountContext/Sources/Premium.swift index 86a92800d1..cccec77d59 100644 --- a/submodules/AccountContext/Sources/Premium.swift +++ b/submodules/AccountContext/Sources/Premium.swift @@ -43,6 +43,7 @@ public enum PremiumIntroSource { case animatedEmoji case messageEffects case paidMessages + case auth(String) } public enum PremiumGiftSource: Equatable { diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 914bfb8934..51354a786d 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -251,15 +251,17 @@ final class AuthorizationSequencePaymentScreenComponent: Component { iconName: "Premium/Authorization/Support", iconColor: linkColor, 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 } let introController = component.sharedContext.makePremiumIntroController( sharedContext: component.sharedContext, engine: component.engine, inAppPurchaseManager: component.inAppPurchaseManager, - source: .about, - dismissed: nil + source: .auth(product.price), + proceed: { [weak self] in + self?.proceed() + } ) controller.push(introController) } @@ -274,11 +276,13 @@ final class AuthorizationSequencePaymentScreenComponent: Component { 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 listSpacing: CGFloat = 12.0 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 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) } - 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 bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset @@ -329,7 +331,7 @@ final class AuthorizationSequencePaymentScreenComponent: Component { component: AnyComponent( VStack([ 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) ) ), @@ -410,6 +412,10 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo fatalError("init(coder:) has not been implemented") } + override public func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + } + @objc private func cancelPressed() { self.dismiss() } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index b567a0a2a8..6d5338baa8 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2794,6 +2794,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController private weak var storyCameraTooltip: TooltipScreen? 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 premiumNeeded = false var hasActiveCall = false @@ -4641,6 +4647,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } @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 { return } diff --git a/submodules/Components/SolidRoundedButtonComponent/Sources/SolidRoundedButtonComponent.swift b/submodules/Components/SolidRoundedButtonComponent/Sources/SolidRoundedButtonComponent.swift index aa65028e56..f6630c9ac9 100644 --- a/submodules/Components/SolidRoundedButtonComponent/Sources/SolidRoundedButtonComponent.swift +++ b/submodules/Components/SolidRoundedButtonComponent/Sources/SolidRoundedButtonComponent.swift @@ -9,6 +9,7 @@ public final class SolidRoundedButtonComponent: Component { public typealias Theme = SolidRoundedButtonTheme public let title: String? + public let subtitle: String? public let label: String? public let badge: String? public let icon: UIImage? @@ -28,6 +29,7 @@ public final class SolidRoundedButtonComponent: Component { public init( title: String? = nil, + subtitle: String? = nil, label: String? = nil, badge: String? = nil, icon: UIImage? = nil, @@ -46,6 +48,7 @@ public final class SolidRoundedButtonComponent: Component { action: @escaping () -> Void ) { self.title = title + self.subtitle = subtitle self.label = label self.badge = badge self.icon = icon @@ -68,6 +71,9 @@ public final class SolidRoundedButtonComponent: Component { if lhs.title != rhs.title { return false } + if lhs.subtitle != rhs.subtitle { + return false + } if lhs.label != rhs.label { return false } @@ -147,6 +153,7 @@ public final class SolidRoundedButtonComponent: Component { if let button = self.button { button.title = component.title + button.subtitle = component.subtitle button.label = component.label button.badge = component.badge button.iconPosition = component.iconPosition diff --git a/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift b/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift index e3b6141e82..4eeac4b0c1 100644 --- a/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift +++ b/submodules/Components/ViewControllerComponent/Sources/ViewControllerComponent.swift @@ -242,6 +242,7 @@ open class ViewControllerComponentContainer: ViewController { public private(set) var validLayout: ContainerViewLayout? public var wasDismissed: (() -> Void)? + public var customProceed: (() -> Void)? public init( context: AccountContext, diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h index efdee05775..ba44c28837 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGMediaEditingContext.h @@ -67,9 +67,7 @@ - (SSignal *)coverImageSignalForItem:(NSObject *)item; - (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id)item; - (UIImage *)coverImageForItem:(NSObject *)item; - - (NSNumber *)coverPositionForItem:(NSObject *)item; -- (void)setCoverImage:(UIImage *)image position:(NSNumber *)position forItem:(id)item; - (void)setTemporaryRep:(id)rep forItem:(id)item; diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index 61175ca87b..76082e2966 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -309,6 +309,12 @@ public enum PremiumSource: Equatable { } else { 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 messageEffects case paidMessages + case auth(String) var identifier: String? { switch self { @@ -452,6 +459,8 @@ public enum PremiumSource: Equatable { return "effects" case .paidMessages: return "paid_messages" + case .auth: + return "auth" } } } @@ -1214,6 +1223,7 @@ final class PerkComponent: CombinedComponent { let subtitleColor: UIColor let arrowColor: UIColor let accentColor: UIColor + let displayArrow: Bool let badge: String? init( @@ -1225,6 +1235,7 @@ final class PerkComponent: CombinedComponent { subtitleColor: UIColor, arrowColor: UIColor, accentColor: UIColor, + displayArrow: Bool = true, badge: String? = nil ) { self.iconName = iconName @@ -1235,6 +1246,7 @@ final class PerkComponent: CombinedComponent { self.subtitleColor = subtitleColor self.arrowColor = arrowColor self.accentColor = accentColor + self.displayArrow = displayArrow self.badge = badge } @@ -1263,6 +1275,9 @@ final class PerkComponent: CombinedComponent { if lhs.accentColor != rhs.accentColor { return false } + if lhs.displayArrow != rhs.displayArrow { + return false + } if lhs.badge != rhs.badge { return false } @@ -1305,16 +1320,7 @@ final class PerkComponent: CombinedComponent { availableSize: iconSize, 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( component: MultilineTextComponent( 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) - context.add(arrow - .position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0)) - ) + + 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 + .position(CGPoint(x: context.availableSize.width - 7.0 - arrow.size.width / 2.0, y: size.height / 2.0)) + ) + } return size } @@ -2086,6 +2103,7 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { foregroundColor: .white, iconName: perk.iconName ))), false), + accessory: accountContext != nil ? .arrow : nil, action: { [weak state] _ in guard let accountContext else { return @@ -2162,7 +2180,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { updateIsFocused(true) addAppLogEvent(postbox: accountContext.account.postbox, type: "premium.promo_screen_tap", data: ["item": perk.identifier]) - } + }, + highlighting: accountContext != nil ? .default : .disabled )))) i += 1 } @@ -3660,7 +3679,11 @@ private final class PremiumIntroScreenComponent: CombinedComponent { if !buttonIsHidden { 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 } else if state.isPremium == true && state.canUpgrade { 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 } + let controller = environment.controller let sideInset: CGFloat = 16.0 let button = button.update( component: SolidRoundedButtonComponent( title: buttonTitle, + subtitle: buttonSubtitle, theme: SolidRoundedButtonComponent.Theme( backgroundColor: UIColor(rgb: 0x8878ff), backgroundColors: [ @@ -3687,7 +3712,12 @@ private final class PremiumIntroScreenComponent: CombinedComponent { gloss: true, isLoading: state.inProgress, action: { - state.buy() + if let controller = controller() as? PremiumIntroScreen, let customProceed = controller.customProceed { + controller.dismiss() + customProceed() + } else { + state.buy() + } } ), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - environment.safeInsets.left - environment.safeInsets.right, height: 50.0), diff --git a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift index e18a0ac730..7b724ca498 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsPeersController.swift @@ -315,7 +315,7 @@ private func selectivePrivacyPeersControllerEntries(presentationData: Presentati entries.append(.footerItem(footer)) } - if !peers.isEmpty { + if !peers.isEmpty || state.enableForPremium || state.enableForBots { entries.append(.deleteItem(presentationData.strings.Privacy_Exceptions_DeleteAllExceptions)) } diff --git a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift index 5574b7f9f1..3c10b7dca4 100644 --- a/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift +++ b/submodules/SolidRoundedButtonNode/Sources/SolidRoundedButtonNode.swift @@ -1412,7 +1412,7 @@ public final class SolidRoundedButtonView: UIView { } 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) @@ -1472,7 +1472,7 @@ public final class SolidRoundedButtonView: UIView { } 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 iconSpacing: CGFloat = self.iconSpacing let badgeSpacing: CGFloat = 6.0 @@ -1533,11 +1533,11 @@ public final class SolidRoundedButtonView: UIView { } 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 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) if previousSubtitle == nil && self.subtitle != nil { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 4d7c541c9a..0efc2bec9d 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -577,6 +577,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) } dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($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[-970673810] = { return Api.MessageAction.parse_messageActionPaymentSent($0) } dict[-6288180] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) } diff --git a/submodules/TelegramApi/Sources/Api15.swift b/submodules/TelegramApi/Sources/Api15.swift index 72842970c5..63df242808 100644 --- a/submodules/TelegramApi/Sources/Api15.swift +++ b/submodules/TelegramApi/Sources/Api15.swift @@ -363,6 +363,8 @@ public extension Api { case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32) case messageActionHistoryClear 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 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?) @@ -595,6 +597,19 @@ public extension Api { serializeInt64(item, buffer: buffer, boxed: false) } 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): if boxed { buffer.appendInt32(1102307842) @@ -847,6 +862,10 @@ public extension Api { return ("messageActionHistoryClear", []) case .messageActionInviteToGroupCall(let call, let users): 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): 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): @@ -1277,6 +1296,31 @@ public extension Api { 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? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 03276a38be..d3fe483a2e 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -227,7 +227,7 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { } 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 case let .messageActionChannelMigrateFrom(_, chatId): result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(chatId))) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift index e4e7923481..2dccae65da 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift @@ -191,6 +191,10 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe 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)) + case let .messageActionPaidMessagesRefunded(count, stars): + return TelegramMediaAction(action: .paidMessagesRefunded(count: count, stars: stars)) + case let .messageActionPaidMessagesPrice(stars): + return TelegramMediaAction(action: .paidMessagesPriceEdited(stars: stars)) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift index 6dc1fdecb2..513375d750 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift @@ -132,6 +132,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { 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 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) { 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")) 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")) + 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: self = .unknown } @@ -626,6 +632,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { } else { 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") } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SendAsPeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SendAsPeers.swift index b9630127c2..01422837b6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/SendAsPeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/SendAsPeers.swift @@ -109,7 +109,14 @@ func _internal_peerSendAsAvailablePeers(accountPeerId: PeerId, network: Network, 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 { return .single([]) } diff --git a/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift b/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift index 5143dcad64..69c7260435 100644 --- a/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift +++ b/submodules/TelegramPresentationData/Sources/PresentationThemeEssentialGraphics.swift @@ -170,6 +170,12 @@ public final class PrincipalThemeEssentialGraphics { public let outgoingDateAndStatusRepliesIcon: UIImage public let mediaRepliesIcon: 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 outgoingDateAndStatusPinnedIcon: UIImage public let mediaPinnedIcon: UIImage @@ -358,6 +364,12 @@ public final class PrincipalThemeEssentialGraphics { self.mediaRepliesIcon = generateTintedImage(image: repliesImage, color: .white)! 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")! self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.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.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")! self.incomingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.incoming.secondaryTextColor)! self.outgoingDateAndStatusPinnedIcon = generateTintedImage(image: pinnedImage, color: theme.message.outgoing.secondaryTextColor)! diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 89a13d50e5..4f75317468 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -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: attributedString = nil } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift index eca913ad51..5d7a6a9ae0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode/Sources/ChatMessageDateAndStatusNode.swift @@ -413,7 +413,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.incomingDateAndStatusPinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.incomingDateAndStatusRepliesIcon + starsImage = graphics.incomingDateAndStatusStarsIcon } case let .BubbleOutgoing(status): dateColor = arguments.presentationData.theme.theme.chat.message.outgoing.secondaryTextColor @@ -432,7 +432,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.outgoingDateAndStatusPinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.outgoingDateAndStatusRepliesIcon + starsImage = graphics.outgoingDateAndStatusStarsIcon } case .ImageIncoming: dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor @@ -451,7 +451,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.mediaPinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.mediaRepliesIcon + starsImage = graphics.mediaStarsIcon } case let .ImageOutgoing(status): dateColor = arguments.presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor @@ -471,7 +471,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.mediaPinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.mediaRepliesIcon + starsImage = graphics.mediaStarsIcon } case .FreeIncoming: let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) @@ -492,7 +492,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.freePinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.freeRepliesIcon + starsImage = graphics.freeStarsIcon } case let .FreeOutgoing(status): let serviceColor = serviceMessageColorComponents(theme: arguments.presentationData.theme.theme, wallpaper: arguments.presentationData.theme.wallpaper) @@ -513,7 +513,7 @@ public class ChatMessageDateAndStatusNode: ASDisplayNode { repliesImage = graphics.freePinnedIcon } if (arguments.starsCount ?? 0) != 0 { - starsImage = graphics.freeRepliesIcon + starsImage = graphics.freeStarsIcon } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift index baf1702c7e..74e3de47ae 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift @@ -516,7 +516,7 @@ public final class PeerInfoCoverComponent: Component { let baseItemDistance: CGFloat = baseDistance + CGFloat(row) * baseRowDistance 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 var itemAngle: CGFloat diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift index 6c81f40c57..776c0ea55e 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoGiftsCoverComponent.swift @@ -19,6 +19,7 @@ public final class PeerInfoGiftsCoverComponent: Component { public let giftsContext: ProfileGiftsContext public let hasBackground: Bool public let avatarCenter: CGPoint + public let avatarSize: CGSize public let defaultHeight: CGFloat public let avatarTransitionFraction: CGFloat public let statusBarHeight: CGFloat @@ -34,6 +35,7 @@ public final class PeerInfoGiftsCoverComponent: Component { giftsContext: ProfileGiftsContext, hasBackground: Bool, avatarCenter: CGPoint, + avatarSize: CGSize, defaultHeight: CGFloat, avatarTransitionFraction: CGFloat, statusBarHeight: CGFloat, @@ -48,6 +50,7 @@ public final class PeerInfoGiftsCoverComponent: Component { self.giftsContext = giftsContext self.hasBackground = hasBackground self.avatarCenter = avatarCenter + self.avatarSize = avatarSize self.defaultHeight = defaultHeight self.avatarTransitionFraction = avatarTransitionFraction self.statusBarHeight = statusBarHeight @@ -71,6 +74,9 @@ public final class PeerInfoGiftsCoverComponent: Component { if lhs.avatarCenter != rhs.avatarCenter { return false } + if lhs.avatarSize != rhs.avatarSize { + return false + } if lhs.defaultHeight != rhs.defaultHeight { return false } @@ -298,26 +304,25 @@ public final class PeerInfoGiftsCoverComponent: Component { } iconLayer.glowing = component.hasBackground - let centerPosition = component.avatarCenter - let finalPosition = iconPosition.center.offsetBy(dx: component.avatarCenter.x, dy: component.avatarCenter.y) - let itemScaleFraction = patternScaleValueAt(fraction: component.avatarTransitionFraction, t: 0.0, reverse: false) + let itemDistanceFraction = max(0.0, min(1.0, iconPosition.distance / 100.0)) + let itemScaleFraction = patternScaleValueAt(fraction: min(1.0, component.avatarTransitionFraction * 1.56), t: itemDistanceFraction, 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 interpolatedX = from.x + (to.x - from.x) * clampedT - let interpolatedY = from.y + (to.y - from.y) * clampedT + let interpolatedDistance = from.distance + (to.distance - from.distance) * clampedT + let interpolatedAngle = from.angle + (to.angle - from.angle) * clampedT - return CGPoint( - x: interpolatedX, - y: interpolatedY - ) + return PositionGenerator.Position(distance: interpolatedDistance, angle: interpolatedAngle, scale: from.scale) } - 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.setPosition(layer: iconLayer, position: effectivePosition) + iconTransition.setPosition(layer: iconLayer, position: position) iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction)) iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction) @@ -638,8 +643,16 @@ private class GiftIconLayer: SimpleLayer { private struct PositionGenerator { struct Position { - let center: CGPoint + let distance: CGFloat + let angle: CGFloat let scale: CGFloat + + var relativeCartesian: CGPoint { + return CGPoint( + x: self.distance * cos(self.angle), + y: self.distance * sin(self.angle) + ) + } } let containerSize: CGSize @@ -700,15 +713,14 @@ private struct PositionGenerator { let orbitRangeSize = self.innerOrbitRange.max - self.innerOrbitRange.min 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 angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2) let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next()) - let absoluteX = centerPoint.x + orbitDistance * cos(angle) - let absoluteY = centerPoint.y + orbitDistance * sin(angle) - let absolutePosition = CGPoint(x: absoluteX, y: absoluteY) + // Get the absolute position to check boundaries and collisions + let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint) if absolutePosition.x - itemSize.width/2 < self.edgePadding || absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding || @@ -717,11 +729,6 @@ private struct PositionGenerator { continue } - let relativePosition = CGPoint( - x: absolutePosition.x - centerPoint.x, - y: absolutePosition.y - centerPoint.y - ) - let itemRect = CGRect( x: absolutePosition.x - itemSize.width/2, y: absolutePosition.y - itemSize.height/2, @@ -729,10 +736,12 @@ private struct PositionGenerator { 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 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 { leftPositions += 1 @@ -751,15 +760,14 @@ private struct PositionGenerator { let orbitRangeSize = self.outerOrbitRange.max - self.outerOrbitRange.min 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 angleOffset: CGFloat = placeOnLeftSide ? .pi/2 : -(.pi/2) let angle = angleOffset + angleRange * CGFloat(self.lokiRng.next()) - let absoluteX = centerPoint.x + orbitDistance * cos(angle) - let absoluteY = centerPoint.y + orbitDistance * sin(angle) - let absolutePosition = CGPoint(x: absoluteX, y: absoluteY) + // Get the absolute position to check boundaries and collisions + let absolutePosition = getAbsolutePosition(distance: distance, angle: angle, centerPoint: centerPoint) if absolutePosition.x - itemSize.width/2 < self.edgePadding || absolutePosition.x + itemSize.width/2 > self.containerSize.width - self.edgePadding || @@ -768,11 +776,6 @@ private struct PositionGenerator { continue } - let relativePosition = CGPoint( - x: absolutePosition.x - centerPoint.x, - y: absolutePosition.y - centerPoint.y - ) - let itemRect = CGRect( x: absolutePosition.x - itemSize.width/2, y: absolutePosition.y - itemSize.height/2, @@ -780,12 +783,12 @@ private struct PositionGenerator { height: itemSize.height ) - if self.isValidPosition(itemRect, existingPositions: positions.map { self.posToAbsolute($0.center, centerPoint: centerPoint) }, itemSize: itemSize) { - let distance = hypot(absolutePosition.x - centerPoint.x, absolutePosition.y - centerPoint.y) - + if self.isValidPosition(itemRect, existingPositions: positions.map { + getAbsolutePosition(distance: $0.distance, angle: $0.angle, centerPoint: centerPoint) + }, itemSize: itemSize) { let normalizedDistance = min(distance / maxPossibleDistance, 1.0) 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 { leftPositions += 1 @@ -798,8 +801,11 @@ private struct PositionGenerator { return positions } - private func posToAbsolute(_ relativePos: CGPoint, centerPoint: CGPoint) -> CGPoint { - return CGPoint(x: relativePos.x + centerPoint.x, y: relativePos.y + centerPoint.y) + 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 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 { return bezierPoint(0.6, 0.0, 0.4, 1.0, t) } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift index 1c0c8c45df..b0aedadc45 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift @@ -2352,6 +2352,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { giftsContext: profileGiftsContext, hasBackground: hasBackground, avatarCenter: apparentAvatarFrame.center, + avatarSize: apparentAvatarFrame.size, defaultHeight: backgroundDefaultHeight, avatarTransitionFraction: max(0.0, min(1.0, titleCollapseFraction + transitionFraction * 2.0)), statusBarHeight: statusBarHeight, diff --git a/submodules/TelegramUI/Components/Settings/AccountFreezeInfoScreen/Sources/AccountFreezeInfoScreen.swift b/submodules/TelegramUI/Components/Settings/AccountFreezeInfoScreen/Sources/AccountFreezeInfoScreen.swift index 64960bfc00..9de68c6b39 100644 --- a/submodules/TelegramUI/Components/Settings/AccountFreezeInfoScreen/Sources/AccountFreezeInfoScreen.swift +++ b/submodules/TelegramUI/Components/Settings/AccountFreezeInfoScreen/Sources/AccountFreezeInfoScreen.swift @@ -165,9 +165,9 @@ private final class SheetContent: CombinedComponent { iconName: "Account Freeze/Appeal", iconColor: linkColor, 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, displaysProgress: false, action: { - component.submitAppeal() - Queue.mainQueue().after(1.0) { - component.dismiss() + component.dismiss() + Queue.mainQueue().after(0.5) { + component.submitAppeal() } } ), diff --git a/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/Contents.json index 93a1282c31..ecd534d108 100644 --- a/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "hand_30.pdf", + "filename" : "sandtimer_30.pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/sandtimer_30.pdf b/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/sandtimer_30.pdf similarity index 100% rename from submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/sandtimer_30.pdf rename to submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/sandtimer_30.pdf diff --git a/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/Contents.json index ecd534d108..93a1282c31 100644 --- a/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "sandtimer_30.pdf", + "filename" : "hand_30.pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/hand_30.pdf b/submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/hand_30.pdf similarity index 100% rename from submodules/TelegramUI/Images.xcassets/Account Freeze/Appeal.imageset/hand_30.pdf rename to submodules/TelegramUI/Images.xcassets/Account Freeze/Violation.imageset/hand_30.pdf diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/Contents.json new file mode 100644 index 0000000000..fa834c36d7 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "msgstar.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/msgstar.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/msgstar.pdf new file mode 100644 index 0000000000..5565014e2c Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat/Message/StarsCount.imageset/msgstar.pdf differ diff --git a/submodules/TelegramUI/Sources/AccountContext.swift b/submodules/TelegramUI/Sources/AccountContext.swift index 490328164c..0b6ab11965 100644 --- a/submodules/TelegramUI/Sources/AccountContext.swift +++ b/submodules/TelegramUI/Sources/AccountContext.swift @@ -266,6 +266,9 @@ public final class AccountContextImpl: AccountContext { public private(set) var isPremium: Bool + private var isFrozenDisposable: Disposable? + public private(set) var isFrozen: Bool + public let imageCache: AnyObject? 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.audioTranscriptionTrial = AudioTranscription.TrialState.defaultValue self.isPremium = false + self.isFrozen = false self.downloadedMediaStoreManager = DownloadedMediaStoreManagerImpl(postbox: account.postbox, accountManager: sharedContext.accountManager) @@ -452,6 +456,18 @@ public final class AccountContextImpl: AccountContext { } 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 { @@ -464,6 +480,7 @@ public final class AccountContextImpl: AccountContext { self.animatedEmojiStickersDisposable?.dispose() self.userLimitsConfigurationDisposable?.dispose() self.peerNameColorsConfigurationDisposable?.dispose() + self.isFrozenDisposable?.dispose() } public func storeSecureIdPassword(password: String) { diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerFrozenAccount.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerFrozenAccount.swift new file mode 100644 index 0000000000..c4d0348db4 --- /dev/null +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerFrozenAccount.swift @@ -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 + } +} diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index 20be263b74..b38259a3c5 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -1865,6 +1865,12 @@ extension ChatControllerImpl { guard let strongSelf = self, strongSelf.isNodeLoaded else { return } + + guard !strongSelf.presentAccountFrozenInfoIfNeeded() else { + completion(.immediate, {}) + return + } + if let messageId = messageId { let intrinsicCanSendMessagesHere = canSendMessagesToChat(strongSelf.presentationInterfaceState) var canSendMessagesHere = intrinsicCanSendMessagesHere @@ -2114,6 +2120,11 @@ extension ChatControllerImpl { }) }, deleteMessages: { [weak self] messages, contextController, completion in if let strongSelf = self, !messages.isEmpty { + guard !strongSelf.presentAccountFrozenInfoIfNeeded() else { + completion(.default) + return + } + 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) |> deliverOnMainQueue).startStrict(next: { actions in @@ -4416,13 +4427,10 @@ extension ChatControllerImpl { return } - let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) - if let _ = accountFreezeConfiguration.freezeUntilDate { - let controller = self.context.sharedContext.makeAccountFreezeInfoScreen(context: self.context) - self.push(controller) + guard !self.presentAccountFrozenInfoIfNeeded() else { return } - + guard let peerId = self.chatLocation.peerId, let cachedData = self.peerView?.cachedData as? CachedChannelData, let boostToUnrestrict = cachedData.boostsToUnrestrict else { return } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift index 66b8679ef6..785024337b 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerOpenMessageContextMenu.swift @@ -333,6 +333,9 @@ extension ChatControllerImpl { } controller?.dismissWithoutContent() + guard !self.presentAccountFrozenInfoIfNeeded() else { + return + } self.presentTagPremiumPaywall() } @@ -341,6 +344,11 @@ extension ChatControllerImpl { return } + guard !self.presentAccountFrozenInfoIfNeeded() else { + controller?.dismiss(completion: {}) + return + } + guard let message = messages.first else { return } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f61918c4e7..957f6e77fe 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3399,42 +3399,51 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } }, scheduleCurrentMessage: { [weak self] params in - if let strongSelf = self { - strongSelf.presentScheduleTimePicker(completion: { [weak self] time in - if let strongSelf = self { - if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState { - strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap { - return ChatSendMessageEffect(id: $0.id) - }) - } else { - let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting - strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, messageEffect: (params?.effect).flatMap { - return ChatSendMessageEffect(id: $0.id) - }) { [weak self] in - if let strongSelf = self { - strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, { - $0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) } - }) - - if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { - strongSelf.openScheduledMessages() - } + guard let self else { + return + } + guard !self.presentAccountFrozenInfoIfNeeded() else { + return + } + self.presentScheduleTimePicker(completion: { [weak self] time in + if let strongSelf = self { + if let _ = strongSelf.presentationInterfaceState.interfaceState.mediaDraftState { + strongSelf.sendMediaRecording(scheduleTime: time, messageEffect: (params?.effect).flatMap { + return ChatSendMessageEffect(id: $0.id) + }) + } else { + let silentPosting = strongSelf.presentationInterfaceState.interfaceState.silentPosting + strongSelf.chatDisplayNode.sendCurrentMessage(silentPosting: silentPosting, scheduleTime: time, messageEffect: (params?.effect).flatMap { + return ChatSendMessageEffect(id: $0.id) + }) { [weak self] in + if let strongSelf = self { + strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: false, saveInterfaceState: strongSelf.presentationInterfaceState.subject != .scheduledMessages, { + $0.updatedInterfaceState { $0.withUpdatedReplyMessageSubject(nil).withUpdatedSendMessageEffect(nil).withUpdatedForwardMessageIds(nil).withUpdatedForwardOptionsState(nil).withUpdatedComposeInputState(ChatTextInputState(inputText: NSAttributedString(string: ""))) } + }) + + if strongSelf.presentationInterfaceState.subject != .scheduledMessages && time != scheduleWhenOnlineTimestamp { + strongSelf.openScheduledMessages() } } } } - }) - } - }, sendScheduledMessagesNow: { [weak self] messageIds in - if let strongSelf = self { - if let _ = strongSelf.presentationInterfaceState.slowmodeState { - if let rect = strongSelf.chatDisplayNode.frameForInputActionButton() { - strongSelf.interfaceInteraction?.displaySlowmodeTooltip(strongSelf.chatDisplayNode.view, rect) - } - return - } else { - let _ = strongSelf.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone() } + }) + }, sendScheduledMessagesNow: { [weak self] messageIds in + guard let self else { + return + } + guard !self.presentAccountFrozenInfoIfNeeded() else { + return + } + + if let _ = self.presentationInterfaceState.slowmodeState { + if let rect = self.chatDisplayNode.frameForInputActionButton() { + self.interfaceInteraction?.displaySlowmodeTooltip(self.chatDisplayNode.view, rect) + } + return + } else { + let _ = self.context.engine.messages.sendScheduledMessageNowInteractively(messageId: messageIds.first!).startStandalone() } }, editScheduledMessagesTime: { [weak self] messageIds in if let strongSelf = self, let messageId = messageIds.first { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift index 486f255b1c..f69d9ad7a9 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift @@ -21,15 +21,24 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState return (nil, nil) } - let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) - if let _ = accountFreezeConfiguration.freezeUntilDate { - if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { - return (currentPanel, nil) - } else { - let panel = ChatRestrictedInputPanelNode() - panel.context = context - panel.interfaceInteraction = interfaceInteraction - return (panel, nil) + if context.isFrozen { + var isActuallyFrozen = true + let accountFreezeConfiguration = AccountFreezeConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 }) + 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) { + return (currentPanel, nil) + } else { + let panel = ChatRestrictedInputPanelNode() + panel.context = context + panel.interfaceInteraction = interfaceInteraction + return (panel, nil) + } } } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index bf2d24cdc6..f6b6715f03 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -644,7 +644,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch return self.actionButtons.micButton } - private let startingBotDisposable = MetaDisposable() private let statusDisposable = MetaDisposable() override var interfaceInteraction: ChatPanelInterfaceInteraction? { didSet { @@ -655,28 +654,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch self?.updateIsProcessingInlineRequest(value) }).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() -// } -// } - } - } - + func updateInputTextState(_ state: ChatTextInputState, keepSendButtonEnabled: Bool, extendedSearchLayout: Bool, accessoryItems: [ChatTextInputAccessoryItem], animated: Bool) { if let currentState = self.presentationInterfaceState { var updateAccessoryButtons = false @@ -1130,7 +1110,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch deinit { self.statusDisposable.dispose() - self.startingBotDisposable.dispose() self.tooltipController?.dismiss() self.currentEmojiSuggestion?.disposable.dispose() } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 65c74b7751..16a7303a7c 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -2451,6 +2451,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { mappedSource = .animatedEmoji case .paidMessages: mappedSource = .paidMessages + case let .auth(price): + mappedSource = .auth(price) } return mappedSource } @@ -2465,13 +2467,13 @@ public final class SharedAccountContextImpl: SharedAccountContext { 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 if case .settings = source { modal = false } let controller = PremiumIntroScreen(screenContext: .sharedContext(sharedContext, engine, inAppPurchaseManager), source: self.mapIntroSource(source: source), modal: modal) - controller.wasDismissed = dismissed + controller.customProceed = proceed return controller }