diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 39c216d423..763900807a 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14916,3 +14916,11 @@ Sorry for the inconvenience."; "Conversation.StopVoiceMessageDescription" = "Are you sure you want to pause recording?"; "Conversation.StopVoiceMessageDiscardAction" = "Discard"; "Conversation.StopVoiceMessagePauseAction" = "Pause"; + +"Gift.Options.GiftLocked.Title" = "Gift Locked"; + +"Gift.Unique.Value" = "Value"; +"Gift.Unique.LearnMore" = "learn more"; + +"Gift.Upgrade.GiftUpgrade" = "Pay %@ for Upgrade"; +"Gift.View.GiftUpgrade" = "Gift an Upgrade"; diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 2d3d1734c2..e186981260 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1180,7 +1180,7 @@ public protocol SharedAccountContext: AnyObject { func navigateToChat(accountId: AccountRecordId, peerId: PeerId, messageId: MessageId?) func openChatMessage(_ params: OpenChatMessageParams) -> Bool func messageFromPreloadedChatHistoryViewForLocation(id: MessageId, location: ChatHistoryLocationInput, context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, chatLocationContextHolder: Atomic, tag: HistoryViewInputTag?) -> Signal<(MessageIndex?, Bool), NoError> - func makeOverlayAudioPlayerController(context: AccountContext, chatLocation: ChatLocation, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, parentNavigationController: NavigationController?, updateMusicSaved: ((FileMediaReference, Bool) -> Void)?, reorderSavedMusic: ((FileMediaReference, FileMediaReference?) -> Void)?) -> ViewController & OverlayAudioPlayerController + func makeOverlayAudioPlayerController(context: AccountContext, chatLocation: ChatLocation, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, parentNavigationController: NavigationController?) -> ViewController & OverlayAudioPlayerController func makePeerInfoController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, fromChat: Bool, requestsContext: PeerInvitationImportersContext?) -> ViewController? func makeChannelAdminController(context: AccountContext, peerId: PeerId, adminId: PeerId, initialParticipant: ChannelParticipant) -> ViewController? func makeDeviceContactInfoController(context: ShareControllerAccountContext, environment: ShareControllerEnvironment, subject: DeviceContactInfoSubject, completed: (() -> Void)?, cancelled: (() -> Void)?) -> ViewController diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index fbba79185a..ccd93181b5 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -1179,7 +1179,7 @@ public enum ChatHistoryListSource { } case `default` - case custom(messages: Signal<([Message], Int32, Bool), NoError>, messageId: MessageId?, quote: Quote?, updateAll: Bool, canReorder: Bool, loadMore: (() -> Void)?) + case custom(messages: Signal<([Message], Int32, Bool), NoError>, messageId: MessageId?, quote: Quote?, isSavedMusic: Bool, canReorder: Bool, loadMore: (() -> Void)?) case customView(historyView: Signal<(MessageHistoryView, ViewUpdateType), NoError>) } diff --git a/submodules/AccountContext/Sources/MediaManager.swift b/submodules/AccountContext/Sources/MediaManager.swift index dba8c26977..b2a0964af4 100644 --- a/submodules/AccountContext/Sources/MediaManager.swift +++ b/submodules/AccountContext/Sources/MediaManager.swift @@ -12,6 +12,7 @@ public enum PeerMessagesMediaPlaylistId: Equatable, SharedMediaPlaylistId { case peer(PeerId) case recentActions(PeerId) case feed(Int32) + case savedMusic(PeerId) case custom public func isEqual(to: SharedMediaPlaylistId) -> Bool { @@ -26,6 +27,7 @@ public enum PeerMessagesPlaylistLocation: Equatable, SharedMediaPlaylistLocation case messages(chatLocation: ChatLocation, tagMask: MessageTags, at: MessageId) case singleMessage(MessageId) case recentActions(Message) + case savedMusic(context: ProfileSavedMusicContext, at: Int32, canReorder: Bool) case custom(messages: Signal<([Message], Int32, Bool), NoError>, canReorder: Bool, at: MessageId, loadMore: (() -> Void)?) public var playlistId: PeerMessagesMediaPlaylistId { @@ -43,11 +45,52 @@ public enum PeerMessagesPlaylistLocation: Equatable, SharedMediaPlaylistLocation return .peer(id.peerId) case let .recentActions(message): return .recentActions(message.id.peerId) + case let .savedMusic(context, _, _): + return .savedMusic(context.peerId) case .custom: return .custom } } + public func effectiveLocation(context: AccountContext) -> PeerMessagesPlaylistLocation { + switch self { + case let .savedMusic(savedMusicContext, at, canReorder): + let peerId = savedMusicContext.peerId + return .custom( + messages: combineLatest( + savedMusicContext.state, + context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: savedMusicContext.peerId)) + ) + |> map { state, peer in + var messages: [Message] = [] + var peers = SimpleDictionary() + if let peer { + peers[peerId] = peer._asPeer() + } + for file in state.files { + let stableId = UInt32(clamping: file.fileId.id % Int64(Int32.max)) + messages.append(Message(stableId: stableId, stableVersion: 0, id: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: Int32(stableId)), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [.music], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [file], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])) + } + var canLoadMore = false + if case let .ready(canLoadMoreValue) = state.dataState { + canLoadMore = canLoadMoreValue + } + return (messages, Int32(messages.count), canLoadMore) + }, + canReorder: canReorder, + at: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: at), + loadMore: { [weak savedMusicContext] in + guard let savedMusicContext else { + return + } + savedMusicContext.loadMore() + } + ) + default: + return self + } + } + public var messageId: MessageId? { switch self { case let .messages(_, _, messageId), let .singleMessage(messageId), let .custom(_, _, messageId, _): @@ -85,6 +128,12 @@ public enum PeerMessagesPlaylistLocation: Equatable, SharedMediaPlaylistLocation } else { return false } + case let .savedMusic(lhsContext, lhsAt, _): + if case let .savedMusic(rhsContext, rhsAt, _) = rhs { + return lhsContext.peerId == rhsContext.peerId && lhsAt == rhsAt + } else { + return false + } case let .custom(_, _, lhsAt, _): if case let .custom(_, _, rhsAt, _) = rhs, lhsAt == rhsAt { return true @@ -120,8 +169,10 @@ public func peerMessageMediaPlayerType(_ message: EngineMessage) -> MediaManager return nil } -public func peerMessagesMediaPlaylistAndItemId(_ message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool) -> (SharedMediaPlaylistId, SharedMediaPlaylistItemId)? { - if isGlobalSearch && !isDownloadList { +public func peerMessagesMediaPlaylistAndItemId(_ message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool, isSavedMusic: Bool) -> (SharedMediaPlaylistId, SharedMediaPlaylistItemId)? { + if isSavedMusic { + return (PeerMessagesMediaPlaylistId.savedMusic(message.id.peerId), PeerMessagesMediaPlaylistItemId(messageId: message.id, messageIndex: message.index)) + } else if isGlobalSearch && !isDownloadList { return (PeerMessagesMediaPlaylistId.custom, PeerMessagesMediaPlaylistItemId(messageId: message.id, messageIndex: message.index)) } else if isRecentActions && !isDownloadList { return (PeerMessagesMediaPlaylistId.recentActions(message.id.peerId), PeerMessagesMediaPlaylistItemId(messageId: message.id, messageIndex: message.index)) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift index e566c6b298..ff71e9e9cf 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequenceController.swift @@ -767,8 +767,8 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth return controller } - private func paymentController(number: String, phoneCodeHash: String, storeProduct: String) -> AuthorizationSequencePaymentScreen { - let controller = AuthorizationSequencePaymentScreen(sharedContext: self.sharedContext, engine: self.engine, presentationData: self.presentationData, inAppPurchaseManager: self.inAppPurchaseManager, phoneNumber: number, phoneCodeHash: phoneCodeHash, storeProduct: storeProduct, back: { [weak self] in + private func paymentController(number: String, phoneCodeHash: String, storeProduct: String, supportEmailAddress: String, supportEmailSubject: String) -> AuthorizationSequencePaymentScreen { + let controller = AuthorizationSequencePaymentScreen(sharedContext: self.sharedContext, engine: self.engine, presentationData: self.presentationData, inAppPurchaseManager: self.inAppPurchaseManager, phoneNumber: number, phoneCodeHash: phoneCodeHash, storeProduct: storeProduct, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject, back: { [weak self] in guard let self else { return } @@ -808,7 +808,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth case .emailNotAllowed: text = strongSelf.presentationData.strings.Login_EmailNotAllowedError } - lastController.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + lastController.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } })) } else { @@ -1305,12 +1305,12 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth } controllers.append(self.signUpController(firstName: firstName, lastName: lastName, termsOfService: termsOfService, displayCancel: displayCancel)) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) - case let .payment(number, codeHash, storeProduct, _): + case let .payment(number, codeHash, storeProduct, supportEmailAddress, supportEmailSubject, _): var controllers: [ViewController] = [] if !self.otherAccountPhoneNumbers.1.isEmpty { controllers.append(self.splashController()) } - controllers.append(self.paymentController(number: number, phoneCodeHash: codeHash, storeProduct: storeProduct)) + controllers.append(self.paymentController(number: number, phoneCodeHash: codeHash, storeProduct: storeProduct, supportEmailAddress: supportEmailAddress, supportEmailSubject: supportEmailSubject)) self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty) } } @@ -1337,7 +1337,7 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth } } - private static func presentEmailComposeController(address: String, subject: String, body: String, from controller: ViewController, presentationData: PresentationData) { + static func presentEmailComposeController(address: String, subject: String, body: String, from controller: ViewController, presentationData: PresentationData) { if MFMailComposeViewController.canSendMail() { final class ComposeDelegate: NSObject, MFMailComposeViewControllerDelegate { @objc func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { @@ -1414,24 +1414,20 @@ public final class AuthorizationSequenceController: NavigationController, ASAuth phoneNumber: String, mnc: String ) { - if MFMailComposeViewController.canSendMail() { - let formattedNumber = formatPhoneNumber(phoneNumber) - - var emailBody = "" - emailBody.append(presentationData.strings.Login_EmailCodeBody(formattedNumber).string) - emailBody.append("\n\n") - - let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" - let systemVersion = UIDevice.current.systemVersion - let locale = Locale.current.identifier - emailBody.append("Telegram: \(appVersion)\n") - emailBody.append("OS: \(systemVersion)\n") - emailBody.append("Locale: \(locale)\n") - emailBody.append("MNC: \(mnc)") - - AuthorizationSequenceController.presentEmailComposeController(address: "sms@telegram.org", subject: presentationData.strings.Login_EmailCodeSubject(formattedNumber).string, body: emailBody, from: controller, presentationData: presentationData) - } else { - controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: nil, text: presentationData.strings.Login_EmailNotConfiguredError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - } + let formattedNumber = formatPhoneNumber(phoneNumber) + + var emailBody = "" + emailBody.append(presentationData.strings.Login_EmailCodeBody(formattedNumber).string) + emailBody.append("\n\n") + + let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" + let systemVersion = UIDevice.current.systemVersion + let locale = Locale.current.identifier + emailBody.append("Telegram: \(appVersion)\n") + emailBody.append("OS: \(systemVersion)\n") + emailBody.append("Locale: \(locale)\n") + emailBody.append("MNC: \(mnc)") + + AuthorizationSequenceController.presentEmailComposeController(address: "sms@telegram.org", subject: presentationData.strings.Login_EmailCodeSubject(formattedNumber).string, body: emailBody, from: controller, presentationData: presentationData) } } diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 8310c8f980..1f35a72415 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -23,6 +23,9 @@ import Markdown import CountrySelectionUI import AccountContext import AlertUI +import MessageUI +import CoreTelephony +import PhoneNumberFormat final class AuthorizationSequencePaymentScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -34,6 +37,8 @@ final class AuthorizationSequencePaymentScreenComponent: Component { let phoneNumber: String let phoneCodeHash: String let storeProduct: String + let supportEmailAddress: String + let supportEmailSubject: String init( sharedContext: SharedAccountContext, @@ -42,7 +47,9 @@ final class AuthorizationSequencePaymentScreenComponent: Component { presentationData: PresentationData, phoneNumber: String, phoneCodeHash: String, - storeProduct: String + storeProduct: String, + supportEmailAddress: String, + supportEmailSubject: String ) { self.sharedContext = sharedContext self.engine = engine @@ -51,6 +58,8 @@ final class AuthorizationSequencePaymentScreenComponent: Component { self.phoneNumber = phoneNumber self.phoneCodeHash = phoneCodeHash self.storeProduct = storeProduct + self.supportEmailAddress = supportEmailAddress + self.supportEmailSubject = supportEmailSubject } static func ==(lhs: AuthorizationSequencePaymentScreenComponent, rhs: AuthorizationSequencePaymentScreenComponent) -> Bool { @@ -125,26 +134,54 @@ final class AuthorizationSequencePaymentScreenComponent: Component { self.state?.updated(transition: .immediate) var errorText: String? + var errorCode: Int32? switch error { case .generic: errorText = presentationData.strings.Premium_Purchase_ErrorUnknown + errorCode = 1001 case .network: errorText = presentationData.strings.Premium_Purchase_ErrorNetwork + errorCode = 1002 case .notAllowed: errorText = presentationData.strings.Premium_Purchase_ErrorNotAllowed + errorCode = 1003 case .cantMakePayments: errorText = presentationData.strings.Premium_Purchase_ErrorCantMakePayments + errorCode = 1004 case .assignFailed: errorText = presentationData.strings.Premium_Purchase_ErrorUnknown + errorCode = 1005 case .tryLater: errorText = presentationData.strings.Premium_Purchase_ErrorUnknown + errorCode = 1006 case .cancelled: break } - if let errorText { + if let errorText, let errorCode { let theme = AlertControllerTheme(presentationData: presentationData) - let alertController = textAlertController(alertContext: AlertControllerContext(theme: theme, themeSignal: .single(theme)), title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]) + let alertController = textAlertController( + alertContext: AlertControllerContext(theme: theme, themeSignal: .single(theme)), + title: nil, + text: errorText, + actions: [ + TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {}), + TextAlertAction(type: .defaultAction, title: presentationData.strings.Login_PhoneNumberHelp, action: { [weak controller] in + guard let controller else { + return + } + let formattedNumber = formatPhoneNumber(component.phoneNumber) + let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown" + let systemVersion = UIDevice.current.systemVersion + let locale = Locale.current.identifier + let carrier = CTCarrier() + let mnc = carrier.mobileNetworkCode ?? "none" + let errorString: String = "\(errorCode): \(errorText)" + + AuthorizationSequenceController.presentEmailComposeController(address: component.supportEmailAddress, subject: component.supportEmailSubject, body: presentationData.strings.Login_PhoneGenericEmailBody(formattedNumber, errorString, appVersion, systemVersion, locale, mnc).string, from: controller, presentationData: presentationData) + }) + ] + ) controller.present(alertController, in: .window(.root)) } })) @@ -377,6 +414,8 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo phoneNumber: String, phoneCodeHash: String, storeProduct: String, + supportEmailAddress: String, + supportEmailSubject: String, back: @escaping () -> Void ) { super.init(component: AuthorizationSequencePaymentScreenComponent( @@ -386,7 +425,9 @@ public final class AuthorizationSequencePaymentScreen: ViewControllerComponentCo presentationData: presentationData, phoneNumber: phoneNumber, phoneCodeHash: phoneCodeHash, - storeProduct: storeProduct + storeProduct: storeProduct, + supportEmailAddress: supportEmailAddress, + supportEmailSubject: supportEmailSubject ), navigationBarAppearance: .transparent, theme: .default, updatedPresentationData: (initial: presentationData, signal: .single(presentationData))) loadServerCountryCodes(accountManager: sharedContext.accountManager, engine: engine, completion: { [weak self] in diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 5ad9daebf4..86a748c929 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -4934,7 +4934,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } else { controllerContext = strongSelf.context.sharedContext.makeTempAccountContext(account: account) } - let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: .peer(id: id.messageId.peerId), type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: playlistLocation, parentNavigationController: navigationController, updateMusicSaved: nil, reorderSavedMusic: nil) + let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: .peer(id: id.messageId.peerId), type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: playlistLocation, parentNavigationController: navigationController) strongSelf.interaction.dismissInput() strongSelf.interaction.present(controller, nil) } else if case let .messages(chatLocation, _, _) = playlistLocation { @@ -4975,7 +4975,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } else { controllerContext = strongSelf.context.sharedContext.makeTempAccountContext(account: account) } - let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: navigationController, updateMusicSaved: nil, reorderSavedMusic: nil) + let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: navigationController) strongSelf.interaction.dismissInput() strongSelf.interaction.present(controller, nil) } else if index.1 { diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 026dfa2641..b4bfa0c22b 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1876,17 +1876,17 @@ public final class ChatListNode: ListView { switch notice { case .xmasPremiumGift: let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.xmasPremiumGift.id).startStandalone() - self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in + self.present?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gift", scale: 0.058, colors: ["__allcolors__": UIColor.white], title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, customUndoText: nil, timeout: 5.0), elevatedLayout: false, action: { _ in return true })) case .setupBirthday: let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupBirthday.id).startStandalone() - self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_BirthdayInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in + self.present?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gift", scale: 0.058, colors: ["__allcolors__": UIColor.white], title: nil, text: presentationData.strings.ChatList_BirthdayInSettingsInfo, customUndoText: nil, timeout: 5.0), elevatedLayout: false, action: { _ in return true })) case .birthdayPremiumGift: let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.todayBirthdays.id).startStandalone() - self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in + self.present?(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gift", scale: 0.058, colors: ["__allcolors__": UIColor.white], title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, customUndoText: nil, timeout: 5.0), elevatedLayout: false, action: { _ in return true })) case .premiumGrace: diff --git a/submodules/ComponentFlow/Source/Components/Text.swift b/submodules/ComponentFlow/Source/Components/Text.swift index b364de1224..65d9e81587 100644 --- a/submodules/ComponentFlow/Source/Components/Text.swift +++ b/submodules/ComponentFlow/Source/Components/Text.swift @@ -30,12 +30,16 @@ public final class Text: Component { public final class View: UIView { private var measureState: MeasureState? - public func update(component: Text, availableSize: CGSize) -> CGSize { + public func update(component: Text, availableSize: CGSize, transition: ComponentTransition) -> CGSize { let attributedText = NSAttributedString(string: component.text, attributes: [ NSAttributedString.Key.font: component.font, NSAttributedString.Key.foregroundColor: component.color ]) + if let tintColor = component.tintColor { + transition.setTintColor(layer: self.layer, color: tintColor) + } + if let measureState = self.measureState { if measureState.attributedText.isEqual(to: attributedText) && measureState.availableSize == availableSize { return measureState.size @@ -71,11 +75,13 @@ public final class Text: Component { public let text: String public let font: UIFont public let color: UIColor + public let tintColor: UIColor? - public init(text: String, font: UIFont, color: UIColor) { + public init(text: String, font: UIFont, color: UIColor, tintColor: UIColor? = nil) { self.text = text self.font = font self.color = color + self.tintColor = tintColor } public static func ==(lhs: Text, rhs: Text) -> Bool { @@ -88,6 +94,9 @@ public final class Text: Component { if !lhs.color.isEqual(rhs.color) { return false } + if lhs.tintColor != rhs.tintColor { + return false + } return true } @@ -96,6 +105,6 @@ public final class Text: Component { } public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { - return view.update(component: self, availableSize: availableSize) + return view.update(component: self, availableSize: availableSize, transition: transition) } } diff --git a/submodules/Components/BalancedTextComponent/Sources/BalancedTextComponent.swift b/submodules/Components/BalancedTextComponent/Sources/BalancedTextComponent.swift index 30453c2122..3908f9ae06 100644 --- a/submodules/Components/BalancedTextComponent/Sources/BalancedTextComponent.swift +++ b/submodules/Components/BalancedTextComponent/Sources/BalancedTextComponent.swift @@ -19,6 +19,7 @@ public final class BalancedTextComponent: Component { public let lineSpacing: CGFloat public let cutout: TextNodeCutout? public let insets: UIEdgeInsets + public let tintColor: UIColor? public let textShadowColor: UIColor? public let textShadowBlur: CGFloat? public let textStroke: (UIColor, CGFloat)? @@ -38,6 +39,7 @@ public final class BalancedTextComponent: Component { lineSpacing: CGFloat = 0.0, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), + tintColor: UIColor? = nil, textShadowColor: UIColor? = nil, textShadowBlur: CGFloat? = nil, textStroke: (UIColor, CGFloat)? = nil, @@ -56,6 +58,7 @@ public final class BalancedTextComponent: Component { self.lineSpacing = lineSpacing self.cutout = cutout self.insets = insets + self.tintColor = tintColor self.textShadowColor = textShadowColor self.textShadowBlur = textShadowBlur self.textStroke = textStroke @@ -94,7 +97,9 @@ public final class BalancedTextComponent: Component { if lhs.insets != rhs.insets { return false } - + if lhs.tintColor != rhs.tintColor { + return false + } if let lhsTextShadowColor = lhs.textShadowColor, let rhsTextShadowColor = rhs.textShadowColor { if !lhsTextShadowColor.isEqual(rhsTextShadowColor) { return false @@ -202,6 +207,10 @@ public final class BalancedTextComponent: Component { bestSize = (availableSize.width, bestInfo) } + if let tintColor = component.tintColor { + transition.setTintColor(layer: self.textView.layer, color: tintColor) + } + self.textView.frame = CGRect(origin: CGPoint(), size: bestSize.info.size) return bestSize.info.size } diff --git a/submodules/Components/MultilineTextComponent/Sources/MultilineTextComponent.swift b/submodules/Components/MultilineTextComponent/Sources/MultilineTextComponent.swift index cfcbaf9b85..11f08ffc52 100644 --- a/submodules/Components/MultilineTextComponent/Sources/MultilineTextComponent.swift +++ b/submodules/Components/MultilineTextComponent/Sources/MultilineTextComponent.swift @@ -18,6 +18,7 @@ public final class MultilineTextComponent: Component { public let lineSpacing: CGFloat public let cutout: TextNodeCutout? public let insets: UIEdgeInsets + public let tintColor: UIColor? public let textShadowColor: UIColor? public let textShadowBlur: CGFloat? public let textStroke: (UIColor, CGFloat)? @@ -36,6 +37,7 @@ public final class MultilineTextComponent: Component { lineSpacing: CGFloat = 0.0, cutout: TextNodeCutout? = nil, insets: UIEdgeInsets = UIEdgeInsets(), + tintColor: UIColor? = nil, textShadowColor: UIColor? = nil, textShadowBlur: CGFloat? = nil, textStroke: (UIColor, CGFloat)? = nil, @@ -53,6 +55,7 @@ public final class MultilineTextComponent: Component { self.lineSpacing = lineSpacing self.cutout = cutout self.insets = insets + self.tintColor = tintColor self.textShadowColor = textShadowColor self.textShadowBlur = textShadowBlur self.textStroke = textStroke @@ -88,7 +91,9 @@ public final class MultilineTextComponent: Component { if lhs.insets != rhs.insets { return false } - + if lhs.tintColor != rhs.tintColor { + return false + } if let lhsTextShadowColor = lhs.textShadowColor, let rhsTextShadowColor = rhs.textShadowColor { if !lhsTextShadowColor.isEqual(rhsTextShadowColor) { return false @@ -169,6 +174,12 @@ public final class MultilineTextComponent: Component { let size = self.updateLayout(availableSize) + if let tintColor = component.tintColor { + transition.setTintColor(layer: self.layer, color: tintColor) + } else { + self.layer.layerTintColor = nil + } + return size } } diff --git a/submodules/ContextUI/Sources/ContextController.swift b/submodules/ContextUI/Sources/ContextController.swift index 06082cb5c4..a1344158eb 100644 --- a/submodules/ContextUI/Sources/ContextController.swift +++ b/submodules/ContextUI/Sources/ContextController.swift @@ -2213,6 +2213,7 @@ public protocol ContextExtractedContentSource: AnyObject { var keepDefaultContentTouches: Bool { get } var blurBackground: Bool { get } var shouldBeDismissed: Signal { get } + var additionalInsets: UIEdgeInsets { get } var actionsHorizontalAlignment: ContextActionsHorizontalAlignment { get } @@ -2237,6 +2238,10 @@ public extension ContextExtractedContentSource { return false } + var additionalInsets: UIEdgeInsets { + return .zero + } + var actionsHorizontalAlignment: ContextActionsHorizontalAlignment { return .default } diff --git a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift index 3c1bfa50b9..e4bb7bc615 100644 --- a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift @@ -586,7 +586,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo let actionsEdgeInset: CGFloat let actionsSideInset: CGFloat let topInset: CGFloat = layout.insets(options: .statusBar).top + 8.0 - let bottomInset: CGFloat = 10.0 + var bottomInset: CGFloat = 10.0 let itemContentNode: ItemContentNode? let controllerContentNode: ControllerContentNode? @@ -903,6 +903,7 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo case let .extracted(source): keepInPlace = source.keepInPlace actionsHorizontalAlignment = source.actionsHorizontalAlignment + bottomInset += source.additionalInsets.bottom case .controller: //TODO: keepInPlace = false diff --git a/submodules/Display/Source/ListView.swift b/submodules/Display/Source/ListView.swift index a4f94b2dd6..1b84649a91 100644 --- a/submodules/Display/Source/ListView.swift +++ b/submodules/Display/Source/ListView.swift @@ -352,6 +352,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel private var currentGeneralScrollDirection: GeneralScrollDirection? public final var generalScrollDirectionUpdated: (GeneralScrollDirection) -> Void = { _ in } + public var autoScrollWhenReordering = true public private(set) var isReordering = false public final var willBeginReorder: (CGPoint) -> Void = { _ in } public final var reorderBegan: () -> Void = { } @@ -668,6 +669,12 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel private func updateReordering(offset: CGFloat) { if let reorderNode = self.reorderNode { + if !self.autoScrollWhenReordering, case let .known(contentOffset) = self.visibleContentOffset() { + let updatedLocation = reorderNode.initialLocation.y + offset + if updatedLocation < self.insets.top - contentOffset { + return + } + } reorderNode.updateOffset(offset: offset) self.checkItemReordering() } @@ -1520,10 +1527,14 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel topItemFound = true } + if !topItemFound, self.stackFromBottom && !self.autoScrollWhenReordering, let itemNode = self.itemNodes.first, itemNode.apparentFrame.minY > 0.0 { + topItemFound = true + } + var topOffset: CGFloat if topItemFound { - let realTopItemEdge = itemNodes.first!.apparentFrame.origin.y + let realTopItemEdge = self.itemNodes.first!.apparentFrame.origin.y let realTopItemEdgeOffset = max(0.0, realTopItemEdge) topOffset = realTopItemEdgeOffset @@ -4662,7 +4673,7 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel var offsetRanges = OffsetRanges() var scrollingForReorder = false - if let reorderOffset = self.reorderNode?.currentOffset(), !self.itemNodes.isEmpty { + if self.autoScrollWhenReordering, let reorderOffset = self.reorderNode?.currentOffset(), !self.itemNodes.isEmpty { let effectiveInsets = self.visualInsets ?? self.insets var offset: CGFloat = 6.0 diff --git a/submodules/Display/Source/ListViewIntermediateState.swift b/submodules/Display/Source/ListViewIntermediateState.swift index e80b3c1185..c9ce73bb62 100644 --- a/submodules/Display/Source/ListViewIntermediateState.swift +++ b/submodules/Display/Source/ListViewIntermediateState.swift @@ -818,7 +818,7 @@ struct ListViewState { } operations.append(.Remove(index: index, offsetDirection: offsetDirection)) - if let referenceNode = referenceNode , animated { + if let referenceNode = referenceNode, animated { self.nodes.insert(.Placeholder(frame: nodeFrame), at: index) operations.append(.InsertDisappearingPlaceholder(index: index, referenceNode: referenceNode, offsetDirection: offsetDirection.inverted())) } else { diff --git a/submodules/Display/Source/ListViewReorderingItemNode.swift b/submodules/Display/Source/ListViewReorderingItemNode.swift index b1dd58b192..4cbd14fdd1 100644 --- a/submodules/Display/Source/ListViewReorderingItemNode.swift +++ b/submodules/Display/Source/ListViewReorderingItemNode.swift @@ -51,7 +51,7 @@ final class ListViewReorderingItemNode: ASDisplayNode { var currentState: (Int, Int)? private let copyView: CopyView - private let initialLocation: CGPoint + let initialLocation: CGPoint init(itemNode: ListViewItemNode, initialLocation: CGPoint, hasShadow: Bool) { self.itemNode = itemNode diff --git a/submodules/Display/Source/TextAlertController.swift b/submodules/Display/Source/TextAlertController.swift index 291446f04b..2224e1a4d0 100644 --- a/submodules/Display/Source/TextAlertController.swift +++ b/submodules/Display/Source/TextAlertController.swift @@ -463,8 +463,8 @@ public final class TextAlertContentNode: AlertContentNode { } } -public func textAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, dismissOnOutsideTap: Bool = true) -> AlertController { - return AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap)) +public func textAlertController(theme: AlertControllerTheme, title: NSAttributedString?, text: NSAttributedString, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, dismissOnOutsideTap: Bool = true, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil) -> AlertController { + return AlertController(theme: theme, contentNode: TextAlertContentNode(theme: theme, title: title, text: text, actions: actions, actionLayout: actionLayout, dismissOnOutsideTap: dismissOnOutsideTap, linkAction: linkAction)) } public func standardTextAlertController(theme: AlertControllerTheme, title: String?, text: String, actions: [TextAlertAction], actionLayout: TextAlertContentActionLayout = .horizontal, allowInputInset: Bool = true, parseMarkdown: Bool = false, dismissOnOutsideTap: Bool = true, linkAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil) -> AlertController { diff --git a/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift b/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift index 5c7fb53fd9..a9e00836eb 100644 --- a/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift +++ b/submodules/FileMediaResourceStatus/Sources/FileMediaResourceStatus.swift @@ -5,12 +5,12 @@ import SwiftSignalKit import UniversalMediaPlayer import AccountContext -private func internalMessageFileMediaPlaybackStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool) -> Signal { +private func internalMessageFileMediaPlaybackStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool, isSavedMusic: Bool) -> Signal { guard let playerType = peerMessageMediaPlayerType(message) else { return .single(nil) } - if let (playlistId, itemId) = peerMessagesMediaPlaylistAndItemId(message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList) { + if let (playlistId, itemId) = peerMessagesMediaPlaylistAndItemId(message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList, isSavedMusic: isSavedMusic) { return context.sharedContext.mediaManager.filteredPlaylistState(accountId: context.account.id, playlistId: playlistId, itemId: itemId, type: playerType) |> mapToSignal { state -> Signal in return .single(state?.status) @@ -20,32 +20,32 @@ private func internalMessageFileMediaPlaybackStatus(context: AccountContext, fil } } -public func messageFileMediaPlaybackStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool) -> Signal { +public func messageFileMediaPlaybackStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool, isSavedMusic: Bool) -> Signal { var duration = 0.0 if let value = file.duration { duration = Double(value) } let defaultStatus = MediaPlayerStatus(generationTimestamp: 0.0, duration: duration, dimensions: CGSize(), timestamp: 0.0, baseRate: 1.0, seekId: 0, status: .paused, soundEnabled: true) - return internalMessageFileMediaPlaybackStatus(context: context, file: file, message: message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList) + return internalMessageFileMediaPlaybackStatus(context: context, file: file, message: message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList, isSavedMusic: isSavedMusic) |> map { status in return status ?? defaultStatus } } -public func messageFileMediaPlaybackAudioLevelEvents(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool) -> Signal { +public func messageFileMediaPlaybackAudioLevelEvents(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isGlobalSearch: Bool, isDownloadList: Bool, isSavedMusic: Bool) -> Signal { guard let playerType = peerMessageMediaPlayerType(message) else { return .never() } - if let (playlistId, itemId) = peerMessagesMediaPlaylistAndItemId(message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList) { + if let (playlistId, itemId) = peerMessagesMediaPlaylistAndItemId(message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList, isSavedMusic: isSavedMusic) { return context.sharedContext.mediaManager.filteredPlayerAudioLevelEvents(accountId: context.account.id, playlistId: playlistId, itemId: itemId, type: playerType) } else { return .never() } } -public func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isSharedMedia: Bool = false, isGlobalSearch: Bool = false, isDownloadList: Bool = false) -> Signal { - let playbackStatus = internalMessageFileMediaPlaybackStatus(context: context, file: file, message: message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList) |> map { status -> MediaPlayerPlaybackStatus? in +public func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMediaFile, message: EngineMessage, isRecentActions: Bool, isSharedMedia: Bool = false, isGlobalSearch: Bool = false, isDownloadList: Bool = false, isSavedMusic: Bool = false) -> Signal { + let playbackStatus = internalMessageFileMediaPlaybackStatus(context: context, file: file, message: message, isRecentActions: isRecentActions, isGlobalSearch: isGlobalSearch, isDownloadList: isDownloadList, isSavedMusic: isSavedMusic) |> map { status -> MediaPlayerPlaybackStatus? in return status?.status } diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index fe3759663f..be9aee83dc 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -684,7 +684,7 @@ private final class PendingInAppPurchaseState: Codable { case gift(peerId: EnginePeer.Id) case giftCode(peerIds: [EnginePeer.Id], boostPeer: EnginePeer.Id?, text: String?, entities: [MessageTextEntity]?) case giveaway(boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32) - case stars(count: Int64) + case stars(count: Int64, peerId: EnginePeer.Id?) case starsGift(peerId: EnginePeer.Id, count: Int64) case starsGiveaway(stars: Int64, boostPeer: EnginePeer.Id, additionalPeerIds: [EnginePeer.Id], countries: [String], onlyNewSubscribers: Bool, showWinners: Bool, prizeDescription: String?, randomId: Int64, untilDate: Int32, users: Int32) case authCode(restore: Bool, phoneNumber: String, phoneCodeHash: String) @@ -724,7 +724,8 @@ private final class PendingInAppPurchaseState: Codable { ) case .stars: self = .stars( - count: try container.decode(Int64.self, forKey: .stars) + count: try container.decode(Int64.self, forKey: .stars), + peerId: try container.decodeIfPresent(Int64.self, forKey: .peer).flatMap { EnginePeer.Id($0) } ) case .starsGift: self = .starsGift( @@ -784,9 +785,10 @@ private final class PendingInAppPurchaseState: Codable { try container.encodeIfPresent(prizeDescription, forKey: .prizeDescription) try container.encode(randomId, forKey: .randomId) try container.encode(untilDate, forKey: .untilDate) - case let .stars(count): + case let .stars(count, peerId): try container.encode(PurposeType.stars.rawValue, forKey: .type) try container.encode(count, forKey: .stars) + try container.encodeIfPresent(peerId?.toInt64(), forKey: .peer) case let .starsGift(peerId, count): try container.encode(PurposeType.starsGift.rawValue, forKey: .type) try container.encode(peerId.toInt64(), forKey: .peer) @@ -825,8 +827,8 @@ private final class PendingInAppPurchaseState: Codable { self = .giftCode(peerIds: peerIds, boostPeer: boostPeer, text: text, entities: entities) case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, _, _): self = .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate) - case let .stars(count, _, _): - self = .stars(count: count) + case let .stars(count, _, _, peerId): + self = .stars(count: count, peerId: peerId) case let .starsGift(peerId, count, _, _): self = .starsGift(peerId: peerId, count: count) case let .starsGiveaway(stars, boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, _, _, users): @@ -851,8 +853,8 @@ private final class PendingInAppPurchaseState: Codable { return .giftCode(peerIds: peerIds, boostPeer: boostPeer, currency: currency, amount: amount, text: text, entities: entities) case let .giveaway(boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate): return .giveaway(boostPeer: boostPeer, additionalPeerIds: additionalPeerIds, countries: countries, onlyNewSubscribers: onlyNewSubscribers, showWinners: showWinners, prizeDescription: prizeDescription, randomId: randomId, untilDate: untilDate, currency: currency, amount: amount) - case let .stars(count): - return .stars(count: count, currency: currency, amount: amount) + case let .stars(count, peerId): + return .stars(count: count, currency: currency, amount: amount, peerId: peerId) case let .starsGift(peerId, count): return .starsGift(peerId: peerId, count: count, currency: currency, amount: amount) case let .starsGiveaway(stars, boostPeer, additionalPeerIds, countries, onlyNewSubscribers, showWinners, prizeDescription, randomId, untilDate, users): diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index b1e68a51c4..0de2906f25 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -907,7 +907,7 @@ public final class ListMessageFileItemNode: ListMessageNode { if statusUpdated && item.displayFileInfo { if let file = selectedMedia as? TelegramMediaFile { - updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: file, message: EngineMessage(message), isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult || message.id.namespace == Namespaces.Message.Local, isDownloadList: item.isDownloadList) + updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: file, message: EngineMessage(message), isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult, isDownloadList: item.isDownloadList, isSavedMusic: item.isSavedMusic) |> mapToSignal { value -> Signal in if case .Fetching = value.fetchStatus, !item.isDownloadList { return .single(value) |> delay(0.1, queue: Queue.concurrentDefaultQueue()) @@ -934,7 +934,7 @@ public final class ListMessageFileItemNode: ListMessageNode { } } if isVoice { - updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: item.context, file: file, message: EngineMessage(message), isRecentActions: false, isGlobalSearch: item.isGlobalSearchResult, isDownloadList: item.isDownloadList) + updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: item.context, file: file, message: EngineMessage(message), isRecentActions: false, isGlobalSearch: item.isGlobalSearchResult, isDownloadList: item.isDownloadList, isSavedMusic: false) } } else if let image = selectedMedia as? TelegramMediaImage { updatedStatusSignal = messageImageMediaResourceStatus(context: item.context, image: image, message: EngineMessage(message), isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult || item.isDownloadList) diff --git a/submodules/ListMessageItem/Sources/ListMessageItem.swift b/submodules/ListMessageItem/Sources/ListMessageItem.swift index 57e6d972ba..5968f972ed 100644 --- a/submodules/ListMessageItem/Sources/ListMessageItem.swift +++ b/submodules/ListMessageItem/Sources/ListMessageItem.swift @@ -55,6 +55,7 @@ public final class ListMessageItem: ListViewItem { let hintIsLink: Bool let isGlobalSearchResult: Bool let isDownloadList: Bool + let isSavedMusic: Bool let displayFileInfo: Bool let displayBackground: Bool let canReorder: Bool @@ -64,7 +65,7 @@ public final class ListMessageItem: ListViewItem { public let selectable: Bool = true - public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message?, translateToLanguage: String? = nil, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, hintIsLink: Bool = false, isGlobalSearchResult: Bool = false, isDownloadList: Bool = false, displayFileInfo: Bool = true, displayBackground: Bool = false, canReorder: Bool = false, style: ItemListStyle = .plain) { + public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message?, translateToLanguage: String? = nil, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, hintIsLink: Bool = false, isGlobalSearchResult: Bool = false, isDownloadList: Bool = false, isSavedMusic: Bool = false, displayFileInfo: Bool = true, displayBackground: Bool = false, canReorder: Bool = false, style: ItemListStyle = .plain) { self.presentationData = presentationData self.context = context self.chatLocation = chatLocation @@ -82,6 +83,7 @@ public final class ListMessageItem: ListViewItem { self.hintIsLink = hintIsLink self.isGlobalSearchResult = isGlobalSearchResult self.isDownloadList = isDownloadList + self.isSavedMusic = isSavedMusic self.displayFileInfo = displayFileInfo self.displayBackground = displayBackground self.canReorder = canReorder diff --git a/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift b/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift index 1e379d80e4..824b909963 100644 --- a/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift +++ b/submodules/MediaPlayer/Sources/MediaPlayerTimeTextNode.swift @@ -193,7 +193,7 @@ public final class MediaPlayerTimeTextNode: ASDisplayNode { self.state = MediaPlayerTimeTextNodeState(hours: timestamp / (60 * 60), minutes: timestamp % (60 * 60) / 60, seconds: timestamp % 60) } else { let timestampSeconds: Double - if !statusValue.generationTimestamp.isZero { + if !statusValue.generationTimestamp.isZero && isPlaying { timestampSeconds = timestamp + (CACurrentMediaTime() - statusValue.generationTimestamp) } else { timestampSeconds = timestamp diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index e458dc3881..87b3433037 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -221,6 +221,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1385335754] = { return Api.ChatReactions.parse_chatReactionsAll($0) } dict[-352570692] = { return Api.ChatReactions.parse_chatReactionsNone($0) } dict[1713193015] = { return Api.ChatReactions.parse_chatReactionsSome($0) } + dict[-1008731132] = { return Api.ChatTheme.parse_chatTheme($0) } + dict[388142507] = { return Api.ChatTheme.parse_chatThemeUniqueGift($0) } dict[-1390068360] = { return Api.CodeSettings.parse_codeSettings($0) } dict[-870702050] = { return Api.Config.parse_config($0) } dict[-849058964] = { return Api.ConnectedBot.parse_connectedBot($0) } @@ -344,6 +346,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1991004873] = { return Api.InputChatPhoto.parse_inputChatPhoto($0) } dict[480546647] = { return Api.InputChatPhoto.parse_inputChatPhotoEmpty($0) } dict[-1110593856] = { return Api.InputChatPhoto.parse_inputChatUploadedPhoto($0) } + dict[-918689444] = { return Api.InputChatTheme.parse_inputChatTheme($0) } + dict[-2094627709] = { return Api.InputChatTheme.parse_inputChatThemeEmpty($0) } + dict[-2014978076] = { return Api.InputChatTheme.parse_inputChatThemeUniqueGift($0) } dict[-203367885] = { return Api.InputChatlist.parse_inputChatlistDialogFilter($0) } dict[-1736378792] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordEmpty($0) } dict[-763367294] = { return Api.InputCheckPasswordSRP.parse_inputCheckPasswordSRP($0) } @@ -600,7 +605,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1200788123] = { return Api.MessageAction.parse_messageActionScreenshotTaken($0) } dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) } dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) } - dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) } + dict[-1189364422] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) } dict[1348510708] = { return Api.MessageAction.parse_messageActionSetChatWallPaper($0) } dict[1007897979] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) } dict[-229775366] = { return Api.MessageAction.parse_messageActionStarGift($0) } @@ -1191,7 +1196,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1831650802] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) } dict[34280482] = { return Api.User.parse_user($0) } dict[-742634630] = { return Api.User.parse_userEmpty($0) } - dict[-962665488] = { return Api.UserFull.parse_userFull($0) } + dict[-156655069] = { return Api.UserFull.parse_userFull($0) } dict[-2100168954] = { return Api.UserProfilePhoto.parse_userProfilePhoto($0) } dict[1326562017] = { return Api.UserProfilePhoto.parse_userProfilePhotoEmpty($0) } dict[164646985] = { return Api.UserStatus.parse_userStatusEmpty($0) } @@ -1226,6 +1231,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1674235686] = { return Api.account.AutoDownloadSettings.parse_autoDownloadSettings($0) } dict[1279133341] = { return Api.account.AutoSaveSettings.parse_autoSaveSettings($0) } dict[-331111727] = { return Api.account.BusinessChatLinks.parse_businessChatLinks($0) } + dict[1271855483] = { return Api.account.ChatThemes.parse_chatThemes($0) } + dict[-535699004] = { return Api.account.ChatThemes.parse_chatThemesNotModified($0) } dict[400029819] = { return Api.account.ConnectedBots.parse_connectedBots($0) } dict[1474462241] = { return Api.account.ContentSettings.parse_contentSettings($0) } dict[731303195] = { return Api.account.EmailVerified.parse_emailVerified($0) } @@ -1269,7 +1276,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[957176926] = { return Api.auth.LoginToken.parse_loginTokenSuccess($0) } dict[326715557] = { return Api.auth.PasswordRecovery.parse_passwordRecovery($0) } dict[1577067778] = { return Api.auth.SentCode.parse_sentCode($0) } - dict[-674301568] = { return Api.auth.SentCode.parse_sentCodePaymentRequired($0) } + dict[-677184263] = { return Api.auth.SentCode.parse_sentCodePaymentRequired($0) } dict[596704836] = { return Api.auth.SentCode.parse_sentCodeSuccess($0) } dict[1035688326] = { return Api.auth.SentCodeType.parse_sentCodeTypeApp($0) } dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) } @@ -1706,6 +1713,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.ChatReactions: _1.serialize(buffer, boxed) + case let _1 as Api.ChatTheme: + _1.serialize(buffer, boxed) case let _1 as Api.CodeSettings: _1.serialize(buffer, boxed) case let _1 as Api.Config: @@ -1842,6 +1851,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.InputChatPhoto: _1.serialize(buffer, boxed) + case let _1 as Api.InputChatTheme: + _1.serialize(buffer, boxed) case let _1 as Api.InputChatlist: _1.serialize(buffer, boxed) case let _1 as Api.InputCheckPasswordSRP: @@ -2300,6 +2311,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.account.BusinessChatLinks: _1.serialize(buffer, boxed) + case let _1 as Api.account.ChatThemes: + _1.serialize(buffer, boxed) case let _1 as Api.account.ConnectedBots: _1.serialize(buffer, boxed) case let _1 as Api.account.ContentSettings: diff --git a/submodules/TelegramApi/Sources/Api15.swift b/submodules/TelegramApi/Sources/Api15.swift index 99fb5aacd4..ca9922c304 100644 --- a/submodules/TelegramApi/Sources/Api15.swift +++ b/submodules/TelegramApi/Sources/Api15.swift @@ -390,7 +390,7 @@ public extension Api { case messageActionScreenshotTaken case messageActionSecureValuesSent(types: [Api.SecureValueType]) case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) - case messageActionSetChatTheme(emoticon: String) + case messageActionSetChatTheme(theme: Api.ChatTheme) case messageActionSetChatWallPaper(flags: Int32, wallpaper: Api.WallPaper) case messageActionSetMessagesTTL(flags: Int32, period: Int32, autoSettingFrom: Int64?) case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64?, upgradeMsgId: Int32?, upgradeStars: Int64?, fromId: Api.Peer?, peer: Api.Peer?, savedId: Int64?, prepaidUpgradeHash: String?, giftMsgId: Int32?) @@ -762,11 +762,11 @@ public extension Api { } credentials.serialize(buffer, true) break - case .messageActionSetChatTheme(let emoticon): + case .messageActionSetChatTheme(let theme): if boxed { - buffer.appendInt32(-1434950843) + buffer.appendInt32(-1189364422) } - serializeString(emoticon, buffer: buffer, boxed: false) + theme.serialize(buffer, true) break case .messageActionSetChatWallPaper(let flags, let wallpaper): if boxed { @@ -987,8 +987,8 @@ public extension Api { return ("messageActionSecureValuesSent", [("types", types as Any)]) case .messageActionSecureValuesSentMe(let values, let credentials): return ("messageActionSecureValuesSentMe", [("values", values as Any), ("credentials", credentials as Any)]) - case .messageActionSetChatTheme(let emoticon): - return ("messageActionSetChatTheme", [("emoticon", emoticon as Any)]) + case .messageActionSetChatTheme(let theme): + return ("messageActionSetChatTheme", [("theme", theme as Any)]) case .messageActionSetChatWallPaper(let flags, let wallpaper): return ("messageActionSetChatWallPaper", [("flags", flags as Any), ("wallpaper", wallpaper as Any)]) case .messageActionSetMessagesTTL(let flags, let period, let autoSettingFrom): @@ -1687,11 +1687,13 @@ public extension Api { } } public static func parse_messageActionSetChatTheme(_ reader: BufferReader) -> MessageAction? { - var _1: String? - _1 = parseString(reader) + var _1: Api.ChatTheme? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.ChatTheme + } let _c1 = _1 != nil if _c1 { - return Api.MessageAction.messageActionSetChatTheme(emoticon: _1!) + return Api.MessageAction.messageActionSetChatTheme(theme: _1!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api28.swift b/submodules/TelegramApi/Sources/Api28.swift index 0dc8b22b20..6b0cd777c4 100644 --- a/submodules/TelegramApi/Sources/Api28.swift +++ b/submodules/TelegramApi/Sources/Api28.swift @@ -614,13 +614,13 @@ public extension Api { } public extension Api { enum UserFull: TypeConstructorDescription { - case userFull(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, themeEmoticon: String?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?, starsRating: Api.StarsRating?, starsMyPendingRating: Api.StarsRating?, starsMyPendingRatingDate: Int32?, linkedBotforumChannelId: Int64?, mainTab: Api.ProfileTab?, savedMusic: Api.Document?) + case userFull(flags: Int32, flags2: Int32, id: Int64, about: String?, settings: Api.PeerSettings, personalPhoto: Api.Photo?, profilePhoto: Api.Photo?, fallbackPhoto: Api.Photo?, notifySettings: Api.PeerNotifySettings, botInfo: Api.BotInfo?, pinnedMsgId: Int32?, commonChatsCount: Int32, folderId: Int32?, ttlPeriod: Int32?, theme: Api.ChatTheme?, privateForwardName: String?, botGroupAdminRights: Api.ChatAdminRights?, botBroadcastAdminRights: Api.ChatAdminRights?, wallpaper: Api.WallPaper?, stories: Api.PeerStories?, businessWorkHours: Api.BusinessWorkHours?, businessLocation: Api.BusinessLocation?, businessGreetingMessage: Api.BusinessGreetingMessage?, businessAwayMessage: Api.BusinessAwayMessage?, businessIntro: Api.BusinessIntro?, birthday: Api.Birthday?, personalChannelId: Int64?, personalChannelMessage: Int32?, stargiftsCount: Int32?, starrefProgram: Api.StarRefProgram?, botVerification: Api.BotVerification?, sendPaidMessagesStars: Int64?, disallowedGifts: Api.DisallowedGiftsSettings?, starsRating: Api.StarsRating?, starsMyPendingRating: Api.StarsRating?, starsMyPendingRatingDate: Int32?, linkedBotforumChannelId: Int64?, mainTab: Api.ProfileTab?, savedMusic: Api.Document?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts, let starsRating, let starsMyPendingRating, let starsMyPendingRatingDate, let linkedBotforumChannelId, let mainTab, let savedMusic): + case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let theme, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts, let starsRating, let starsMyPendingRating, let starsMyPendingRatingDate, let linkedBotforumChannelId, let mainTab, let savedMusic): if boxed { - buffer.appendInt32(-962665488) + buffer.appendInt32(-156655069) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags2, buffer: buffer, boxed: false) @@ -636,7 +636,7 @@ public extension Api { serializeInt32(commonChatsCount, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 11) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 14) != 0 {serializeInt32(ttlPeriod!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 15) != 0 {serializeString(themeEmoticon!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 15) != 0 {theme!.serialize(buffer, true)} if Int(flags) & Int(1 << 16) != 0 {serializeString(privateForwardName!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 17) != 0 {botGroupAdminRights!.serialize(buffer, true)} if Int(flags) & Int(1 << 18) != 0 {botBroadcastAdminRights!.serialize(buffer, true)} @@ -667,8 +667,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let themeEmoticon, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts, let starsRating, let starsMyPendingRating, let starsMyPendingRatingDate, let linkedBotforumChannelId, let mainTab, let savedMusic): - return ("userFull", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("themeEmoticon", themeEmoticon as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any), ("businessWorkHours", businessWorkHours as Any), ("businessLocation", businessLocation as Any), ("businessGreetingMessage", businessGreetingMessage as Any), ("businessAwayMessage", businessAwayMessage as Any), ("businessIntro", businessIntro as Any), ("birthday", birthday as Any), ("personalChannelId", personalChannelId as Any), ("personalChannelMessage", personalChannelMessage as Any), ("stargiftsCount", stargiftsCount as Any), ("starrefProgram", starrefProgram as Any), ("botVerification", botVerification as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("disallowedGifts", disallowedGifts as Any), ("starsRating", starsRating as Any), ("starsMyPendingRating", starsMyPendingRating as Any), ("starsMyPendingRatingDate", starsMyPendingRatingDate as Any), ("linkedBotforumChannelId", linkedBotforumChannelId as Any), ("mainTab", mainTab as Any), ("savedMusic", savedMusic as Any)]) + case .userFull(let flags, let flags2, let id, let about, let settings, let personalPhoto, let profilePhoto, let fallbackPhoto, let notifySettings, let botInfo, let pinnedMsgId, let commonChatsCount, let folderId, let ttlPeriod, let theme, let privateForwardName, let botGroupAdminRights, let botBroadcastAdminRights, let wallpaper, let stories, let businessWorkHours, let businessLocation, let businessGreetingMessage, let businessAwayMessage, let businessIntro, let birthday, let personalChannelId, let personalChannelMessage, let stargiftsCount, let starrefProgram, let botVerification, let sendPaidMessagesStars, let disallowedGifts, let starsRating, let starsMyPendingRating, let starsMyPendingRatingDate, let linkedBotforumChannelId, let mainTab, let savedMusic): + return ("userFull", [("flags", flags as Any), ("flags2", flags2 as Any), ("id", id as Any), ("about", about as Any), ("settings", settings as Any), ("personalPhoto", personalPhoto as Any), ("profilePhoto", profilePhoto as Any), ("fallbackPhoto", fallbackPhoto as Any), ("notifySettings", notifySettings as Any), ("botInfo", botInfo as Any), ("pinnedMsgId", pinnedMsgId as Any), ("commonChatsCount", commonChatsCount as Any), ("folderId", folderId as Any), ("ttlPeriod", ttlPeriod as Any), ("theme", theme as Any), ("privateForwardName", privateForwardName as Any), ("botGroupAdminRights", botGroupAdminRights as Any), ("botBroadcastAdminRights", botBroadcastAdminRights as Any), ("wallpaper", wallpaper as Any), ("stories", stories as Any), ("businessWorkHours", businessWorkHours as Any), ("businessLocation", businessLocation as Any), ("businessGreetingMessage", businessGreetingMessage as Any), ("businessAwayMessage", businessAwayMessage as Any), ("businessIntro", businessIntro as Any), ("birthday", birthday as Any), ("personalChannelId", personalChannelId as Any), ("personalChannelMessage", personalChannelMessage as Any), ("stargiftsCount", stargiftsCount as Any), ("starrefProgram", starrefProgram as Any), ("botVerification", botVerification as Any), ("sendPaidMessagesStars", sendPaidMessagesStars as Any), ("disallowedGifts", disallowedGifts as Any), ("starsRating", starsRating as Any), ("starsMyPendingRating", starsMyPendingRating as Any), ("starsMyPendingRatingDate", starsMyPendingRatingDate as Any), ("linkedBotforumChannelId", linkedBotforumChannelId as Any), ("mainTab", mainTab as Any), ("savedMusic", savedMusic as Any)]) } } @@ -713,8 +713,10 @@ public extension Api { if Int(_1!) & Int(1 << 11) != 0 {_13 = reader.readInt32() } var _14: Int32? if Int(_1!) & Int(1 << 14) != 0 {_14 = reader.readInt32() } - var _15: String? - if Int(_1!) & Int(1 << 15) != 0 {_15 = parseString(reader) } + var _15: Api.ChatTheme? + if Int(_1!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() { + _15 = Api.parse(reader, signature: signature) as? Api.ChatTheme + } } var _16: String? if Int(_1!) & Int(1 << 16) != 0 {_16 = parseString(reader) } var _17: Api.ChatAdminRights? @@ -837,7 +839,7 @@ public extension Api { let _c38 = (Int(_2!) & Int(1 << 20) == 0) || _38 != nil let _c39 = (Int(_2!) & Int(1 << 21) == 0) || _39 != nil if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 && _c18 && _c19 && _c20 && _c21 && _c22 && _c23 && _c24 && _c25 && _c26 && _c27 && _c28 && _c29 && _c30 && _c31 && _c32 && _c33 && _c34 && _c35 && _c36 && _c37 && _c38 && _c39 { - return Api.UserFull.userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, themeEmoticon: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedGifts: _33, starsRating: _34, starsMyPendingRating: _35, starsMyPendingRatingDate: _36, linkedBotforumChannelId: _37, mainTab: _38, savedMusic: _39) + return Api.UserFull.userFull(flags: _1!, flags2: _2!, id: _3!, about: _4, settings: _5!, personalPhoto: _6, profilePhoto: _7, fallbackPhoto: _8, notifySettings: _9!, botInfo: _10, pinnedMsgId: _11, commonChatsCount: _12!, folderId: _13, ttlPeriod: _14, theme: _15, privateForwardName: _16, botGroupAdminRights: _17, botBroadcastAdminRights: _18, wallpaper: _19, stories: _20, businessWorkHours: _21, businessLocation: _22, businessGreetingMessage: _23, businessAwayMessage: _24, businessIntro: _25, birthday: _26, personalChannelId: _27, personalChannelMessage: _28, stargiftsCount: _29, starrefProgram: _30, botVerification: _31, sendPaidMessagesStars: _32, disallowedGifts: _33, starsRating: _34, starsMyPendingRating: _35, starsMyPendingRatingDate: _36, linkedBotforumChannelId: _37, mainTab: _38, savedMusic: _39) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api29.swift b/submodules/TelegramApi/Sources/Api29.swift index 78f5b40929..ee37df45c0 100644 --- a/submodules/TelegramApi/Sources/Api29.swift +++ b/submodules/TelegramApi/Sources/Api29.swift @@ -568,6 +568,72 @@ public extension Api.account { } } +public extension Api.account { + enum ChatThemes: TypeConstructorDescription { + case chatThemes(flags: Int32, hash: Int64, themes: [Api.ChatTheme], nextOffset: Int32?) + case chatThemesNotModified + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatThemes(let flags, let hash, let themes, let nextOffset): + if boxed { + buffer.appendInt32(1271855483) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(themes.count)) + for item in themes { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(nextOffset!, buffer: buffer, boxed: false)} + break + case .chatThemesNotModified: + if boxed { + buffer.appendInt32(-535699004) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatThemes(let flags, let hash, let themes, let nextOffset): + return ("chatThemes", [("flags", flags as Any), ("hash", hash as Any), ("themes", themes as Any), ("nextOffset", nextOffset as Any)]) + case .chatThemesNotModified: + return ("chatThemesNotModified", []) + } + } + + public static func parse_chatThemes(_ reader: BufferReader) -> ChatThemes? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: [Api.ChatTheme]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ChatTheme.self) + } + var _4: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_4 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.account.ChatThemes.chatThemes(flags: _1!, hash: _2!, themes: _3!, nextOffset: _4) + } + else { + return nil + } + } + public static func parse_chatThemesNotModified(_ reader: BufferReader) -> ChatThemes? { + return Api.account.ChatThemes.chatThemesNotModified + } + + } +} public extension Api.account { enum ConnectedBots: TypeConstructorDescription { case connectedBots(connectedBots: [Api.ConnectedBot], users: [Api.User]) @@ -1310,61 +1376,3 @@ public extension Api.account { } } -public extension Api.account { - enum SavedRingtones: TypeConstructorDescription { - case savedRingtones(hash: Int64, ringtones: [Api.Document]) - case savedRingtonesNotModified - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .savedRingtones(let hash, let ringtones): - if boxed { - buffer.appendInt32(-1041683259) - } - serializeInt64(hash, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(ringtones.count)) - for item in ringtones { - item.serialize(buffer, true) - } - break - case .savedRingtonesNotModified: - if boxed { - buffer.appendInt32(-67704655) - } - - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .savedRingtones(let hash, let ringtones): - return ("savedRingtones", [("hash", hash as Any), ("ringtones", ringtones as Any)]) - case .savedRingtonesNotModified: - return ("savedRingtonesNotModified", []) - } - } - - public static func parse_savedRingtones(_ reader: BufferReader) -> SavedRingtones? { - var _1: Int64? - _1 = reader.readInt64() - var _2: [Api.Document]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.account.SavedRingtones.savedRingtones(hash: _1!, ringtones: _2!) - } - else { - return nil - } - } - public static func parse_savedRingtonesNotModified(_ reader: BufferReader) -> SavedRingtones? { - return Api.account.SavedRingtones.savedRingtonesNotModified - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api30.swift b/submodules/TelegramApi/Sources/Api30.swift index 253d962784..cd4d6eb155 100644 --- a/submodules/TelegramApi/Sources/Api30.swift +++ b/submodules/TelegramApi/Sources/Api30.swift @@ -1,3 +1,61 @@ +public extension Api.account { + enum SavedRingtones: TypeConstructorDescription { + case savedRingtones(hash: Int64, ringtones: [Api.Document]) + case savedRingtonesNotModified + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .savedRingtones(let hash, let ringtones): + if boxed { + buffer.appendInt32(-1041683259) + } + serializeInt64(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(ringtones.count)) + for item in ringtones { + item.serialize(buffer, true) + } + break + case .savedRingtonesNotModified: + if boxed { + buffer.appendInt32(-67704655) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .savedRingtones(let hash, let ringtones): + return ("savedRingtones", [("hash", hash as Any), ("ringtones", ringtones as Any)]) + case .savedRingtonesNotModified: + return ("savedRingtonesNotModified", []) + } + } + + public static func parse_savedRingtones(_ reader: BufferReader) -> SavedRingtones? { + var _1: Int64? + _1 = reader.readInt64() + var _2: [Api.Document]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.account.SavedRingtones.savedRingtones(hash: _1!, ringtones: _2!) + } + else { + return nil + } + } + public static func parse_savedRingtonesNotModified(_ reader: BufferReader) -> SavedRingtones? { + return Api.account.SavedRingtones.savedRingtonesNotModified + } + + } +} public extension Api.account { enum SentEmailCode: TypeConstructorDescription { case sentEmailCode(emailPattern: String, length: Int32) @@ -643,7 +701,7 @@ public extension Api.auth { public extension Api.auth { enum SentCode: TypeConstructorDescription { case sentCode(flags: Int32, type: Api.auth.SentCodeType, phoneCodeHash: String, nextType: Api.auth.CodeType?, timeout: Int32?) - case sentCodePaymentRequired(storeProduct: String, phoneCodeHash: String) + case sentCodePaymentRequired(storeProduct: String, phoneCodeHash: String, supportEmailAddress: String, supportEmailSubject: String) case sentCodeSuccess(authorization: Api.auth.Authorization) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { @@ -658,12 +716,14 @@ public extension Api.auth { if Int(flags) & Int(1 << 1) != 0 {nextType!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {serializeInt32(timeout!, buffer: buffer, boxed: false)} break - case .sentCodePaymentRequired(let storeProduct, let phoneCodeHash): + case .sentCodePaymentRequired(let storeProduct, let phoneCodeHash, let supportEmailAddress, let supportEmailSubject): if boxed { - buffer.appendInt32(-674301568) + buffer.appendInt32(-677184263) } serializeString(storeProduct, buffer: buffer, boxed: false) serializeString(phoneCodeHash, buffer: buffer, boxed: false) + serializeString(supportEmailAddress, buffer: buffer, boxed: false) + serializeString(supportEmailSubject, buffer: buffer, boxed: false) break case .sentCodeSuccess(let authorization): if boxed { @@ -678,8 +738,8 @@ public extension Api.auth { switch self { case .sentCode(let flags, let type, let phoneCodeHash, let nextType, let timeout): return ("sentCode", [("flags", flags as Any), ("type", type as Any), ("phoneCodeHash", phoneCodeHash as Any), ("nextType", nextType as Any), ("timeout", timeout as Any)]) - case .sentCodePaymentRequired(let storeProduct, let phoneCodeHash): - return ("sentCodePaymentRequired", [("storeProduct", storeProduct as Any), ("phoneCodeHash", phoneCodeHash as Any)]) + case .sentCodePaymentRequired(let storeProduct, let phoneCodeHash, let supportEmailAddress, let supportEmailSubject): + return ("sentCodePaymentRequired", [("storeProduct", storeProduct as Any), ("phoneCodeHash", phoneCodeHash as Any), ("supportEmailAddress", supportEmailAddress as Any), ("supportEmailSubject", supportEmailSubject as Any)]) case .sentCodeSuccess(let authorization): return ("sentCodeSuccess", [("authorization", authorization as Any)]) } @@ -717,10 +777,16 @@ public extension Api.auth { _1 = parseString(reader) var _2: String? _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + _4 = parseString(reader) let _c1 = _1 != nil let _c2 = _2 != nil - if _c1 && _c2 { - return Api.auth.SentCode.sentCodePaymentRequired(storeProduct: _1!, phoneCodeHash: _2!) + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.auth.SentCode.sentCodePaymentRequired(storeProduct: _1!, phoneCodeHash: _2!, supportEmailAddress: _3!, supportEmailSubject: _4!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api39.swift b/submodules/TelegramApi/Sources/Api39.swift index c9bfe5f2df..c24ea8797e 100644 --- a/submodules/TelegramApi/Sources/Api39.swift +++ b/submodules/TelegramApi/Sources/Api39.swift @@ -838,6 +838,23 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func getUniqueGiftChatThemes(offset: Int32, limit: Int32, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-25890913) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getUniqueGiftChatThemes", parameters: [("offset", String(describing: offset)), ("limit", String(describing: limit)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.ChatThemes? in + let reader = BufferReader(buffer) + var result: Api.account.ChatThemes? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.ChatThemes + } + return result + }) + } +} public extension Api.functions.account { static func getWallPaper(wallpaper: Api.InputWallPaper) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -8664,12 +8681,12 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func setChatTheme(peer: Api.InputPeer, emoticon: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func setChatTheme(peer: Api.InputPeer, theme: Api.InputChatTheme) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-432283329) + buffer.appendInt32(135398089) peer.serialize(buffer, true) - serializeString(emoticon, buffer: buffer, boxed: false) - return (FunctionDescription(name: "messages.setChatTheme", parameters: [("peer", String(describing: peer)), ("emoticon", String(describing: emoticon))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + theme.serialize(buffer, true) + return (FunctionDescription(name: "messages.setChatTheme", parameters: [("peer", String(describing: peer)), ("theme", String(describing: theme))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { diff --git a/submodules/TelegramApi/Sources/Api5.swift b/submodules/TelegramApi/Sources/Api5.swift index 88cff55c26..6956a8c5f0 100644 --- a/submodules/TelegramApi/Sources/Api5.swift +++ b/submodules/TelegramApi/Sources/Api5.swift @@ -392,6 +392,70 @@ public extension Api { } } +public extension Api { + enum ChatTheme: TypeConstructorDescription { + case chatTheme(emoticon: String) + case chatThemeUniqueGift(gift: Api.StarGift, wallpaperDocument: Api.Document) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .chatTheme(let emoticon): + if boxed { + buffer.appendInt32(-1008731132) + } + serializeString(emoticon, buffer: buffer, boxed: false) + break + case .chatThemeUniqueGift(let gift, let wallpaperDocument): + if boxed { + buffer.appendInt32(388142507) + } + gift.serialize(buffer, true) + wallpaperDocument.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .chatTheme(let emoticon): + return ("chatTheme", [("emoticon", emoticon as Any)]) + case .chatThemeUniqueGift(let gift, let wallpaperDocument): + return ("chatThemeUniqueGift", [("gift", gift as Any), ("wallpaperDocument", wallpaperDocument as Any)]) + } + } + + public static func parse_chatTheme(_ reader: BufferReader) -> ChatTheme? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.ChatTheme.chatTheme(emoticon: _1!) + } + else { + return nil + } + } + public static func parse_chatThemeUniqueGift(_ reader: BufferReader) -> ChatTheme? { + var _1: Api.StarGift? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StarGift + } + var _2: Api.Document? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.Document + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ChatTheme.chatThemeUniqueGift(gift: _1!, wallpaperDocument: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum CodeSettings: TypeConstructorDescription { case codeSettings(flags: Int32, logoutTokens: [Buffer]?, token: String?, appSandbox: Api.Bool?) @@ -1424,153 +1488,3 @@ public extension Api { } } -public extension Api { - enum DisallowedGiftsSettings: TypeConstructorDescription { - case disallowedGiftsSettings(flags: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .disallowedGiftsSettings(let flags): - if boxed { - buffer.appendInt32(1911715524) - } - serializeInt32(flags, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .disallowedGiftsSettings(let flags): - return ("disallowedGiftsSettings", [("flags", flags as Any)]) - } - } - - public static func parse_disallowedGiftsSettings(_ reader: BufferReader) -> DisallowedGiftsSettings? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.DisallowedGiftsSettings.disallowedGiftsSettings(flags: _1!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum Document: TypeConstructorDescription { - case document(flags: Int32, id: Int64, accessHash: Int64, fileReference: Buffer, date: Int32, mimeType: String, size: Int64, thumbs: [Api.PhotoSize]?, videoThumbs: [Api.VideoSize]?, dcId: Int32, attributes: [Api.DocumentAttribute]) - case documentEmpty(id: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let videoThumbs, let dcId, let attributes): - if boxed { - buffer.appendInt32(-1881881384) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt64(id, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeBytes(fileReference, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeString(mimeType, buffer: buffer, boxed: false) - serializeInt64(size, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(thumbs!.count)) - for item in thumbs! { - item.serialize(buffer, true) - }} - if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(videoThumbs!.count)) - for item in videoThumbs! { - item.serialize(buffer, true) - }} - serializeInt32(dcId, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(attributes.count)) - for item in attributes { - item.serialize(buffer, true) - } - break - case .documentEmpty(let id): - if boxed { - buffer.appendInt32(922273905) - } - serializeInt64(id, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let videoThumbs, let dcId, let attributes): - return ("document", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("date", date as Any), ("mimeType", mimeType as Any), ("size", size as Any), ("thumbs", thumbs as Any), ("videoThumbs", videoThumbs as Any), ("dcId", dcId as Any), ("attributes", attributes as Any)]) - case .documentEmpty(let id): - return ("documentEmpty", [("id", id as Any)]) - } - } - - public static func parse_document(_ reader: BufferReader) -> Document? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: Int64? - _3 = reader.readInt64() - var _4: Buffer? - _4 = parseBytes(reader) - var _5: Int32? - _5 = reader.readInt32() - var _6: String? - _6 = parseString(reader) - var _7: Int64? - _7 = reader.readInt64() - var _8: [Api.PhotoSize]? - if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { - _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhotoSize.self) - } } - var _9: [Api.VideoSize]? - if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { - _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.VideoSize.self) - } } - var _10: Int32? - _10 = reader.readInt32() - var _11: [Api.DocumentAttribute]? - if let _ = reader.readInt32() { - _11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil - let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { - return Api.Document.document(flags: _1!, id: _2!, accessHash: _3!, fileReference: _4!, date: _5!, mimeType: _6!, size: _7!, thumbs: _8, videoThumbs: _9, dcId: _10!, attributes: _11!) - } - else { - return nil - } - } - public static func parse_documentEmpty(_ reader: BufferReader) -> Document? { - var _1: Int64? - _1 = reader.readInt64() - let _c1 = _1 != nil - if _c1 { - return Api.Document.documentEmpty(id: _1!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api6.swift b/submodules/TelegramApi/Sources/Api6.swift index c149e4cc89..ca7545a09a 100644 --- a/submodules/TelegramApi/Sources/Api6.swift +++ b/submodules/TelegramApi/Sources/Api6.swift @@ -1,3 +1,153 @@ +public extension Api { + enum DisallowedGiftsSettings: TypeConstructorDescription { + case disallowedGiftsSettings(flags: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .disallowedGiftsSettings(let flags): + if boxed { + buffer.appendInt32(1911715524) + } + serializeInt32(flags, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .disallowedGiftsSettings(let flags): + return ("disallowedGiftsSettings", [("flags", flags as Any)]) + } + } + + public static func parse_disallowedGiftsSettings(_ reader: BufferReader) -> DisallowedGiftsSettings? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.DisallowedGiftsSettings.disallowedGiftsSettings(flags: _1!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum Document: TypeConstructorDescription { + case document(flags: Int32, id: Int64, accessHash: Int64, fileReference: Buffer, date: Int32, mimeType: String, size: Int64, thumbs: [Api.PhotoSize]?, videoThumbs: [Api.VideoSize]?, dcId: Int32, attributes: [Api.DocumentAttribute]) + case documentEmpty(id: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let videoThumbs, let dcId, let attributes): + if boxed { + buffer.appendInt32(-1881881384) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeBytes(fileReference, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + serializeInt64(size, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(thumbs!.count)) + for item in thumbs! { + item.serialize(buffer, true) + }} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(videoThumbs!.count)) + for item in videoThumbs! { + item.serialize(buffer, true) + }} + serializeInt32(dcId, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(attributes.count)) + for item in attributes { + item.serialize(buffer, true) + } + break + case .documentEmpty(let id): + if boxed { + buffer.appendInt32(922273905) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .document(let flags, let id, let accessHash, let fileReference, let date, let mimeType, let size, let thumbs, let videoThumbs, let dcId, let attributes): + return ("document", [("flags", flags as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("fileReference", fileReference as Any), ("date", date as Any), ("mimeType", mimeType as Any), ("size", size as Any), ("thumbs", thumbs as Any), ("videoThumbs", videoThumbs as Any), ("dcId", dcId as Any), ("attributes", attributes as Any)]) + case .documentEmpty(let id): + return ("documentEmpty", [("id", id as Any)]) + } + } + + public static func parse_document(_ reader: BufferReader) -> Document? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int64? + _3 = reader.readInt64() + var _4: Buffer? + _4 = parseBytes(reader) + var _5: Int32? + _5 = reader.readInt32() + var _6: String? + _6 = parseString(reader) + var _7: Int64? + _7 = reader.readInt64() + var _8: [Api.PhotoSize]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PhotoSize.self) + } } + var _9: [Api.VideoSize]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.VideoSize.self) + } } + var _10: Int32? + _10 = reader.readInt32() + var _11: [Api.DocumentAttribute]? + if let _ = reader.readInt32() { + _11 = Api.parseVector(reader, elementSignature: 0, elementType: Api.DocumentAttribute.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = (Int(_1!) & Int(1 << 0) == 0) || _8 != nil + let _c9 = (Int(_1!) & Int(1 << 1) == 0) || _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 { + return Api.Document.document(flags: _1!, id: _2!, accessHash: _3!, fileReference: _4!, date: _5!, mimeType: _6!, size: _7!, thumbs: _8, videoThumbs: _9, dcId: _10!, attributes: _11!) + } + else { + return nil + } + } + public static func parse_documentEmpty(_ reader: BufferReader) -> Document? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.Document.documentEmpty(id: _1!) + } + else { + return nil + } + } + + } +} public extension Api { enum DocumentAttribute: TypeConstructorDescription { case documentAttributeAnimated @@ -944,227 +1094,3 @@ public extension Api { } } -public extension Api { - enum EmojiURL: TypeConstructorDescription { - case emojiURL(url: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .emojiURL(let url): - if boxed { - buffer.appendInt32(-1519029347) - } - serializeString(url, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .emojiURL(let url): - return ("emojiURL", [("url", url as Any)]) - } - } - - public static func parse_emojiURL(_ reader: BufferReader) -> EmojiURL? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.EmojiURL.emojiURL(url: _1!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum EncryptedChat: TypeConstructorDescription { - case encryptedChat(id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAOrB: Buffer, keyFingerprint: Int64) - case encryptedChatDiscarded(flags: Int32, id: Int32) - case encryptedChatEmpty(id: Int32) - case encryptedChatRequested(flags: Int32, folderId: Int32?, id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gA: Buffer) - case encryptedChatWaiting(id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): - if boxed { - buffer.appendInt32(1643173063) - } - serializeInt32(id, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeInt64(adminId, buffer: buffer, boxed: false) - serializeInt64(participantId, buffer: buffer, boxed: false) - serializeBytes(gAOrB, buffer: buffer, boxed: false) - serializeInt64(keyFingerprint, buffer: buffer, boxed: false) - break - case .encryptedChatDiscarded(let flags, let id): - if boxed { - buffer.appendInt32(505183301) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(id, buffer: buffer, boxed: false) - break - case .encryptedChatEmpty(let id): - if boxed { - buffer.appendInt32(-1417756512) - } - serializeInt32(id, buffer: buffer, boxed: false) - break - case .encryptedChatRequested(let flags, let folderId, let id, let accessHash, let date, let adminId, let participantId, let gA): - if boxed { - buffer.appendInt32(1223809356) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} - serializeInt32(id, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeInt64(adminId, buffer: buffer, boxed: false) - serializeInt64(participantId, buffer: buffer, boxed: false) - serializeBytes(gA, buffer: buffer, boxed: false) - break - case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): - if boxed { - buffer.appendInt32(1722964307) - } - serializeInt32(id, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeInt64(adminId, buffer: buffer, boxed: false) - serializeInt64(participantId, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): - return ("encryptedChat", [("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAOrB", gAOrB as Any), ("keyFingerprint", keyFingerprint as Any)]) - case .encryptedChatDiscarded(let flags, let id): - return ("encryptedChatDiscarded", [("flags", flags as Any), ("id", id as Any)]) - case .encryptedChatEmpty(let id): - return ("encryptedChatEmpty", [("id", id as Any)]) - case .encryptedChatRequested(let flags, let folderId, let id, let accessHash, let date, let adminId, let participantId, let gA): - return ("encryptedChatRequested", [("flags", flags as Any), ("folderId", folderId as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gA", gA as Any)]) - case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): - return ("encryptedChatWaiting", [("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any)]) - } - } - - public static func parse_encryptedChat(_ reader: BufferReader) -> EncryptedChat? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: Int32? - _3 = reader.readInt32() - var _4: Int64? - _4 = reader.readInt64() - var _5: Int64? - _5 = reader.readInt64() - var _6: Buffer? - _6 = parseBytes(reader) - var _7: Int64? - _7 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { - return Api.EncryptedChat.encryptedChat(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!, gAOrB: _6!, keyFingerprint: _7!) - } - else { - return nil - } - } - public static func parse_encryptedChatDiscarded(_ reader: BufferReader) -> EncryptedChat? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.EncryptedChat.encryptedChatDiscarded(flags: _1!, id: _2!) - } - else { - return nil - } - } - public static func parse_encryptedChatEmpty(_ reader: BufferReader) -> EncryptedChat? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.EncryptedChat.encryptedChatEmpty(id: _1!) - } - else { - return nil - } - } - public static func parse_encryptedChatRequested(_ reader: BufferReader) -> EncryptedChat? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } - var _3: Int32? - _3 = reader.readInt32() - var _4: Int64? - _4 = reader.readInt64() - var _5: Int32? - _5 = reader.readInt32() - var _6: Int64? - _6 = reader.readInt64() - var _7: Int64? - _7 = reader.readInt64() - var _8: Buffer? - _8 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = _8 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { - return Api.EncryptedChat.encryptedChatRequested(flags: _1!, folderId: _2, id: _3!, accessHash: _4!, date: _5!, adminId: _6!, participantId: _7!, gA: _8!) - } - else { - return nil - } - } - public static func parse_encryptedChatWaiting(_ reader: BufferReader) -> EncryptedChat? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: Int32? - _3 = reader.readInt32() - var _4: Int64? - _4 = reader.readInt64() - var _5: Int64? - _5 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.EncryptedChat.encryptedChatWaiting(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api7.swift b/submodules/TelegramApi/Sources/Api7.swift index 4529fac0e5..97dd79ac02 100644 --- a/submodules/TelegramApi/Sources/Api7.swift +++ b/submodules/TelegramApi/Sources/Api7.swift @@ -1,3 +1,227 @@ +public extension Api { + enum EmojiURL: TypeConstructorDescription { + case emojiURL(url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .emojiURL(let url): + if boxed { + buffer.appendInt32(-1519029347) + } + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .emojiURL(let url): + return ("emojiURL", [("url", url as Any)]) + } + } + + public static func parse_emojiURL(_ reader: BufferReader) -> EmojiURL? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.EmojiURL.emojiURL(url: _1!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum EncryptedChat: TypeConstructorDescription { + case encryptedChat(id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gAOrB: Buffer, keyFingerprint: Int64) + case encryptedChatDiscarded(flags: Int32, id: Int32) + case encryptedChatEmpty(id: Int32) + case encryptedChatRequested(flags: Int32, folderId: Int32?, id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64, gA: Buffer) + case encryptedChatWaiting(id: Int32, accessHash: Int64, date: Int32, adminId: Int64, participantId: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): + if boxed { + buffer.appendInt32(1643173063) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt64(adminId, buffer: buffer, boxed: false) + serializeInt64(participantId, buffer: buffer, boxed: false) + serializeBytes(gAOrB, buffer: buffer, boxed: false) + serializeInt64(keyFingerprint, buffer: buffer, boxed: false) + break + case .encryptedChatDiscarded(let flags, let id): + if boxed { + buffer.appendInt32(505183301) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(id, buffer: buffer, boxed: false) + break + case .encryptedChatEmpty(let id): + if boxed { + buffer.appendInt32(-1417756512) + } + serializeInt32(id, buffer: buffer, boxed: false) + break + case .encryptedChatRequested(let flags, let folderId, let id, let accessHash, let date, let adminId, let participantId, let gA): + if boxed { + buffer.appendInt32(1223809356) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeInt32(folderId!, buffer: buffer, boxed: false)} + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt64(adminId, buffer: buffer, boxed: false) + serializeInt64(participantId, buffer: buffer, boxed: false) + serializeBytes(gA, buffer: buffer, boxed: false) + break + case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): + if boxed { + buffer.appendInt32(1722964307) + } + serializeInt32(id, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt64(adminId, buffer: buffer, boxed: false) + serializeInt64(participantId, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .encryptedChat(let id, let accessHash, let date, let adminId, let participantId, let gAOrB, let keyFingerprint): + return ("encryptedChat", [("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gAOrB", gAOrB as Any), ("keyFingerprint", keyFingerprint as Any)]) + case .encryptedChatDiscarded(let flags, let id): + return ("encryptedChatDiscarded", [("flags", flags as Any), ("id", id as Any)]) + case .encryptedChatEmpty(let id): + return ("encryptedChatEmpty", [("id", id as Any)]) + case .encryptedChatRequested(let flags, let folderId, let id, let accessHash, let date, let adminId, let participantId, let gA): + return ("encryptedChatRequested", [("flags", flags as Any), ("folderId", folderId as Any), ("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any), ("gA", gA as Any)]) + case .encryptedChatWaiting(let id, let accessHash, let date, let adminId, let participantId): + return ("encryptedChatWaiting", [("id", id as Any), ("accessHash", accessHash as Any), ("date", date as Any), ("adminId", adminId as Any), ("participantId", participantId as Any)]) + } + } + + public static func parse_encryptedChat(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int64? + _4 = reader.readInt64() + var _5: Int64? + _5 = reader.readInt64() + var _6: Buffer? + _6 = parseBytes(reader) + var _7: Int64? + _7 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.EncryptedChat.encryptedChat(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!, gAOrB: _6!, keyFingerprint: _7!) + } + else { + return nil + } + } + public static func parse_encryptedChatDiscarded(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.EncryptedChat.encryptedChatDiscarded(flags: _1!, id: _2!) + } + else { + return nil + } + } + public static func parse_encryptedChatEmpty(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.EncryptedChat.encryptedChatEmpty(id: _1!) + } + else { + return nil + } + } + public static func parse_encryptedChatRequested(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + if Int(_1!) & Int(1 << 0) != 0 {_2 = reader.readInt32() } + var _3: Int32? + _3 = reader.readInt32() + var _4: Int64? + _4 = reader.readInt64() + var _5: Int32? + _5 = reader.readInt32() + var _6: Int64? + _6 = reader.readInt64() + var _7: Int64? + _7 = reader.readInt64() + var _8: Buffer? + _8 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.EncryptedChat.encryptedChatRequested(flags: _1!, folderId: _2, id: _3!, accessHash: _4!, date: _5!, adminId: _6!, participantId: _7!, gA: _8!) + } + else { + return nil + } + } + public static func parse_encryptedChatWaiting(_ reader: BufferReader) -> EncryptedChat? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int64? + _4 = reader.readInt64() + var _5: Int64? + _5 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.EncryptedChat.encryptedChatWaiting(id: _1!, accessHash: _2!, date: _3!, adminId: _4!, participantId: _5!) + } + else { + return nil + } + } + + } +} public extension Api { enum EncryptedFile: TypeConstructorDescription { case encryptedFile(id: Int64, accessHash: Int64, size: Int64, dcId: Int32, keyFingerprint: Int32) @@ -1230,257 +1454,3 @@ public extension Api { } } -public extension Api { - enum GroupCallParticipantVideoSourceGroup: TypeConstructorDescription { - case groupCallParticipantVideoSourceGroup(semantics: String, sources: [Int32]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .groupCallParticipantVideoSourceGroup(let semantics, let sources): - if boxed { - buffer.appendInt32(-592373577) - } - serializeString(semantics, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(sources.count)) - for item in sources { - serializeInt32(item, buffer: buffer, boxed: false) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .groupCallParticipantVideoSourceGroup(let semantics, let sources): - return ("groupCallParticipantVideoSourceGroup", [("semantics", semantics as Any), ("sources", sources as Any)]) - } - } - - public static func parse_groupCallParticipantVideoSourceGroup(_ reader: BufferReader) -> GroupCallParticipantVideoSourceGroup? { - var _1: String? - _1 = parseString(reader) - var _2: [Int32]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.GroupCallParticipantVideoSourceGroup.groupCallParticipantVideoSourceGroup(semantics: _1!, sources: _2!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum GroupCallStreamChannel: TypeConstructorDescription { - case groupCallStreamChannel(channel: Int32, scale: Int32, lastTimestampMs: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .groupCallStreamChannel(let channel, let scale, let lastTimestampMs): - if boxed { - buffer.appendInt32(-2132064081) - } - serializeInt32(channel, buffer: buffer, boxed: false) - serializeInt32(scale, buffer: buffer, boxed: false) - serializeInt64(lastTimestampMs, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .groupCallStreamChannel(let channel, let scale, let lastTimestampMs): - return ("groupCallStreamChannel", [("channel", channel as Any), ("scale", scale as Any), ("lastTimestampMs", lastTimestampMs as Any)]) - } - } - - public static func parse_groupCallStreamChannel(_ reader: BufferReader) -> GroupCallStreamChannel? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: Int64? - _3 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.GroupCallStreamChannel.groupCallStreamChannel(channel: _1!, scale: _2!, lastTimestampMs: _3!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum HighScore: TypeConstructorDescription { - case highScore(pos: Int32, userId: Int64, score: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .highScore(let pos, let userId, let score): - if boxed { - buffer.appendInt32(1940093419) - } - serializeInt32(pos, buffer: buffer, boxed: false) - serializeInt64(userId, buffer: buffer, boxed: false) - serializeInt32(score, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .highScore(let pos, let userId, let score): - return ("highScore", [("pos", pos as Any), ("userId", userId as Any), ("score", score as Any)]) - } - } - - public static func parse_highScore(_ reader: BufferReader) -> HighScore? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int64? - _2 = reader.readInt64() - var _3: Int32? - _3 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.HighScore.highScore(pos: _1!, userId: _2!, score: _3!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum ImportedContact: TypeConstructorDescription { - case importedContact(userId: Int64, clientId: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .importedContact(let userId, let clientId): - if boxed { - buffer.appendInt32(-1052885936) - } - serializeInt64(userId, buffer: buffer, boxed: false) - serializeInt64(clientId, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .importedContact(let userId, let clientId): - return ("importedContact", [("userId", userId as Any), ("clientId", clientId as Any)]) - } - } - - public static func parse_importedContact(_ reader: BufferReader) -> ImportedContact? { - var _1: Int64? - _1 = reader.readInt64() - var _2: Int64? - _2 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.ImportedContact.importedContact(userId: _1!, clientId: _2!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum InlineBotSwitchPM: TypeConstructorDescription { - case inlineBotSwitchPM(text: String, startParam: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inlineBotSwitchPM(let text, let startParam): - if boxed { - buffer.appendInt32(1008755359) - } - serializeString(text, buffer: buffer, boxed: false) - serializeString(startParam, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inlineBotSwitchPM(let text, let startParam): - return ("inlineBotSwitchPM", [("text", text as Any), ("startParam", startParam as Any)]) - } - } - - public static func parse_inlineBotSwitchPM(_ reader: BufferReader) -> InlineBotSwitchPM? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.InlineBotSwitchPM.inlineBotSwitchPM(text: _1!, startParam: _2!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum InlineBotWebView: TypeConstructorDescription { - case inlineBotWebView(text: String, url: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inlineBotWebView(let text, let url): - if boxed { - buffer.appendInt32(-1250781739) - } - serializeString(text, buffer: buffer, boxed: false) - serializeString(url, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inlineBotWebView(let text, let url): - return ("inlineBotWebView", [("text", text as Any), ("url", url as Any)]) - } - } - - public static func parse_inlineBotWebView(_ reader: BufferReader) -> InlineBotWebView? { - var _1: String? - _1 = parseString(reader) - var _2: String? - _2 = parseString(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.InlineBotWebView.inlineBotWebView(text: _1!, url: _2!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api8.swift b/submodules/TelegramApi/Sources/Api8.swift index c40175faf0..7d4678a8c1 100644 --- a/submodules/TelegramApi/Sources/Api8.swift +++ b/submodules/TelegramApi/Sources/Api8.swift @@ -1,3 +1,257 @@ +public extension Api { + enum GroupCallParticipantVideoSourceGroup: TypeConstructorDescription { + case groupCallParticipantVideoSourceGroup(semantics: String, sources: [Int32]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .groupCallParticipantVideoSourceGroup(let semantics, let sources): + if boxed { + buffer.appendInt32(-592373577) + } + serializeString(semantics, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(sources.count)) + for item in sources { + serializeInt32(item, buffer: buffer, boxed: false) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .groupCallParticipantVideoSourceGroup(let semantics, let sources): + return ("groupCallParticipantVideoSourceGroup", [("semantics", semantics as Any), ("sources", sources as Any)]) + } + } + + public static func parse_groupCallParticipantVideoSourceGroup(_ reader: BufferReader) -> GroupCallParticipantVideoSourceGroup? { + var _1: String? + _1 = parseString(reader) + var _2: [Int32]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.GroupCallParticipantVideoSourceGroup.groupCallParticipantVideoSourceGroup(semantics: _1!, sources: _2!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum GroupCallStreamChannel: TypeConstructorDescription { + case groupCallStreamChannel(channel: Int32, scale: Int32, lastTimestampMs: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .groupCallStreamChannel(let channel, let scale, let lastTimestampMs): + if boxed { + buffer.appendInt32(-2132064081) + } + serializeInt32(channel, buffer: buffer, boxed: false) + serializeInt32(scale, buffer: buffer, boxed: false) + serializeInt64(lastTimestampMs, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .groupCallStreamChannel(let channel, let scale, let lastTimestampMs): + return ("groupCallStreamChannel", [("channel", channel as Any), ("scale", scale as Any), ("lastTimestampMs", lastTimestampMs as Any)]) + } + } + + public static func parse_groupCallStreamChannel(_ reader: BufferReader) -> GroupCallStreamChannel? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.GroupCallStreamChannel.groupCallStreamChannel(channel: _1!, scale: _2!, lastTimestampMs: _3!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum HighScore: TypeConstructorDescription { + case highScore(pos: Int32, userId: Int64, score: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .highScore(let pos, let userId, let score): + if boxed { + buffer.appendInt32(1940093419) + } + serializeInt32(pos, buffer: buffer, boxed: false) + serializeInt64(userId, buffer: buffer, boxed: false) + serializeInt32(score, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .highScore(let pos, let userId, let score): + return ("highScore", [("pos", pos as Any), ("userId", userId as Any), ("score", score as Any)]) + } + } + + public static func parse_highScore(_ reader: BufferReader) -> HighScore? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.HighScore.highScore(pos: _1!, userId: _2!, score: _3!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum ImportedContact: TypeConstructorDescription { + case importedContact(userId: Int64, clientId: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .importedContact(let userId, let clientId): + if boxed { + buffer.appendInt32(-1052885936) + } + serializeInt64(userId, buffer: buffer, boxed: false) + serializeInt64(clientId, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .importedContact(let userId, let clientId): + return ("importedContact", [("userId", userId as Any), ("clientId", clientId as Any)]) + } + } + + public static func parse_importedContact(_ reader: BufferReader) -> ImportedContact? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.ImportedContact.importedContact(userId: _1!, clientId: _2!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum InlineBotSwitchPM: TypeConstructorDescription { + case inlineBotSwitchPM(text: String, startParam: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + if boxed { + buffer.appendInt32(1008755359) + } + serializeString(text, buffer: buffer, boxed: false) + serializeString(startParam, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inlineBotSwitchPM(let text, let startParam): + return ("inlineBotSwitchPM", [("text", text as Any), ("startParam", startParam as Any)]) + } + } + + public static func parse_inlineBotSwitchPM(_ reader: BufferReader) -> InlineBotSwitchPM? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InlineBotSwitchPM.inlineBotSwitchPM(text: _1!, startParam: _2!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum InlineBotWebView: TypeConstructorDescription { + case inlineBotWebView(text: String, url: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inlineBotWebView(let text, let url): + if boxed { + buffer.appendInt32(-1250781739) + } + serializeString(text, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inlineBotWebView(let text, let url): + return ("inlineBotWebView", [("text", text as Any), ("url", url as Any)]) + } + } + + public static func parse_inlineBotWebView(_ reader: BufferReader) -> InlineBotWebView? { + var _1: String? + _1 = parseString(reader) + var _2: String? + _2 = parseString(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InlineBotWebView.inlineBotWebView(text: _1!, url: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum InlineQueryPeerType: TypeConstructorDescription { case inlineQueryPeerTypeBotPM @@ -992,227 +1246,3 @@ public extension Api { } } -public extension Api { - enum InputBusinessGreetingMessage: TypeConstructorDescription { - case inputBusinessGreetingMessage(shortcutId: Int32, recipients: Api.InputBusinessRecipients, noActivityDays: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputBusinessGreetingMessage(let shortcutId, let recipients, let noActivityDays): - if boxed { - buffer.appendInt32(26528571) - } - serializeInt32(shortcutId, buffer: buffer, boxed: false) - recipients.serialize(buffer, true) - serializeInt32(noActivityDays, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputBusinessGreetingMessage(let shortcutId, let recipients, let noActivityDays): - return ("inputBusinessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)]) - } - } - - public static func parse_inputBusinessGreetingMessage(_ reader: BufferReader) -> InputBusinessGreetingMessage? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.InputBusinessRecipients? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.InputBusinessRecipients - } - var _3: Int32? - _3 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.InputBusinessGreetingMessage.inputBusinessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!) - } - else { - return nil - } - } - - } -} -public extension Api { - enum InputBusinessIntro: TypeConstructorDescription { - case inputBusinessIntro(flags: Int32, title: String, description: String, sticker: Api.InputDocument?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputBusinessIntro(let flags, let title, let description, let sticker): - if boxed { - buffer.appendInt32(163867085) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(title, buffer: buffer, boxed: false) - serializeString(description, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputBusinessIntro(let flags, let title, let description, let sticker): - return ("inputBusinessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)]) - } - } - - public static func parse_inputBusinessIntro(_ reader: BufferReader) -> InputBusinessIntro? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: Api.InputDocument? - if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.InputDocument - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.InputBusinessIntro.inputBusinessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4) - } - else { - return nil - } - } - - } -} -public extension Api { - enum InputBusinessRecipients: TypeConstructorDescription { - case inputBusinessRecipients(flags: Int32, users: [Api.InputUser]?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputBusinessRecipients(let flags, let users): - if boxed { - buffer.appendInt32(1871393450) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users!.count)) - for item in users! { - item.serialize(buffer, true) - }} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputBusinessRecipients(let flags, let users): - return ("inputBusinessRecipients", [("flags", flags as Any), ("users", users as Any)]) - } - } - - public static func parse_inputBusinessRecipients(_ reader: BufferReader) -> InputBusinessRecipients? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.InputUser]? - if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputUser.self) - } } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 4) == 0) || _2 != nil - if _c1 && _c2 { - return Api.InputBusinessRecipients.inputBusinessRecipients(flags: _1!, users: _2) - } - else { - return nil - } - } - - } -} -public extension Api { - indirect enum InputChannel: TypeConstructorDescription { - case inputChannel(channelId: Int64, accessHash: Int64) - case inputChannelEmpty - case inputChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .inputChannel(let channelId, let accessHash): - if boxed { - buffer.appendInt32(-212145112) - } - serializeInt64(channelId, buffer: buffer, boxed: false) - serializeInt64(accessHash, buffer: buffer, boxed: false) - break - case .inputChannelEmpty: - if boxed { - buffer.appendInt32(-292807034) - } - - break - case .inputChannelFromMessage(let peer, let msgId, let channelId): - if boxed { - buffer.appendInt32(1536380829) - } - peer.serialize(buffer, true) - serializeInt32(msgId, buffer: buffer, boxed: false) - serializeInt64(channelId, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .inputChannel(let channelId, let accessHash): - return ("inputChannel", [("channelId", channelId as Any), ("accessHash", accessHash as Any)]) - case .inputChannelEmpty: - return ("inputChannelEmpty", []) - case .inputChannelFromMessage(let peer, let msgId, let channelId): - return ("inputChannelFromMessage", [("peer", peer as Any), ("msgId", msgId as Any), ("channelId", channelId as Any)]) - } - } - - public static func parse_inputChannel(_ reader: BufferReader) -> InputChannel? { - var _1: Int64? - _1 = reader.readInt64() - var _2: Int64? - _2 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.InputChannel.inputChannel(channelId: _1!, accessHash: _2!) - } - else { - return nil - } - } - public static func parse_inputChannelEmpty(_ reader: BufferReader) -> InputChannel? { - return Api.InputChannel.inputChannelEmpty - } - public static func parse_inputChannelFromMessage(_ reader: BufferReader) -> InputChannel? { - var _1: Api.InputPeer? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.InputPeer - } - var _2: Int32? - _2 = reader.readInt32() - var _3: Int64? - _3 = reader.readInt64() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.InputChannel.inputChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api9.swift b/submodules/TelegramApi/Sources/Api9.swift index 8d077df130..d67c5a00ae 100644 --- a/submodules/TelegramApi/Sources/Api9.swift +++ b/submodules/TelegramApi/Sources/Api9.swift @@ -1,3 +1,227 @@ +public extension Api { + enum InputBusinessGreetingMessage: TypeConstructorDescription { + case inputBusinessGreetingMessage(shortcutId: Int32, recipients: Api.InputBusinessRecipients, noActivityDays: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBusinessGreetingMessage(let shortcutId, let recipients, let noActivityDays): + if boxed { + buffer.appendInt32(26528571) + } + serializeInt32(shortcutId, buffer: buffer, boxed: false) + recipients.serialize(buffer, true) + serializeInt32(noActivityDays, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBusinessGreetingMessage(let shortcutId, let recipients, let noActivityDays): + return ("inputBusinessGreetingMessage", [("shortcutId", shortcutId as Any), ("recipients", recipients as Any), ("noActivityDays", noActivityDays as Any)]) + } + } + + public static func parse_inputBusinessGreetingMessage(_ reader: BufferReader) -> InputBusinessGreetingMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.InputBusinessRecipients? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.InputBusinessRecipients + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputBusinessGreetingMessage.inputBusinessGreetingMessage(shortcutId: _1!, recipients: _2!, noActivityDays: _3!) + } + else { + return nil + } + } + + } +} +public extension Api { + enum InputBusinessIntro: TypeConstructorDescription { + case inputBusinessIntro(flags: Int32, title: String, description: String, sticker: Api.InputDocument?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBusinessIntro(let flags, let title, let description, let sticker): + if boxed { + buffer.appendInt32(163867085) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + serializeString(description, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {sticker!.serialize(buffer, true)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBusinessIntro(let flags, let title, let description, let sticker): + return ("inputBusinessIntro", [("flags", flags as Any), ("title", title as Any), ("description", description as Any), ("sticker", sticker as Any)]) + } + } + + public static func parse_inputBusinessIntro(_ reader: BufferReader) -> InputBusinessIntro? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: Api.InputDocument? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.InputDocument + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.InputBusinessIntro.inputBusinessIntro(flags: _1!, title: _2!, description: _3!, sticker: _4) + } + else { + return nil + } + } + + } +} +public extension Api { + enum InputBusinessRecipients: TypeConstructorDescription { + case inputBusinessRecipients(flags: Int32, users: [Api.InputUser]?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputBusinessRecipients(let flags, let users): + if boxed { + buffer.appendInt32(1871393450) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 4) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users!.count)) + for item in users! { + item.serialize(buffer, true) + }} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputBusinessRecipients(let flags, let users): + return ("inputBusinessRecipients", [("flags", flags as Any), ("users", users as Any)]) + } + } + + public static func parse_inputBusinessRecipients(_ reader: BufferReader) -> InputBusinessRecipients? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.InputUser]? + if Int(_1!) & Int(1 << 4) != 0 {if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.InputUser.self) + } } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 4) == 0) || _2 != nil + if _c1 && _c2 { + return Api.InputBusinessRecipients.inputBusinessRecipients(flags: _1!, users: _2) + } + else { + return nil + } + } + + } +} +public extension Api { + indirect enum InputChannel: TypeConstructorDescription { + case inputChannel(channelId: Int64, accessHash: Int64) + case inputChannelEmpty + case inputChannelFromMessage(peer: Api.InputPeer, msgId: Int32, channelId: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputChannel(let channelId, let accessHash): + if boxed { + buffer.appendInt32(-212145112) + } + serializeInt64(channelId, buffer: buffer, boxed: false) + serializeInt64(accessHash, buffer: buffer, boxed: false) + break + case .inputChannelEmpty: + if boxed { + buffer.appendInt32(-292807034) + } + + break + case .inputChannelFromMessage(let peer, let msgId, let channelId): + if boxed { + buffer.appendInt32(1536380829) + } + peer.serialize(buffer, true) + serializeInt32(msgId, buffer: buffer, boxed: false) + serializeInt64(channelId, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputChannel(let channelId, let accessHash): + return ("inputChannel", [("channelId", channelId as Any), ("accessHash", accessHash as Any)]) + case .inputChannelEmpty: + return ("inputChannelEmpty", []) + case .inputChannelFromMessage(let peer, let msgId, let channelId): + return ("inputChannelFromMessage", [("peer", peer as Any), ("msgId", msgId as Any), ("channelId", channelId as Any)]) + } + } + + public static func parse_inputChannel(_ reader: BufferReader) -> InputChannel? { + var _1: Int64? + _1 = reader.readInt64() + var _2: Int64? + _2 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.InputChannel.inputChannel(channelId: _1!, accessHash: _2!) + } + else { + return nil + } + } + public static func parse_inputChannelEmpty(_ reader: BufferReader) -> InputChannel? { + return Api.InputChannel.inputChannelEmpty + } + public static func parse_inputChannelFromMessage(_ reader: BufferReader) -> InputChannel? { + var _1: Api.InputPeer? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.InputPeer + } + var _2: Int32? + _2 = reader.readInt32() + var _3: Int64? + _3 = reader.readInt64() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.InputChannel.inputChannelFromMessage(peer: _1!, msgId: _2!, channelId: _3!) + } + else { + return nil + } + } + + } +} public extension Api { enum InputChatPhoto: TypeConstructorDescription { case inputChatPhoto(id: Api.InputPhoto) @@ -90,6 +314,74 @@ public extension Api { } } +public extension Api { + enum InputChatTheme: TypeConstructorDescription { + case inputChatTheme(emoticon: String) + case inputChatThemeEmpty + case inputChatThemeUniqueGift(slug: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .inputChatTheme(let emoticon): + if boxed { + buffer.appendInt32(-918689444) + } + serializeString(emoticon, buffer: buffer, boxed: false) + break + case .inputChatThemeEmpty: + if boxed { + buffer.appendInt32(-2094627709) + } + + break + case .inputChatThemeUniqueGift(let slug): + if boxed { + buffer.appendInt32(-2014978076) + } + serializeString(slug, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .inputChatTheme(let emoticon): + return ("inputChatTheme", [("emoticon", emoticon as Any)]) + case .inputChatThemeEmpty: + return ("inputChatThemeEmpty", []) + case .inputChatThemeUniqueGift(let slug): + return ("inputChatThemeUniqueGift", [("slug", slug as Any)]) + } + } + + public static func parse_inputChatTheme(_ reader: BufferReader) -> InputChatTheme? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.InputChatTheme.inputChatTheme(emoticon: _1!) + } + else { + return nil + } + } + public static func parse_inputChatThemeEmpty(_ reader: BufferReader) -> InputChatTheme? { + return Api.InputChatTheme.inputChatThemeEmpty + } + public static func parse_inputChatThemeUniqueGift(_ reader: BufferReader) -> InputChatTheme? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.InputChatTheme.inputChatThemeUniqueGift(slug: _1!) + } + else { + return nil + } + } + + } +} public extension Api { enum InputChatlist: TypeConstructorDescription { case inputChatlistDialogFilter(filterId: Int32) diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index b543d3f8fa..53089efce6 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -853,17 +853,18 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } if let id = state.id as? PeerMessagesMediaPlaylistItemId, let playlistLocation = strongSelf.playlistLocation as? PeerMessagesPlaylistLocation { if type == .music { - if case .custom = playlistLocation { + switch playlistLocation { + case .custom, .savedMusic: let controllerContext: AccountContext if account.id == strongSelf.context.account.id { controllerContext = strongSelf.context } else { controllerContext = strongSelf.context.sharedContext.makeTempAccountContext(account: account) } - let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: .peer(id: id.messageId.peerId), type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: playlistLocation, parentNavigationController: strongSelf.navigationController as? NavigationController, updateMusicSaved: nil, reorderSavedMusic: nil) + let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: .peer(id: id.messageId.peerId), type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: playlistLocation, parentNavigationController: strongSelf.navigationController as? NavigationController) strongSelf.displayNode.view.window?.endEditing(true) strongSelf.present(controller, in: .window(.root)) - } else if case let .messages(chatLocation, _, _) = playlistLocation { + case let .messages(chatLocation, _, _): let signal = strongSelf.context.sharedContext.messageFromPreloadedChatHistoryViewForLocation(id: id.messageId, location: ChatHistoryLocationInput(content: .InitialSearch(subject: MessageHistoryInitialSearchSubject(location: .id(id.messageId)), count: 60, highlight: true, setupReply: false), id: 0), context: strongSelf.context, chatLocation: chatLocation, subject: nil, chatLocationContextHolder: Atomic(value: nil), tag: .tag(MessageTags.music)) var cancelImpl: (() -> Void)? @@ -901,7 +902,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { } else { controllerContext = strongSelf.context.sharedContext.makeTempAccountContext(account: account) } - let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: strongSelf.navigationController as? NavigationController, updateMusicSaved: nil, reorderSavedMusic: nil) + let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: strongSelf.navigationController as? NavigationController) strongSelf.displayNode.view.window?.endEditing(true) strongSelf.present(controller, in: .window(.root)) } else if index.1 { @@ -915,6 +916,8 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { cancelImpl = { self?.playlistPreloadDisposable?.dispose() } + default: + break } } else { strongSelf.context.sharedContext.navigateToChat(accountId: strongSelf.context.account.id, peerId: id.messageId.peerId, messageId: id.messageId) diff --git a/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs b/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs index 65fb77a3ba..852e58faf1 100644 --- a/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs +++ b/submodules/TelegramCore/FlatSerialization/Models/PartialMediaReference.fbs @@ -41,13 +41,18 @@ table PartialMediaReference_SavedSticker { table PartialMediaReference_RecentSticker { } +table PartialMediaReference_SavedMusic { + peer:PeerReference (id: 0); +} + union PartialMediaReference_Value { PartialMediaReference_Message, PartialMediaReference_WebPage, PartialMediaReference_StickerPack, PartialMediaReference_SavedGif, PartialMediaReference_SavedSticker, - PartialMediaReference_RecentSticker + PartialMediaReference_RecentSticker, + PartialMediaReference_SavedMusic } table PartialMediaReference { diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 4836e5ece5..e17ded2bde 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -127,7 +127,7 @@ public class UnauthorizedAccount { if let nextType = nextType { parsedNextType = AuthorizationCodeNextType(apiType: nextType) } - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(phoneNumber, _, _, syncContacts) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(phoneNumber, _, _, _, _, syncContacts) = state.contents { transaction.setState(UnauthorizedAccountState(isTestingEnvironment: testingEnvironment, masterDatacenterId: masterDatacenterId, contents: .confirmationCodeEntry(number: phoneNumber, type: SentAuthorizationCodeType(apiType: type), hash: phoneCodeHash, timeout: codeTimeout, nextType: parsedNextType, syncContacts: syncContacts, previousCodeEntry: nil, usePrevious: false))) } }).start() @@ -136,7 +136,7 @@ public class UnauthorizedAccount { case let .authorization(_, _, _, futureAuthToken, user): let _ = postbox.transaction({ [weak self] transaction in var syncContacts = true - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(_, _, _, syncContactsValue) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(_, _, _, _, _, syncContactsValue) = state.contents { syncContacts = syncContactsValue } @@ -162,7 +162,7 @@ public class UnauthorizedAccount { case let .authorizationSignUpRequired(_, termsOfService): let _ = postbox.transaction({ [weak self] transaction in if let self { - if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(number, codeHash, _, syncContacts) = state.contents { + if let state = transaction.getState() as? UnauthorizedAccountState, case let .payment(number, codeHash, _, _, _, syncContacts) = state.contents { let _ = beginSignUp( account: self, data: AuthorizationSignUpData( diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift index d8765c1825..d90a71b734 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift @@ -101,8 +101,12 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe case .inputGroupCallSlug, .inputGroupCallInviteMessage: return nil } - case let .messageActionSetChatTheme(emoji): - return TelegramMediaAction(action: .setChatTheme(emoji: emoji)) + case let .messageActionSetChatTheme(chatTheme): + if let chatTheme = ChatTheme(apiChatTheme: chatTheme) { + return TelegramMediaAction(action: .setChatTheme(chatTheme: chatTheme)) + } else { + return nil + } case .messageActionChatJoinedByRequest: return TelegramMediaAction(action: .joinedByRequest) case let .messageActionWebViewDataSentMe(text, _), let .messageActionWebViewDataSent(text): diff --git a/submodules/TelegramCore/Sources/Authorization.swift b/submodules/TelegramCore/Sources/Authorization.swift index 836687ce7f..a146932d6f 100644 --- a/submodules/TelegramCore/Sources/Authorization.swift +++ b/submodules/TelegramCore/Sources/Authorization.swift @@ -518,8 +518,8 @@ private func internalResendAuthorizationCode(accountManager: AccountManager castError(PendingMessageUploadError.self), .text) - } else if let media = media.first, let mediaResult = mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, passFetchProgress: passFetchProgress, forceNoBigParts: forceNoBigParts, peerId: peerId, media: media, text: text, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, messageId: messageId, attributes: attributes, mediaReference: mediaReference) { + } else if let media = media.first, let mediaResult = mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, passFetchProgress: passFetchProgress, forceNoBigParts: forceNoBigParts, peerId: peerId, media: media, text: text, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, messageId: messageId, attributes: attributes, mediaReference: mediaReference, explicitPartialReference: explicitPartialReference) { return .signal(mediaResult, .media) } else { return .signal(.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil, cacheReferenceKey: nil))), .text) } } -func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, passFetchProgress: Bool, forceNoBigParts: Bool, peerId: PeerId, media: Media, text: String, autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute], mediaReference: AnyMediaReference?) -> Signal? { +func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, passFetchProgress: Bool, forceNoBigParts: Bool, peerId: PeerId, media: Media, text: String, autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute], mediaReference: AnyMediaReference?, explicitPartialReference: PartialMediaReference?) -> Signal? { if let paidContent = media as? TelegramMediaPaidContent { var signals: [Signal] = [] var mediaIds: [MediaId] = [] @@ -217,6 +218,8 @@ func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Post return .standalone(media: file) } } + } else if let explicitPartialReference { + finalMediaReference = .single(explicitPartialReference.mediaReference(file)) } else { finalMediaReference = .single(.savedGif(media: file)) } @@ -580,7 +583,7 @@ if "".isEmpty { let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) } else { - updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: Int64.random(in: Int64.min ... Int64.max), flags: [.transformedMedia], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [])) + updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: Int64.random(in: Int64.min ... Int64.max), flags: [.transformedMedia], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [], partialReference: nil)) } } @@ -1031,7 +1034,7 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili let attribute = updatedAttributes[index] as! OutgoingMessageInfoAttribute updatedAttributes[index] = attribute.withUpdatedFlags(attribute.flags.union([.transformedMedia])) } else { - updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: Int64.random(in: Int64.min ... Int64.max), flags: [.transformedMedia], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [])) + updatedAttributes.append(OutgoingMessageInfoAttribute(uniqueId: Int64.random(in: Int64.min ... Int64.max), flags: [.transformedMedia], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [], partialReference: nil)) } } diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingPeerMediaUploadManager.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingPeerMediaUploadManager.swift index 864d295311..5c5f8a7cc9 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingPeerMediaUploadManager.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingPeerMediaUploadManager.swift @@ -120,7 +120,7 @@ private func generatePeerMediaMessage(network: Network, accountPeerId: EnginePee flags.insert(.Sending) var attributes: [MessageAttribute] = [] - attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: [], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [])) + attributes.append(OutgoingMessageInfoAttribute(uniqueId: randomId, flags: [], acknowledged: false, correlationId: nil, bubbleUpEmojiOrStickersets: [], partialReference: nil)) var media: [Media] = [] switch content { diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index 15cb2eea6f..7316f7234f 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -66,7 +66,7 @@ private func requestEditMessageInternal(accountPeerId: PeerId, postbox: Postbox, if let invertMediaAttribute { attributes.append(invertMediaAttribute) } - return mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: stateManager.auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: mediaReferenceRevalidationContext, forceReupload: forceReupload, isGrouped: false, passFetchProgress: false, forceNoBigParts: false, peerId: messageId.peerId, media: augmentedMedia, text: "", autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, messageId: nil, attributes: attributes, mediaReference: nil) + return mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: stateManager.auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: mediaReferenceRevalidationContext, forceReupload: forceReupload, isGrouped: false, passFetchProgress: false, forceNoBigParts: false, peerId: messageId.peerId, media: augmentedMedia, text: "", autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, messageId: nil, attributes: attributes, mediaReference: nil, explicitPartialReference: nil) } if let todo = media.media as? TelegramMediaTodo { var flags: Int32 = 0 diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 580736c8fb..dddc9d148b 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -4062,7 +4062,7 @@ func replayFinalState( }) } switch action.action { - case let .setChatTheme(emoticon): + case let .setChatTheme(chatTheme): transaction.updatePeerCachedData(peerIds: [message.id.peerId], update: { peerId, current in var current = current if current == nil { @@ -4075,11 +4075,11 @@ func replayFinalState( } } if let cachedData = current as? CachedUserData { - return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil) + return cachedData.withUpdatedChatTheme(!chatTheme.isEmpty ? chatTheme : nil) } else if let cachedData = current as? CachedGroupData { - return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil) + return cachedData.withUpdatedChatTheme(!chatTheme.isEmpty ? chatTheme : nil) } else if let cachedData = current as? CachedChannelData { - return cachedData.withUpdatedThemeEmoticon(!emoticon.isEmpty ? emoticon : nil) + return cachedData.withUpdatedChatTheme(!chatTheme.isEmpty ? chatTheme : nil) } else { return current } diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index 5e5b2099fc..6989c18fe8 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -1537,7 +1537,7 @@ public final class AccountViewTracker { let peerId = slice[i].0 let value = result[i] transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, cachedData in - var cachedData = cachedData as? CachedUserData ?? CachedUserData(about: nil, botInfo: nil, editableBotInfo: nil, peerStatusSettings: nil, pinnedMessageId: nil, isBlocked: false, commonGroupCount: 0, voiceCallsAvailable: true, videoCallsAvailable: true, callsPrivate: true, canPinMessages: true, hasScheduledMessages: true, autoremoveTimeout: .unknown, themeEmoticon: nil, photo: .unknown, personalPhoto: .unknown, fallbackPhoto: .unknown, voiceMessagesAvailable: true, wallpaper: nil, flags: [], businessHours: nil, businessLocation: nil, greetingMessage: nil, awayMessage: nil, connectedBot: nil, businessIntro: .unknown, birthday: nil, personalChannel: .unknown, botPreview: nil, starGiftsCount: nil, starRefProgram: nil, verification: nil, sendPaidMessageStars: nil, disallowedGifts: [], botGroupAdminRights: nil, botChannelAdminRights: nil, starRating: nil, pendingStarRating: nil, linkedBotChannelId: .unknown, mainProfileTab: nil, savedMusic: nil) + var cachedData = cachedData as? CachedUserData ?? CachedUserData(about: nil, botInfo: nil, editableBotInfo: nil, peerStatusSettings: nil, pinnedMessageId: nil, isBlocked: false, commonGroupCount: 0, voiceCallsAvailable: true, videoCallsAvailable: true, callsPrivate: true, canPinMessages: true, hasScheduledMessages: true, autoremoveTimeout: .unknown, chatTheme: nil, photo: .unknown, personalPhoto: .unknown, fallbackPhoto: .unknown, voiceMessagesAvailable: true, wallpaper: nil, flags: [], businessHours: nil, businessLocation: nil, greetingMessage: nil, awayMessage: nil, connectedBot: nil, businessIntro: .unknown, birthday: nil, personalChannel: .unknown, botPreview: nil, starGiftsCount: nil, starRefProgram: nil, verification: nil, sendPaidMessageStars: nil, disallowedGifts: [], botGroupAdminRights: nil, botChannelAdminRights: nil, starRating: nil, pendingStarRating: nil, linkedBotChannelId: .unknown, mainProfileTab: nil, savedMusic: nil) var flags = cachedData.flags var sendPaidMessageStars = cachedData.sendPaidMessageStars switch value { diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index 1de180df61..3531566048 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 214 + return 215 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift index cb925aece0..6ccc080f08 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedChannelData.swift @@ -259,7 +259,7 @@ public final class CachedChannelData: CachedPeerData { public let activeCall: ActiveCall? public let callJoinPeerId: PeerId? public let pendingSuggestions: [String] - public let themeEmoticon: String? + public let chatTheme: ChatTheme? public let inviteRequestsPending: Int32? public let sendAsPeerId: PeerId? public let reactionSettings: EnginePeerCachedInfoItem @@ -307,7 +307,7 @@ public final class CachedChannelData: CachedPeerData { self.activeCall = nil self.callJoinPeerId = nil self.pendingSuggestions = [] - self.themeEmoticon = nil + self.chatTheme = nil self.inviteRequestsPending = nil self.sendAsPeerId = nil self.reactionSettings = .unknown @@ -348,7 +348,7 @@ public final class CachedChannelData: CachedPeerData { callJoinPeerId: PeerId?, autoremoveTimeout: CachedPeerAutoremoveTimeout, pendingSuggestions: [String], - themeEmoticon: String?, + chatTheme: ChatTheme?, inviteRequestsPending: Int32?, sendAsPeerId: PeerId?, reactionSettings: EnginePeerCachedInfoItem, @@ -387,7 +387,7 @@ public final class CachedChannelData: CachedPeerData { self.callJoinPeerId = callJoinPeerId self.autoremoveTimeout = autoremoveTimeout self.pendingSuggestions = pendingSuggestions - self.themeEmoticon = themeEmoticon + self.chatTheme = chatTheme self.inviteRequestsPending = inviteRequestsPending self.sendAsPeerId = sendAsPeerId self.reactionSettings = reactionSettings @@ -428,155 +428,155 @@ public final class CachedChannelData: CachedPeerData { } public func withUpdatedIsNotAccessible(_ isNotAccessible: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedAbout(_ about: String?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedMigrationReference(_ migrationReference: ChannelMigrationReference?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedLinkedDiscussionPeerId(_ linkedDiscussionPeerId: LinkedDiscussionPeerId) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedPeerGeoLocation(_ peerGeoLocation: PeerGeoLocation?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedSlowModeTimeout(_ slowModeTimeout: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedSlowModeValidUntilTimestamp(_ slowModeValidUntilTimestamp: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedStatsDatacenterId(_ statsDatacenterId: Int32) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedInvitedOn(_ invitedOn: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedActiveCall(_ activeCall: ActiveCall?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedCallJoinPeerId(_ callJoinPeerId: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedAutoremoveTimeout(_ autoremoveTimeout: CachedPeerAutoremoveTimeout) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: autoremoveTimeout, pendingSuggestions: self.pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedPendingSuggestions(_ pendingSuggestions: [String]) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } - public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + public func withUpdatedChatTheme(_ chatTheme: ChatTheme?) -> CachedChannelData { + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedInviteRequestsPending(_ inviteRequestsPending: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedSendAsPeerId(_ sendAsPeerId: PeerId?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedReactionSettings(_ reactionSettings: EnginePeerCachedInfoItem) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedMembersHidden(_ membersHidden: EnginePeerCachedInfoItem) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedViewForumAsMessages(_ viewForumAsMessages: EnginePeerCachedInfoItem) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedWallpaper(_ wallpaper: TelegramWallpaper?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedBoostsToUnrestrict(_ boostsToUnrestrict: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedAppliedBoosts(_ appliedBoosts: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedEmojiPack(_ emojiPack: StickerPackCollectionInfo?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedVerification(_ verification: PeerVerification?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedStarGiftsCount(_ starGiftsCount: Int32?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedSendPaidMessageStars(_ sendPaidMessageStars: StarsAmount?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: sendPaidMessageStars, mainProfileTab: self.mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: sendPaidMessageStars, mainProfileTab: self.mainProfileTab) } public func withUpdatedMainProfileTab(_ mainProfileTab: TelegramProfileTab?) -> CachedChannelData { - return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: mainProfileTab) + return CachedChannelData(isNotAccessible: self.isNotAccessible, flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId, migrationReference: self.migrationReference, linkedDiscussionPeerId: self.linkedDiscussionPeerId, peerGeoLocation: self.peerGeoLocation, slowModeTimeout: self.slowModeTimeout, slowModeValidUntilTimestamp: self.slowModeValidUntilTimestamp, hasScheduledMessages: self.hasScheduledMessages, statsDatacenterId: self.statsDatacenterId, invitedBy: self.invitedBy, invitedOn: self.invitedOn, photo: self.photo, activeCall: self.activeCall, callJoinPeerId: self.callJoinPeerId, autoremoveTimeout: self.autoremoveTimeout, pendingSuggestions: pendingSuggestions, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, sendAsPeerId: self.sendAsPeerId, reactionSettings: self.reactionSettings, membersHidden: self.membersHidden, viewForumAsMessages: self.viewForumAsMessages, wallpaper: self.wallpaper, boostsToUnrestrict: self.boostsToUnrestrict, appliedBoosts: self.appliedBoosts, emojiPack: self.emojiPack, verification: self.verification, starGiftsCount: self.starGiftsCount, sendPaidMessageStars: self.sendPaidMessageStars, mainProfileTab: mainProfileTab) } public init(decoder: PostboxDecoder) { @@ -654,7 +654,13 @@ public final class CachedChannelData: CachedPeerData { self.pendingSuggestions = decoder.decodeStringArrayForKey("sug") - self.themeEmoticon = decoder.decodeOptionalStringForKey("te") + if let chatTheme = decoder.decodeCodable(ChatTheme.self, forKey: "ct") { + self.chatTheme = chatTheme + } else if let themeEmoticon = decoder.decodeOptionalStringForKey("te") { + self.chatTheme = .emoticon(themeEmoticon) + } else { + self.chatTheme = nil + } if let photo = decoder.decodeObjectForKey("ph", decoder: { TelegramMediaImage(decoder: $0) }) as? TelegramMediaImage { self.photo = photo @@ -837,10 +843,10 @@ public final class CachedChannelData: CachedPeerData { encoder.encodeStringArray(self.pendingSuggestions, forKey: "sug") - if let themeEmoticon = self.themeEmoticon, !themeEmoticon.isEmpty { - encoder.encodeString(themeEmoticon, forKey: "te") + if let chatTheme = self.chatTheme { + encoder.encodeCodable(chatTheme, forKey: "ct") } else { - encoder.encodeNil(forKey: "te") + encoder.encodeNil(forKey: "ct") } if let inviteRequestsPending = self.inviteRequestsPending { @@ -1026,7 +1032,7 @@ public final class CachedChannelData: CachedPeerData { return false } - if other.themeEmoticon != self.themeEmoticon { + if other.chatTheme != self.chatTheme { return false } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift index 544760a6b3..b06eb7bd39 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedGroupData.swift @@ -139,7 +139,7 @@ public final class CachedGroupData: CachedPeerData { public let autoremoveTimeout: CachedPeerAutoremoveTimeout public let activeCall: CachedChannelData.ActiveCall? public let callJoinPeerId: PeerId? - public let themeEmoticon: String? + public let chatTheme: ChatTheme? public let inviteRequestsPending: Int32? public let reactionSettings: EnginePeerCachedInfoItem @@ -164,7 +164,7 @@ public final class CachedGroupData: CachedPeerData { self.autoremoveTimeout = .unknown self.activeCall = nil self.callJoinPeerId = nil - self.themeEmoticon = nil + self.chatTheme = nil self.inviteRequestsPending = nil self.reactionSettings = .unknown } @@ -183,7 +183,7 @@ public final class CachedGroupData: CachedPeerData { activeCall: CachedChannelData.ActiveCall?, autoremoveTimeout: CachedPeerAutoremoveTimeout, callJoinPeerId: PeerId?, - themeEmoticon: String?, + chatTheme: ChatTheme?, inviteRequestsPending: Int32?, reactionSettings: EnginePeerCachedInfoItem ) { @@ -200,7 +200,7 @@ public final class CachedGroupData: CachedPeerData { self.activeCall = activeCall self.autoremoveTimeout = autoremoveTimeout self.callJoinPeerId = callJoinPeerId - self.themeEmoticon = themeEmoticon + self.chatTheme = chatTheme self.inviteRequestsPending = inviteRequestsPending self.reactionSettings = reactionSettings @@ -263,7 +263,13 @@ public final class CachedGroupData: CachedPeerData { self.callJoinPeerId = decoder.decodeOptionalInt64ForKey("callJoinPeerId").flatMap(PeerId.init) - self.themeEmoticon = decoder.decodeOptionalStringForKey("te") + if let chatTheme = decoder.decodeCodable(ChatTheme.self, forKey: "ct") { + self.chatTheme = chatTheme + } else if let themeEmoticon = decoder.decodeOptionalStringForKey("te") { + self.chatTheme = .emoticon(themeEmoticon) + } else { + self.chatTheme = nil + } self.inviteRequestsPending = decoder.decodeOptionalInt32ForKey("irp") @@ -357,10 +363,10 @@ public final class CachedGroupData: CachedPeerData { encoder.encodeNil(forKey: "callJoinPeerId") } - if let themeEmoticon = self.themeEmoticon, !themeEmoticon.isEmpty { - encoder.encodeString(themeEmoticon, forKey: "te") + if let chatTheme = self.chatTheme { + encoder.encodeCodable(chatTheme, forKey: "ct") } else { - encoder.encodeNil(forKey: "te") + encoder.encodeNil(forKey: "ct") } if let inviteRequestsPending = self.inviteRequestsPending { @@ -394,70 +400,70 @@ public final class CachedGroupData: CachedPeerData { return false } - return self.participants == other.participants && self.exportedInvitation == other.exportedInvitation && self.botInfos == other.botInfos && self.peerStatusSettings == other.peerStatusSettings && self.pinnedMessageId == other.pinnedMessageId && self.about == other.about && self.flags == other.flags && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.invitedBy == other.invitedBy && self.themeEmoticon == other.themeEmoticon && self.inviteRequestsPending == other.inviteRequestsPending + return self.participants == other.participants && self.exportedInvitation == other.exportedInvitation && self.botInfos == other.botInfos && self.peerStatusSettings == other.peerStatusSettings && self.pinnedMessageId == other.pinnedMessageId && self.about == other.about && self.flags == other.flags && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.invitedBy == other.invitedBy && self.chatTheme == other.chatTheme && self.inviteRequestsPending == other.inviteRequestsPending } public func withUpdatedParticipants(_ participants: CachedGroupParticipants?) -> CachedGroupData { - return CachedGroupData(participants: participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedAbout(_ about: String?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedFlags(_ flags: CachedGroupFlags) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedInvitedBy(_ invitedBy: PeerId?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedPhoto(_ photo: TelegramMediaImage?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedActiveCall(_ activeCall: CachedChannelData.ActiveCall?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedAutoremoveTimeout(_ autoremoveTimeout: CachedPeerAutoremoveTimeout) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedCallJoinPeerId(_ callJoinPeerId: PeerId?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } - public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) + public func withUpdatedChatTheme(_ chatTheme: ChatTheme?) -> CachedGroupData { + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedInviteRequestsPending(_ inviteRequestsPending: Int32?) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: inviteRequestsPending, reactionSettings: self.reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: inviteRequestsPending, reactionSettings: self.reactionSettings) } public func withUpdatedReactionSettings(_ reactionSettings: EnginePeerCachedInfoItem) -> CachedGroupData { - return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, themeEmoticon: self.themeEmoticon, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: reactionSettings) + return CachedGroupData(participants: self.participants, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, about: self.about, flags: self.flags, hasScheduledMessages: self.hasScheduledMessages, invitedBy: self.invitedBy, photo: self.photo, activeCall: self.activeCall, autoremoveTimeout: self.autoremoveTimeout, callJoinPeerId: self.callJoinPeerId, chatTheme: self.chatTheme, inviteRequestsPending: self.inviteRequestsPending, reactionSettings: reactionSettings) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift index 78362448e0..8b27757362 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_CachedUserData.swift @@ -1113,7 +1113,7 @@ public final class CachedUserData: CachedPeerData { public let canPinMessages: Bool public let hasScheduledMessages: Bool public let autoremoveTimeout: CachedPeerAutoremoveTimeout - public let themeEmoticon: String? + public let chatTheme: ChatTheme? public let photo: CachedPeerProfilePhoto public let personalPhoto: CachedPeerProfilePhoto public let fallbackPhoto: CachedPeerProfilePhoto @@ -1160,7 +1160,7 @@ public final class CachedUserData: CachedPeerData { self.canPinMessages = false self.hasScheduledMessages = false self.autoremoveTimeout = .unknown - self.themeEmoticon = nil + self.chatTheme = nil self.photo = .unknown self.personalPhoto = .unknown self.fallbackPhoto = .unknown @@ -1192,7 +1192,7 @@ public final class CachedUserData: CachedPeerData { self.savedMusic = nil } - public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, themeEmoticon: String?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts?, botGroupAdminRights: TelegramChatAdminRights?, botChannelAdminRights: TelegramChatAdminRights?, starRating: TelegramStarRating?, pendingStarRating: TelegramStarPendingRating?, linkedBotChannelId: LinkedBotChannelId, mainProfileTab: TelegramProfileTab?, savedMusic: TelegramMediaFile?) { + public init(about: String?, botInfo: BotInfo?, editableBotInfo: EditableBotInfo?, peerStatusSettings: PeerStatusSettings?, pinnedMessageId: MessageId?, isBlocked: Bool, commonGroupCount: Int32, voiceCallsAvailable: Bool, videoCallsAvailable: Bool, callsPrivate: Bool, canPinMessages: Bool, hasScheduledMessages: Bool, autoremoveTimeout: CachedPeerAutoremoveTimeout, chatTheme: ChatTheme?, photo: CachedPeerProfilePhoto, personalPhoto: CachedPeerProfilePhoto, fallbackPhoto: CachedPeerProfilePhoto, voiceMessagesAvailable: Bool, wallpaper: TelegramWallpaper?, flags: CachedUserFlags, businessHours: TelegramBusinessHours?, businessLocation: TelegramBusinessLocation?, greetingMessage: TelegramBusinessGreetingMessage?, awayMessage: TelegramBusinessAwayMessage?, connectedBot: TelegramAccountConnectedBot?, businessIntro: CachedTelegramBusinessIntro, birthday: TelegramBirthday?, personalChannel: CachedTelegramPersonalChannel, botPreview: BotPreview?, starGiftsCount: Int32?, starRefProgram: TelegramStarRefProgram?, verification: PeerVerification?, sendPaidMessageStars: StarsAmount?, disallowedGifts: TelegramDisallowedGifts?, botGroupAdminRights: TelegramChatAdminRights?, botChannelAdminRights: TelegramChatAdminRights?, starRating: TelegramStarRating?, pendingStarRating: TelegramStarPendingRating?, linkedBotChannelId: LinkedBotChannelId, mainProfileTab: TelegramProfileTab?, savedMusic: TelegramMediaFile?) { self.about = about self.botInfo = botInfo self.editableBotInfo = editableBotInfo @@ -1206,7 +1206,7 @@ public final class CachedUserData: CachedPeerData { self.canPinMessages = canPinMessages self.hasScheduledMessages = hasScheduledMessages self.autoremoveTimeout = autoremoveTimeout - self.themeEmoticon = themeEmoticon + self.chatTheme = chatTheme self.photo = photo self.personalPhoto = personalPhoto self.fallbackPhoto = fallbackPhoto @@ -1268,7 +1268,14 @@ public final class CachedUserData: CachedPeerData { self.canPinMessages = decoder.decodeInt32ForKey("cpm", orElse: 0) != 0 self.hasScheduledMessages = decoder.decodeBoolForKey("hsm", orElse: false) self.autoremoveTimeout = decoder.decodeObjectForKey("artv", decoder: CachedPeerAutoremoveTimeout.init(decoder:)) as? CachedPeerAutoremoveTimeout ?? .unknown - self.themeEmoticon = decoder.decodeOptionalStringForKey("te") + + if let chatTheme = decoder.decodeCodable(ChatTheme.self, forKey: "ct") { + self.chatTheme = chatTheme + } else if let chatTheme = decoder.decodeOptionalStringForKey("te") { + self.chatTheme = .emoticon(chatTheme) + } else { + self.chatTheme = nil + } self.photo = decoder.decodeObjectForKey("phv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown self.personalPhoto = decoder.decodeObjectForKey("pphv", decoder: CachedPeerProfilePhoto.init(decoder:)) as? CachedPeerProfilePhoto ?? .unknown @@ -1372,10 +1379,11 @@ public final class CachedUserData: CachedPeerData { encoder.encodeInt32(self.canPinMessages ? 1 : 0, forKey: "cpm") encoder.encodeBool(self.hasScheduledMessages, forKey: "hsm") encoder.encodeObject(self.autoremoveTimeout, forKey: "artv") - if let themeEmoticon = self.themeEmoticon, !themeEmoticon.isEmpty { - encoder.encodeString(themeEmoticon, forKey: "te") + + if let chatTheme = self.chatTheme { + encoder.encodeCodable(chatTheme, forKey: "ct") } else { - encoder.encodeNil(forKey: "te") + encoder.encodeNil(forKey: "ct") } encoder.encodeObject(self.photo, forKey: "phv") @@ -1584,171 +1592,171 @@ public final class CachedUserData: CachedPeerData { return false } - return other.about == self.about && other.botInfo == self.botInfo && other.editableBotInfo == self.editableBotInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.themeEmoticon == other.themeEmoticon && self.photo == other.photo && self.personalPhoto == other.personalPhoto && self.fallbackPhoto == other.fallbackPhoto && self.voiceMessagesAvailable == other.voiceMessagesAvailable && self.flags == other.flags && self.wallpaper == other.wallpaper + return other.about == self.about && other.botInfo == self.botInfo && other.editableBotInfo == self.editableBotInfo && self.peerStatusSettings == other.peerStatusSettings && self.isBlocked == other.isBlocked && self.commonGroupCount == other.commonGroupCount && self.voiceCallsAvailable == other.voiceCallsAvailable && self.videoCallsAvailable == other.videoCallsAvailable && self.callsPrivate == other.callsPrivate && self.hasScheduledMessages == other.hasScheduledMessages && self.autoremoveTimeout == other.autoremoveTimeout && self.chatTheme == other.chatTheme && self.photo == other.photo && self.personalPhoto == other.personalPhoto && self.fallbackPhoto == other.fallbackPhoto && self.voiceMessagesAvailable == other.voiceMessagesAvailable && self.flags == other.flags && self.wallpaper == other.wallpaper } public func withUpdatedAbout(_ about: String?) -> CachedUserData { - return CachedUserData(about: about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBotInfo(_ botInfo: BotInfo?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedEditableBotInfo(_ editableBotInfo: EditableBotInfo?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPeerStatusSettings(_ peerStatusSettings: PeerStatusSettings) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedIsBlocked(_ isBlocked: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedCommonGroupCount(_ commonGroupCount: Int32) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedVoiceCallsAvailable(_ voiceCallsAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedVideoCallsAvailable(_ videoCallsAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedCallsPrivate(_ callsPrivate: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedCanPinMessages(_ canPinMessages: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedHasScheduledMessages(_ hasScheduledMessages: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedAutoremoveTimeout(_ autoremoveTimeout: CachedPeerAutoremoveTimeout) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } - public func withUpdatedThemeEmoticon(_ themeEmoticon: String?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + public func withUpdatedChatTheme(_ chatTheme: ChatTheme?) -> CachedUserData { + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPhoto(_ photo: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPersonalPhoto(_ personalPhoto: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedFallbackPhoto(_ fallbackPhoto: CachedPeerProfilePhoto) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedVoiceMessagesAvailable(_ voiceMessagesAvailable: Bool) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedWallpaper(_ wallpaper: TelegramWallpaper?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedFlags(_ flags: CachedUserFlags) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBusinessHours(_ businessHours: TelegramBusinessHours?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBusinessLocation(_ businessLocation: TelegramBusinessLocation?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedGreetingMessage(_ greetingMessage: TelegramBusinessGreetingMessage?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedAwayMessage(_ awayMessage: TelegramBusinessAwayMessage?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedConnectedBot(_ connectedBot: TelegramAccountConnectedBot?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBusinessIntro(_ businessIntro: TelegramBusinessIntro?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: .known(businessIntro), birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: .known(businessIntro), birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBirthday(_ birthday: TelegramBirthday?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPersonalChannel(_ personalChannel: TelegramPersonalChannel?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: .known(personalChannel), botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: .known(personalChannel), botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBotPreview(_ botPreview: BotPreview?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedStarGiftsCount(_ starGiftsCount: Int32?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedStarRefProgram(_ starRefProgram: TelegramStarRefProgram?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedVerification(_ verification: PeerVerification?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedSendPaidMessageStars(_ sendPaidMessageStars: StarsAmount?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: sendPaidMessageStars, disallowedGifts: self.disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedDisallowedGifts(_ disallowedGifts: TelegramDisallowedGifts) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBotGroupAdminRights(_ botGroupAdminRights: TelegramChatAdminRights?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedBotChannelAdminRights(_ botChannelAdminRights: TelegramChatAdminRights?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedStarRating(_ starRating: TelegramStarRating?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedPendingStarRating(_ pendingStarRating: TelegramStarPendingRating?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedLinkedBotChannelId(_ linkedBotChannelId: PeerId?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: .known(linkedBotChannelId), mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: .known(linkedBotChannelId), mainProfileTab: self.mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedMainProfileTab(_ mainProfileTab: TelegramProfileTab?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: mainProfileTab, savedMusic: self.savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: mainProfileTab, savedMusic: self.savedMusic) } public func withUpdatedSavedMusic(_ savedMusic: TelegramMediaFile?) -> CachedUserData { - return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, themeEmoticon: self.themeEmoticon, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: savedMusic) + return CachedUserData(about: self.about, botInfo: self.botInfo, editableBotInfo: self.editableBotInfo, peerStatusSettings: self.peerStatusSettings, pinnedMessageId: self.pinnedMessageId, isBlocked: self.isBlocked, commonGroupCount: self.commonGroupCount, voiceCallsAvailable: self.voiceCallsAvailable, videoCallsAvailable: self.videoCallsAvailable, callsPrivate: self.callsPrivate, canPinMessages: self.canPinMessages, hasScheduledMessages: self.hasScheduledMessages, autoremoveTimeout: self.autoremoveTimeout, chatTheme: self.chatTheme, photo: self.photo, personalPhoto: self.personalPhoto, fallbackPhoto: self.fallbackPhoto, voiceMessagesAvailable: self.voiceMessagesAvailable, wallpaper: self.wallpaper, flags: self.flags, businessHours: self.businessHours, businessLocation: self.businessLocation, greetingMessage: self.greetingMessage, awayMessage: self.awayMessage, connectedBot: self.connectedBot, businessIntro: self.businessIntro, birthday: self.birthday, personalChannel: self.personalChannel, botPreview: self.botPreview, starGiftsCount: self.starGiftsCount, starRefProgram: self.starRefProgram, verification: self.verification, sendPaidMessageStars: self.sendPaidMessageStars, disallowedGifts: disallowedGifts, botGroupAdminRights: self.botGroupAdminRights, botChannelAdminRights: self.botChannelAdminRights, starRating: self.starRating, pendingStarRating: self.pendingStarRating, linkedBotChannelId: self.linkedBotChannelId, mainProfileTab: self.mainProfileTab, savedMusic: savedMusic) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift index d94f674edb..d5be2f2137 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift @@ -388,8 +388,8 @@ public enum AnyMediaReference: Equatable { return nil case .starsTransaction: return nil - case .savedMusic: - return nil + case let .savedMusic(peer, _): + return .savedMusic(peer: peer) } } @@ -526,6 +526,7 @@ public enum PartialMediaReference: Equatable { case savedGif case savedSticker case recentSticker + case savedMusic } case message(message: MessageReference) @@ -534,6 +535,7 @@ public enum PartialMediaReference: Equatable { case savedGif case savedSticker case recentSticker + case savedMusic(peer: PeerReference) public init?(decoder: PostboxDecoder) { guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else { @@ -555,6 +557,9 @@ public enum PartialMediaReference: Equatable { self = .savedSticker case .recentSticker: self = .recentSticker + case .savedMusic: + let peer = decoder.decodeObjectForKey("pg", decoder: { PeerReference(decoder: $0) }) as! PeerReference + self = .savedMusic(peer: peer) } } @@ -575,6 +580,9 @@ public enum PartialMediaReference: Equatable { encoder.encodeInt32(CodingCase.savedSticker.rawValue, forKey: "_r") case .recentSticker: encoder.encodeInt32(CodingCase.recentSticker.rawValue, forKey: "_r") + case let .savedMusic(peer): + encoder.encodeInt32(CodingCase.savedMusic.rawValue, forKey: "_r") + encoder.encodeObject(peer, forKey: "pg") } } @@ -592,6 +600,8 @@ public enum PartialMediaReference: Equatable { return .savedSticker(media: media) case .recentSticker: return .recentSticker(media: media) + case let .savedMusic(peer): + return .savedMusic(peer: peer, media: media) } } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift index c083134b6e..881a0be6e0 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReferenceFlatBuffers.swift @@ -106,6 +106,15 @@ public extension PartialMediaReference { self = .savedSticker case .partialmediareferenceRecentsticker: self = .recentSticker + case .partialmediareferenceSavedmusic: + guard let value = flatBuffersObject.value(type: TelegramCore_PartialMediaReference_SavedMusic.self) else { + throw FlatBuffersError.missingRequiredField() + } + if let peer = value.peer { + self = .savedMusic(peer: try PeerReference(flatBuffersObject: peer)) + } else { + return nil + } case .none_: throw FlatBuffersError.missingRequiredField() } @@ -149,6 +158,12 @@ public extension PartialMediaReference { let start = TelegramCore_PartialMediaReference_RecentSticker.startPartialMediaReference_RecentSticker(&builder) valueType = .partialmediareferenceRecentsticker valueOffset = TelegramCore_PartialMediaReference_RecentSticker.endPartialMediaReference_RecentSticker(&builder, start: start) + case let .savedMusic(peer): + let peerOffset = peer.encodeToFlatBuffers(builder: &builder) + let start = TelegramCore_PartialMediaReference_SavedMusic.startPartialMediaReference_SavedMusic(&builder) + TelegramCore_PartialMediaReference_SavedMusic.add(peer: peerOffset, &builder) + valueType = .partialmediareferenceSavedmusic + valueOffset = TelegramCore_PartialMediaReference_SavedMusic.endPartialMediaReference_SavedMusic(&builder, start: start) } return TelegramCore_PartialMediaReference.createPartialMediaReference(&builder, valueType: valueType, valueOffset: valueOffset) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index b139bd2a3d..d9284622d8 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -146,6 +146,7 @@ public struct Namespaces { public static let groupCallPersistentSettings: Int8 = 47 public static let cachedProfileGiftsCollections: Int8 = 48 public static let cachedProfileSavedMusic: Int8 = 49 + public static let cachedChatThemes: Int8 = 50 } public struct UnorderedItemList { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_OutgoingMessageInfoAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_OutgoingMessageInfoAttribute.swift index eabe75a341..6f7c4e0220 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_OutgoingMessageInfoAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_OutgoingMessageInfoAttribute.swift @@ -21,13 +21,15 @@ public class OutgoingMessageInfoAttribute: MessageAttribute { public let acknowledged: Bool public let correlationId: Int64? public let bubbleUpEmojiOrStickersets: [ItemCollectionId] + public let partialReference: PartialMediaReference? - public init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool, correlationId: Int64?, bubbleUpEmojiOrStickersets: [ItemCollectionId]) { + public init(uniqueId: Int64, flags: OutgoingMessageInfoFlags, acknowledged: Bool, correlationId: Int64?, bubbleUpEmojiOrStickersets: [ItemCollectionId], partialReference: PartialMediaReference?) { self.uniqueId = uniqueId self.flags = flags self.acknowledged = acknowledged self.correlationId = correlationId self.bubbleUpEmojiOrStickersets = bubbleUpEmojiOrStickersets + self.partialReference = partialReference } required public init(decoder: PostboxDecoder) { @@ -40,6 +42,11 @@ public class OutgoingMessageInfoAttribute: MessageAttribute { } else { self.bubbleUpEmojiOrStickersets = [] } + if let partialReference = decoder.decodeAnyObjectForKey("partialReference", decoder: { PartialMediaReference(decoder: $0) }) as? PartialMediaReference { + self.partialReference = partialReference + } else { + self.partialReference = nil + } } public func encode(_ encoder: PostboxEncoder) { @@ -54,13 +61,18 @@ public class OutgoingMessageInfoAttribute: MessageAttribute { let bubbleUpEmojiOrStickersetsBuffer = WriteBuffer() ItemCollectionId.encodeArrayToBuffer(self.bubbleUpEmojiOrStickersets, buffer: bubbleUpEmojiOrStickersetsBuffer) encoder.encodeData(bubbleUpEmojiOrStickersetsBuffer.makeData(), forKey: "bubbleUpEmojiOrStickersets") + if let partialReference { + encoder.encodeObjectWithEncoder(partialReference, encoder: partialReference.encode, forKey: "partialReference") + } else { + encoder.encodeNil(forKey: "partialReference") + } } public func withUpdatedFlags(_ flags: OutgoingMessageInfoFlags) -> OutgoingMessageInfoAttribute { - return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged, correlationId: self.correlationId, bubbleUpEmojiOrStickersets: self.bubbleUpEmojiOrStickersets) + return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: flags, acknowledged: self.acknowledged, correlationId: self.correlationId, bubbleUpEmojiOrStickersets: self.bubbleUpEmojiOrStickersets, partialReference: self.partialReference) } public func withUpdatedAcknowledged(_ acknowledged: Bool) -> OutgoingMessageInfoAttribute { - return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged, correlationId: self.correlationId, bubbleUpEmojiOrStickersets: self.bubbleUpEmojiOrStickersets) + return OutgoingMessageInfoAttribute(uniqueId: self.uniqueId, flags: self.flags, acknowledged: acknowledged, correlationId: self.correlationId, bubbleUpEmojiOrStickersets: self.bubbleUpEmojiOrStickersets, partialReference: self.partialReference) } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift index 5e105452ed..bb6966c3a8 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift @@ -224,7 +224,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case geoProximityReached(from: PeerId, to: PeerId, distance: Int32) case groupPhoneCall(callId: Int64, accessHash: Int64, scheduleDate: Int32?, duration: Int32?) case inviteToGroupPhoneCall(callId: Int64, accessHash: Int64, peerIds: [PeerId]) - case setChatTheme(emoji: String) + case setChatTheme(chatTheme: ChatTheme) case joinedByRequest case webViewData(String) case giftPremium(currency: String, amount: Int64, months: Int32, cryptoCurrency: String?, cryptoAmount: Int64?, text: String?, entities: [MessageTextEntity]?) @@ -317,7 +317,13 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { } self = .inviteToGroupPhoneCall(callId: decoder.decodeInt64ForKey("callId", orElse: 0), accessHash: decoder.decodeInt64ForKey("accessHash", orElse: 0), peerIds: peerIds) case 24: - self = .setChatTheme(emoji: decoder.decodeStringForKey("emoji", orElse: "")) + if let chatTheme = decoder.decodeCodable(ChatTheme.self, forKey: "chatTheme") { + self = .setChatTheme(chatTheme: chatTheme) + } else if let emoji = decoder.decodeOptionalStringForKey("emoji"), !emoji.isEmpty { + self = .setChatTheme(chatTheme: .emoticon(emoji)) + } else { + self = .setChatTheme(chatTheme: .emoticon("")) + } case 25: self = .joinedByRequest case 26: @@ -534,9 +540,9 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { encoder.encodeInt64(callId, forKey: "callId") encoder.encodeInt64(accessHash, forKey: "accessHash") encoder.encodeInt64Array(peerIds.map { $0.toInt64() }, forKey: "peerIds") - case let .setChatTheme(emoji): + case let .setChatTheme(chatTheme): encoder.encodeInt32(24, forKey: "_rawValue") - encoder.encodeString(emoji, forKey: "emoji") + encoder.encodeCodable(chatTheme, forKey: "chatTheme") case .joinedByRequest: encoder.encodeInt32(25, forKey: "_rawValue") case let .webViewData(text): diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_UnauthorizedAccountState.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_UnauthorizedAccountState.swift index 20b3ca184b..7a43a6dea9 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_UnauthorizedAccountState.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_UnauthorizedAccountState.swift @@ -182,7 +182,7 @@ public indirect enum UnauthorizedAccountStateContents: PostboxCoding, Equatable case passwordRecovery(hint: String, number: String?, code: AuthorizationCode?, emailPattern: String, syncContacts: Bool) case awaitingAccountReset(protectedUntil: Int32, number: String?, syncContacts: Bool) case signUp(number: String, codeHash: String, firstName: String, lastName: String, termsOfService: UnauthorizedAccountTermsOfService?, syncContacts: Bool) - case payment(number: String, codeHash: String, storeProduct: String, syncContacts: Bool) + case payment(number: String, codeHash: String, storeProduct: String, supportEmailAddress: String, supportEmailSubject: String, syncContacts: Bool) public init(decoder: PostboxDecoder) { switch decoder.decodeInt32ForKey("v", orElse: 0) { @@ -217,7 +217,7 @@ public indirect enum UnauthorizedAccountStateContents: PostboxCoding, Equatable case UnauthorizedAccountStateContentsValue.signUp.rawValue: self = .signUp(number: decoder.decodeStringForKey("n", orElse: ""), codeHash: decoder.decodeStringForKey("h", orElse: ""), firstName: decoder.decodeStringForKey("f", orElse: ""), lastName: decoder.decodeStringForKey("l", orElse: ""), termsOfService: decoder.decodeObjectForKey("tos", decoder: { UnauthorizedAccountTermsOfService(decoder: $0) }) as? UnauthorizedAccountTermsOfService, syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) case UnauthorizedAccountStateContentsValue.payment.rawValue: - self = .payment(number: decoder.decodeStringForKey("n", orElse: ""), codeHash: decoder.decodeStringForKey("h", orElse: ""), storeProduct: decoder.decodeStringForKey("storeProduct", orElse: ""), syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) + self = .payment(number: decoder.decodeStringForKey("n", orElse: ""), codeHash: decoder.decodeStringForKey("h", orElse: ""), storeProduct: decoder.decodeStringForKey("storeProduct", orElse: ""), supportEmailAddress: decoder.decodeStringForKey("supportEmailAddress", orElse: ""), supportEmailSubject: decoder.decodeStringForKey("supportEmailSubject", orElse: ""), syncContacts: decoder.decodeInt32ForKey("syncContacts", orElse: 1) != 0) default: assertionFailure() self = .empty @@ -307,11 +307,13 @@ public indirect enum UnauthorizedAccountStateContents: PostboxCoding, Equatable encoder.encodeNil(forKey: "tos") } encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") - case let .payment(number, codeHash, storeProduct, syncContacts): + case let .payment(number, codeHash, storeProduct, supportEmailAddress, supportEmailSubject, syncContacts): encoder.encodeInt32(UnauthorizedAccountStateContentsValue.payment.rawValue, forKey: "v") encoder.encodeString(number, forKey: "n") encoder.encodeString(codeHash, forKey: "h") encoder.encodeString(storeProduct, forKey: "storeProduct") + encoder.encodeString(supportEmailAddress, forKey: "supportEmailAddress") + encoder.encodeString(supportEmailSubject, forKey: "supportEmailSubject") encoder.encodeInt32(syncContacts ? 1 : 0, forKey: "syncContacts") } } @@ -384,8 +386,8 @@ public indirect enum UnauthorizedAccountStateContents: PostboxCoding, Equatable } else { return false } - case let .payment(number, codeHash, storeProduct, syncContacts): - if case .payment(number, codeHash, storeProduct, syncContacts) = rhs { + case let .payment(number, codeHash, storeProduct, supportEmailAddress, supportEmailSubject, syncContacts): + if case .payment(number, codeHash, storeProduct, supportEmailAddress, supportEmailSubject, syncContacts) = rhs { return true } else { return false diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift index ccbf201a4a..eceaab249d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Data/PeersData.swift @@ -530,8 +530,8 @@ public extension TelegramEngine.EngineData.Item { } } - public struct ThemeEmoticon: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { - public typealias Result = Optional + public struct ChatTheme: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem { + public typealias Result = Optional fileprivate var id: EnginePeer.Id public var mapKey: EnginePeer.Id { @@ -554,11 +554,11 @@ public extension TelegramEngine.EngineData.Item { return nil } if let cachedData = cachedPeerData as? CachedUserData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedPeerData as? CachedGroupData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedPeerData as? CachedChannelData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else { return nil } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SavedMusic.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SavedMusic.swift index 5e0cb2082c..62dc50b2d3 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/SavedMusic.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/SavedMusic.swift @@ -127,13 +127,39 @@ func _internal_addSavedMusic(account: Account, file: FileMediaReference, afterFi return account.postbox.transaction { transaction in if let cachedSavedMusic = transaction.retrieveItemCacheEntry(id: entryId(peerId: account.peerId))?.get(CachedProfileSavedMusic.self) { var updatedFiles = cachedSavedMusic.files - updatedFiles.removeAll(where: { $0.fileId == file.media.fileId }) - if let afterFile, let index = updatedFiles.firstIndex(where: { $0.fileId == afterFile.media.fileId }) { - updatedFiles.insert(file.media, at: index + 1) + var updatedCount = cachedSavedMusic.count + + if let fromIndex = updatedFiles.firstIndex(where: { $0.fileId == file.media.fileId }) { + let anchorIdxOpt: Int? = afterFile.flatMap { af in + updatedFiles.firstIndex(where: { $0.fileId == af.media.fileId }) + } + updatedFiles.remove(at: fromIndex) + let insertIndex: Int + if let anchorIndex = anchorIdxOpt { + if anchorIndex == fromIndex { + insertIndex = min(fromIndex + 1, updatedFiles.count) + } else { + let adjustedAnchor = anchorIndex > fromIndex ? (anchorIndex - 1) : anchorIndex + insertIndex = updatedFiles.index(after: adjustedAnchor) + } + } else if afterFile != nil { + insertIndex = 0 + } else { + insertIndex = 0 + } + + updatedFiles.insert(file.media, at: insertIndex) } else { - updatedFiles.insert(file.media, at: 0) + if let afterFile, let anchor = updatedFiles.firstIndex(where: { $0.fileId == afterFile.media.fileId }) { + updatedFiles.insert(file.media, at: updatedFiles.index(after: anchor)) + } else if afterFile != nil { + updatedFiles.append(file.media) + } else { + updatedFiles.insert(file.media, at: 0) + } + updatedCount = updatedCount + 1 } - let updatedCount = max(0, cachedSavedMusic.count + 1) + if let entry = CodableEntry(CachedProfileSavedMusic(files: updatedFiles, count: updatedCount)) { transaction.putItemCacheEntry(id: entryId(peerId: account.peerId), entry: entry) } @@ -371,15 +397,43 @@ public final class ProfileSavedMusicContext { } public func addMusic(file: FileMediaReference, afterFile: FileMediaReference? = nil, apply: Bool = true) -> Signal { - self.files.removeAll(where: { $0.fileId == file.media.fileId }) - if let afterFile, let index = self.files.firstIndex(where: { $0.fileId == afterFile.media.fileId }) { - self.files.insert(file.media, at: index + 1) + var updatedFiles = self.files + + let fromIdx = updatedFiles.firstIndex { $0.fileId == file.media.fileId } + let anchorIdxOpt = afterFile.flatMap { af in + updatedFiles.firstIndex { $0.fileId == af.media.fileId } + } + + if let fromIdx = fromIdx { + updatedFiles.remove(at: fromIdx) + + let insertIdx: Int + if let anchorIdx = anchorIdxOpt { + if anchorIdx == fromIdx { + insertIdx = min(fromIdx + 1, updatedFiles.count) + } else { + let adjustedAnchor = anchorIdx > fromIdx ? (anchorIdx - 1) : anchorIdx + insertIdx = updatedFiles.index(after: adjustedAnchor) + } + } else if afterFile != nil { + insertIdx = updatedFiles.count + } else { + insertIdx = 0 + } + updatedFiles.insert(file.media, at: insertIdx) } else { - self.files.insert(file.media, at: 0) - } - if let count = self.count { - self.count = count + 1 + if let anchorIdx = anchorIdxOpt { + updatedFiles.insert(file.media, at: updatedFiles.index(after: anchorIdx)) + } else if afterFile != nil { + updatedFiles.append(file.media) + } else { + updatedFiles.insert(file.media, at: 0) + } + if let count = self.count { + self.count = count + 1 + } } + self.files = updatedFiles self.pushState() if apply { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift index 05101564a8..d7413fbd5d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/UpdateCachedPeerData.swift @@ -277,7 +277,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee previous = CachedUserData() } switch fullUser { - case let .userFull(userFullFlags, userFullFlags2, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullThemeEmoticon, _, groupAdminRights, channelAdminRights, userWallpaper, _, businessWorkHours, businessLocation, greetingMessage, awayMessage, businessIntro, birthday, personalChannelId, personalChannelMessage, starGiftsCount, starRefProgram, verification, sendPaidMessageStars, disallowedStarGifts, starsRating, starsMyPendingRating, starsMyPendingRatingDate, linkedBotChannelId, mainTab, savedMusic): + case let .userFull(userFullFlags, userFullFlags2, _, userFullAbout, userFullSettings, personalPhoto, profilePhoto, fallbackPhoto, _, userFullBotInfo, userFullPinnedMsgId, userFullCommonChatsCount, _, userFullTtlPeriod, userFullChatTheme, _, groupAdminRights, channelAdminRights, userWallpaper, _, businessWorkHours, businessLocation, greetingMessage, awayMessage, businessIntro, birthday, personalChannelId, personalChannelMessage, starGiftsCount, starRefProgram, verification, sendPaidMessageStars, disallowedStarGifts, starsRating, starsMyPendingRating, starsMyPendingRatingDate, linkedBotChannelId, mainTab, savedMusic): let botInfo = userFullBotInfo.flatMap(BotInfo.init(apiBotInfo:)) let isBlocked = (userFullFlags & (1 << 0)) != 0 let voiceCallsAvailable = (userFullFlags & (1 << 4)) != 0 @@ -436,6 +436,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee let mappedMainProfileTab = mainTab.flatMap { TelegramProfileTab(apiTab: $0) } let mappedSavedMusic = savedMusic.flatMap { telegramMediaFileFromApiDocument($0, altDocuments: nil) } + let mappedChatTheme: ChatTheme? = userFullChatTheme.flatMap { ChatTheme(apiChatTheme: $0) } + return previous.withUpdatedAbout(userFullAbout) .withUpdatedBotInfo(botInfo) .withUpdatedEditableBotInfo(editableBotInfo) @@ -449,7 +451,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee .withUpdatedPinnedMessageId(pinnedMessageId) .withUpdatedHasScheduledMessages(hasScheduledMessages) .withUpdatedAutoremoveTimeout(autoremoveTimeout) - .withUpdatedThemeEmoticon(userFullThemeEmoticon) + .withUpdatedChatTheme(mappedChatTheme) .withUpdatedPhoto(.known(photo)) .withUpdatedPersonalPhoto(.known(personalPhoto)) .withUpdatedFallbackPhoto(.known(fallbackPhoto)) @@ -583,6 +585,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee let mappedReactionSettings = PeerReactionSettings(allowedReactions: mappedAllowedReactions, maxReactionCount: reactionsLimit, starsAllowed: nil) + let mappedChatTheme: ChatTheme? = chatFullThemeEmoticon.flatMap { .emoticon($0) } + return previous.withUpdatedParticipants(participants) .withUpdatedExportedInvitation(exportedInvitation) .withUpdatedBotInfos(botInfos) @@ -594,7 +598,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee .withUpdatedPhoto(photo) .withUpdatedActiveCall(updatedActiveCall) .withUpdatedCallJoinPeerId(groupCallDefaultJoinAs?.peerId) - .withUpdatedThemeEmoticon(chatFullThemeEmoticon) + .withUpdatedChatTheme(mappedChatTheme) .withUpdatedInviteRequestsPending(chatFullRequestsPending) .withUpdatedAutoremoveTimeout(autoremoveTimeout) .withUpdatedReactionSettings(.known(mappedReactionSettings)) @@ -856,6 +860,8 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee let mappedMainProfileTab = mainTab.flatMap { TelegramProfileTab(apiTab: $0) } + let mappedChatTheme: ChatTheme? = themeEmoticon.flatMap { .emoticon($0) } + return previous.withUpdatedFlags(channelFlags) .withUpdatedAbout(about) .withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount)) @@ -878,7 +884,7 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee .withUpdatedCallJoinPeerId(groupcallDefaultJoinAs?.peerId) .withUpdatedAutoremoveTimeout(autoremoveTimeout) .withUpdatedPendingSuggestions(pendingSuggestions ?? []) - .withUpdatedThemeEmoticon(themeEmoticon) + .withUpdatedChatTheme(mappedChatTheme) .withUpdatedInviteRequestsPending(requestsPending) .withUpdatedSendAsPeerId(sendAsPeerId) .withUpdatedReactionSettings(.known(mappedReactionSettings)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift index 49798b8a9f..1ae68de5ff 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Themes/ChatThemes.swift @@ -31,6 +31,106 @@ public final class ChatThemes: Codable, Equatable { } } +public enum ChatTheme: Codable, Equatable { + case emoticon(String) + case gift(StarGift, TelegramMediaFile) + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + + let type = try container.decode(Int32.self, forKey: "_r") + switch type { + case 0: + self = .emoticon(try container.decode(String.self, forKey: "e")) + case 1: + self = .gift(try container.decode(StarGift.self, forKey: "g"), try container.decode(TelegramMediaFile.self, forKey: "w")) + default: + assertionFailure() + self = .emoticon("") + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: StringCodingKey.self) + + switch self { + case let .emoticon(emoticon): + try container.encode(0, forKey: "_r") + try container.encode(emoticon, forKey: "e") + case let .gift(gift, wallpaperFile): + try container.encode(1, forKey: "_r") + try container.encode(gift, forKey: "g") + try container.encode(wallpaperFile, forKey: "w") + } + } + + public static func ==(lhs: ChatTheme, rhs: ChatTheme) -> Bool { + switch lhs { + case let .emoticon(emoticon): + if case .emoticon(emoticon) = rhs { + return true + } else { + return false + } + case let .gift(lhsGift, lhsWallpaperFile): + if case let .gift(rhsGift, rhsWallpaperFile) = rhs { + return lhsGift == rhsGift && lhsWallpaperFile.fileId == rhsWallpaperFile.fileId + } else { + return false + } + } + } + + public var isEmpty: Bool { + if case .emoticon("") = self { + return true + } else { + return false + } + } + + public var id: String { + switch self { + case let .emoticon(emoticon): + return emoticon.strippedEmoji + case let .gift(gift, _): + if case let .unique(uniqueGift) = gift { + return uniqueGift.slug + } else { + fatalError() + } + } + } +} + +extension ChatTheme { + init?(apiChatTheme: Api.ChatTheme) { + switch apiChatTheme { + case let .chatTheme(emoticon): + self = .emoticon(emoticon) + case let .chatThemeUniqueGift(gift, wallpaperDocument): + guard let gift = StarGift(apiStarGift: gift), let wallpaperFile = telegramMediaFileFromApiDocument(wallpaperDocument, altDocuments: nil) else { + return nil + } + self = .gift(gift, wallpaperFile) + } + } + + var apiChatTheme: Api.InputChatTheme { + switch self { + case let .emoticon(emoticon): + return .inputChatTheme(emoticon: emoticon) + case let .gift(gift, _): + switch gift { + case let .unique(uniqueGift): + return .inputChatThemeUniqueGift(slug: uniqueGift.slug) + default: + fatalError() + } + } + } +} + func _internal_getChatThemes(accountManager: AccountManager, network: Network, forceUpdate: Bool = false, onlyCached: Bool = false) -> Signal<[TelegramTheme], NoError> { let fetch: ([TelegramTheme]?, Int64?) -> Signal<[TelegramTheme], NoError> = { current, hash in return network.request(Api.functions.account.getChatThemes(hash: hash ?? 0)) @@ -81,27 +181,31 @@ func _internal_getChatThemes(accountManager: AccountManager Signal { +func _internal_setChatTheme(account: Account, peerId: PeerId, chatTheme: ChatTheme?) -> Signal { return account.postbox.loadedPeerWithId(peerId) |> mapToSignal { peer in guard let inputPeer = apiInputPeer(peer) else { return .complete() } - return account.postbox.transaction { transaction -> Signal in transaction.updatePeerCachedData(peerIds: Set([peerId]), update: { _, current in if let current = current as? CachedUserData { - return current.withUpdatedThemeEmoticon(emoticon) + return current.withUpdatedChatTheme(chatTheme) } else if let current = current as? CachedGroupData { - return current.withUpdatedThemeEmoticon(emoticon) + return current.withUpdatedChatTheme(chatTheme) } else if let current = current as? CachedChannelData { - return current.withUpdatedThemeEmoticon(emoticon) + return current.withUpdatedChatTheme(chatTheme) } else { return current } }) - - return account.network.request(Api.functions.messages.setChatTheme(peer: inputPeer, emoticon: emoticon ?? "")) + let inputTheme: Api.InputChatTheme + if let chatTheme { + inputTheme = chatTheme.apiChatTheme + } else { + inputTheme = .inputChatThemeEmpty + } + return account.network.request(Api.functions.messages.setChatTheme(peer: inputPeer, theme: inputTheme)) |> `catch` { error in return .complete() } @@ -266,3 +370,148 @@ func _internal_setExistingChatWallpaper(account: Account, messageId: MessageId, } } } + + + + +private final class CachedUniqueGiftChatThemes: Codable { + enum CodingKeys: String, CodingKey { + case themes + } + + let themes: [ChatTheme] + + init(themes: [ChatTheme]) { + self.themes = themes + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.themes = try container.decode([ChatTheme].self, forKey: .themes) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.themes, forKey: .themes) + } +} + +private func entryId() -> ItemCacheEntryId { + let cacheKey = ValueBoxKey(length: 8) + cacheKey.setInt64(0, value: 0) + return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedChatThemes, key: cacheKey) +} + +public final class UniqueGiftChatThemesContext { + public struct State: Equatable { + public enum DataState: Equatable { + case loading + case ready(canLoadMore: Bool) + } + + public var themes: [ChatTheme] + public var dataState: DataState + } + + private let queue: Queue = .mainQueue() + private let account: Account + + private let disposable = MetaDisposable() + private let cacheDisposable = MetaDisposable() + + private var themes: [ChatTheme] = [] + private var nextOffset: Int32? + private var dataState: UniqueGiftChatThemesContext.State.DataState = .ready(canLoadMore: true) + + private let stateValue = Promise() + public var state: Signal { + return self.stateValue.get() + } + + public init(account: Account) { + self.account = account + + self.loadMore() + } + + deinit { + self.disposable.dispose() + self.cacheDisposable.dispose() + } + + public func reload() { + self.themes = [] + self.nextOffset = nil + self.dataState = .ready(canLoadMore: true) + self.loadMore(reload: true) + } + + public func loadMore(reload: Bool = false) { + let network = self.account.network + let postbox = self.account.postbox + let dataState = self.dataState + let offset = self.nextOffset + + guard case .ready(true) = dataState else { + return + } + if self.themes.isEmpty, !reload { + self.cacheDisposable.set((postbox.transaction { transaction -> CachedUniqueGiftChatThemes? in + return transaction.retrieveItemCacheEntry(id: entryId())?.get(CachedUniqueGiftChatThemes.self) + } |> deliverOn(self.queue)).start(next: { [weak self] cachedUniqueGiftChatThemes in + guard let self, let cachedUniqueGiftChatThemes else { + return + } + self.themes = cachedUniqueGiftChatThemes.themes + if case .loading = self.dataState { + self.pushState() + } + })) + } + + self.dataState = .loading + if !reload { + self.pushState() + } + + let signal = network.request(Api.functions.account.getUniqueGiftChatThemes(offset: offset ?? 0, limit: 32, hash: 0)) + |> map { result -> ([ChatTheme], Int32?) in + switch result { + case let .chatThemes(_, _, themes, nextOffset): + return (themes.compactMap { ChatTheme(apiChatTheme: $0) }, nextOffset) + case .chatThemesNotModified: + return ([], nil) + } + } + + self.disposable.set((signal + |> deliverOn(self.queue)).start(next: { [weak self] themes, nextOffset in + guard let self else { + return + } + if offset == 0 || reload { + self.themes = themes + self.cacheDisposable.set(self.account.postbox.transaction { transaction in + if let entry = CodableEntry(CachedUniqueGiftChatThemes(themes: themes)) { + transaction.putItemCacheEntry(id: entryId(), entry: entry) + } + }.start()) + } else { + self.themes.append(contentsOf: themes) + } + + self.dataState = .ready(canLoadMore: nextOffset != nil) + self.pushState() + })) + } + + private func pushState() { + let state = State( + themes: self.themes, + dataState: self.dataState + ) + self.stateValue.set(.single(state)) + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Themes/TelegramEngineThemes.swift b/submodules/TelegramCore/Sources/TelegramEngine/Themes/TelegramEngineThemes.swift index 8e8ea3b097..b6b890c3a7 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Themes/TelegramEngineThemes.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Themes/TelegramEngineThemes.swift @@ -13,8 +13,8 @@ public extension TelegramEngine { return _internal_getChatThemes(accountManager: accountManager, network: self.account.network, forceUpdate: forceUpdate, onlyCached: onlyCached) } - public func setChatTheme(peerId: PeerId, emoticon: String?) -> Signal { - return _internal_setChatTheme(account: self.account, peerId: peerId, emoticon: emoticon) + public func setChatTheme(peerId: PeerId, chatTheme: ChatTheme?) -> Signal { + return _internal_setChatTheme(account: self.account, peerId: peerId, chatTheme: chatTheme) } public func setChatWallpaper(peerId: PeerId, wallpaper: TelegramWallpaper?, forBoth: Bool) -> Signal { diff --git a/submodules/TelegramStringFormatting/Sources/CurrencyFormat.swift b/submodules/TelegramStringFormatting/Sources/CurrencyFormat.swift index 3733889b57..2b81e47ed7 100644 --- a/submodules/TelegramStringFormatting/Sources/CurrencyFormat.swift +++ b/submodules/TelegramStringFormatting/Sources/CurrencyFormat.swift @@ -156,6 +156,23 @@ public func currencyToFractionalAmount(value: Int64, currency: String) -> Double return Double(value) / factor } +private func formatIntegerWithThousandsSeparator(_ number: Int64, separator: String) -> String { + if number == 0 { + return "0" + } + let numberString = String(number) + var result = "" + let digits = Array(numberString) + for (index, digit) in digits.enumerated() { + let remainingDigits = digits.count - index + if remainingDigits % 3 == 0 && index > 0 { + result.append(separator) + } + result.append(digit) + } + return result +} + public func formatCurrencyAmount(_ amount: Int64, currency: String) -> String { if let entry = currencyFormatterEntries[currency] ?? currencyFormatterEntries["USD"] { var result = "" @@ -177,12 +194,13 @@ public func formatCurrencyAmount(_ amount: Int64, currency: String) -> String { fractional.append(Character(scalar)) } } - result.append("\(integerPart)") + let integerString = formatIntegerWithThousandsSeparator(integerPart, separator: entry.thousandsSeparator) + result.append(integerString) if !fractional.isEmpty { result.append(entry.decimalSeparator) - } - for i in 0 ..< fractional.count { - result.append(fractional[fractional.count - i - 1]) + for i in 0 ..< fractional.count { + result.append(fractional[fractional.count - i - 1]) + } } if !entry.symbolOnLeft { if entry.spaceBetweenAmountAndSymbol { @@ -190,7 +208,6 @@ public func formatCurrencyAmount(_ amount: Int64, currency: String) -> String { } result.append(entry.symbol) } - return result } else { assertionFailure() diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 96323a3236..32f5110a72 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -767,8 +767,8 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) - case let .setChatTheme(emoji): - if emoji.isEmpty { + case let .setChatTheme(chatTheme): + if chatTheme.isEmpty { if message.author?.id.namespace == Namespaces.Peer.CloudChannel { attributedString = NSAttributedString(string: strings.Notification_ChannelDisabledTheme, font: titleFont, textColor: primaryTextColor) } else if message.author?.id == accountPeerId { @@ -779,13 +779,34 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) } } else { + var emoji = "" + var additionalAttributes: [String: Any] = [:] + switch chatTheme { + case let .emoticon(emoticon): + emoji = emoticon + case let .gift(starGift, _): + var file: TelegramMediaFile? + if case let .unique(uniqueGift) = starGift { + for attribute in uniqueGift.attributes { + if case let .model(_, fileValue, _) = attribute { + file = fileValue + break + } + } + } + if let file { + additionalAttributes[ChatTextInputAttributes.customEmoji.rawValue] = ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file, custom: nil) + } + } + let emojiAttributes = MarkdownAttributeSet(font: titleFont, textColor: primaryTextColor, additionalAttributes: additionalAttributes) if message.author?.id.namespace == Namespaces.Peer.CloudChannel { attributedString = NSAttributedString(string: strings.Notification_ChannelChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor) } else if message.author?.id == accountPeerId { - attributedString = NSAttributedString(string: strings.Notification_YouChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor) + let resultTitleString = strings.Notification_YouChangedTheme(emoji) + attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: emojiAttributes]) } else { let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji) - attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) + attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes, 1: emojiAttributes]) } } case let .webViewData(text): @@ -1134,7 +1155,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, attributedString = mutableString case .prizeStars: attributedString = NSAttributedString(string: strings.Notification_StarsPrize, font: titleFont, textColor: primaryTextColor) - case let .starGift(gift, _, text, entities, _, _, _, _, _, upgradeStars, _, isPrepaidUpgrade, _, peerId, senderId, _, _, _): + case let .starGift(gift, _, text, entities, _, _, _, _, _, upgradeStars, _, isPrepaidUpgrade, _, peerId, senderId, _, _, _, _): if !forAdditionalServiceMessage { if let text { let mutableAttributedString = NSMutableAttributedString(attributedString: stringWithAppliedEntities(text, entities: entities ?? [], baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false, message: message._asMessage())) diff --git a/submodules/TelegramUI/BUILD b/submodules/TelegramUI/BUILD index 60c67bc72d..2f5be92e7b 100644 --- a/submodules/TelegramUI/BUILD +++ b/submodules/TelegramUI/BUILD @@ -484,6 +484,7 @@ swift_library( "//submodules/TelegramUI/Components/SuggestedPostApproveAlert", "//submodules/TelegramUI/Components/Stars/BalanceNeededScreen", "//submodules/TelegramUI/Components/FaceScanScreen", + "//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist", "//submodules/ContactsHelper", ] + select({ "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift index 4525e1e69c..228acde43e 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageGiftBubbleContentNode/Sources/ChatMessageGiftBubbleContentNode.swift @@ -274,7 +274,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { for media in item.message.media { if let action = media as? TelegramMediaAction { switch action.action { - case let .starGift(gift, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + case let .starGift(gift, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): releasedBy = gift.releasedBy case let .starGiftUnique(gift, _, _, _, _, _, _, _, _, _, _, _, _, _): releasedBy = gift.releasedBy @@ -547,7 +547,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode { buttonTitle = item.presentationData.strings.Notification_PremiumPrize_View hasServiceMessage = false } - case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, isPrepaidUpgrade, _, channelPeerId, senderPeerId, _, _, _): + case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, isPrepaidUpgrade, _, channelPeerId, senderPeerId, _, _, _, _): if case let .generic(gift) = gift { if let releasedBy = gift.releasedBy, let peer = item.message.peers[releasedBy], let addressName = peer.addressName { creatorButtonTitle = item.presentationData.strings.Notification_StarGift_ReleasedBy("**@\(addressName)**").string diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode/Sources/ChatMessageInteractiveFileNode.swift index e5e3182af4..60857c7020 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveFileNode/Sources/ChatMessageInteractiveFileNode.swift @@ -623,15 +623,15 @@ public final class ChatMessageInteractiveFileNode: ASDisplayNode { |> map { resourceStatus, actualFetchStatus -> (FileMediaResourceStatus, MediaResourceStatus?) in return (resourceStatus, actualFetchStatus) } - updatedAudioLevelEventsSignal = messageFileMediaPlaybackAudioLevelEvents(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false) + updatedAudioLevelEventsSignal = messageFileMediaPlaybackAudioLevelEvents(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false, isSavedMusic: false) } else { updatedStatusSignal = messageFileMediaResourceStatus(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions) |> map { resourceStatus -> (FileMediaResourceStatus, MediaResourceStatus?) in return (resourceStatus, nil) } - updatedAudioLevelEventsSignal = messageFileMediaPlaybackAudioLevelEvents(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false) + updatedAudioLevelEventsSignal = messageFileMediaPlaybackAudioLevelEvents(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false, isSavedMusic: false) } - updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false) + updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: arguments.context, file: arguments.file, message: EngineMessage(arguments.message), isRecentActions: arguments.isRecentActions, isGlobalSearch: false, isDownloadList: false, isSavedMusic: false) } var isAudio = false diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode/Sources/ChatMessageInteractiveInstantVideoNode.swift index 1ec33a7f1c..b4605b04f0 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageInteractiveInstantVideoNode/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -1469,7 +1469,7 @@ public class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { playbackStatusNode.position = playbackStatusFrame.center } - let status = messageFileMediaPlaybackStatus(context: item.context, file: file, message: EngineMessage(item.message), isRecentActions: item.associatedData.isRecentActions, isGlobalSearch: false, isDownloadList: false) + let status = messageFileMediaPlaybackStatus(context: item.context, file: file, message: EngineMessage(item.message), isRecentActions: item.associatedData.isRecentActions, isGlobalSearch: false, isDownloadList: false, isSavedMusic: false) playbackStatusNode.status = status self.durationNode?.status = status |> map(Optional.init) diff --git a/submodules/TelegramUI/Components/Chat/ChatQrCodeScreen/Sources/ChatQrCodeScreen.swift b/submodules/TelegramUI/Components/Chat/ChatQrCodeScreen/Sources/ChatQrCodeScreen.swift index e73799fb9f..1871012fc6 100644 --- a/submodules/TelegramUI/Components/Chat/ChatQrCodeScreen/Sources/ChatQrCodeScreen.swift +++ b/submodules/TelegramUI/Components/Chat/ChatQrCodeScreen/Sources/ChatQrCodeScreen.swift @@ -1041,7 +1041,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, ASScrollViewDeleg let sharedData = self.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]) |> take(1) if case let .peer(peer, _, _) = controller.subject, peer.id != self.context.account.peerId { - let themeEmoticon = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThemeEmoticon(id: peer.id)) + let themeEmoticon = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ChatTheme(id: peer.id)) initiallySelectedEmoticon = combineLatest(themeEmoticon, sharedData) |> map { themeEmoticon, sharedData -> String in let themeSettings: PresentationThemeSettings @@ -1051,8 +1051,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, ASScrollViewDeleg themeSettings = PresentationThemeSettings.defaultSettings } let currentDefaultEmoticon = themeSettings.theme.emoticon ?? defaultEmoticon - - return themeEmoticon ?? currentDefaultEmoticon + return themeEmoticon?.id ?? currentDefaultEmoticon } } else { initiallySelectedEmoticon = sharedData diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift index 395378a09d..d267817ca8 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsController.swift @@ -189,31 +189,43 @@ public final class ChatRecentActionsController: TelegramBaseController { self.titleView.title = CounterControllerTitle(title: EnginePeer(peer).compactDisplayTitle, counter: self.presentationData.strings.Channel_AdminLog_TitleAllEvents) - let themeEmoticon = self.context.account.postbox.peerView(id: peer.id) - |> map { view -> String? in + let chatTheme = self.context.account.postbox.peerView(id: peer.id) + |> map { view -> ChatTheme? in let cachedData = view.cachedData if let cachedData = cachedData as? CachedUserData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedData as? CachedGroupData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedData as? CachedChannelData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else { return nil } } |> distinctUntilChanged - self.presentationDataDisposable = combineLatest(queue: Queue.mainQueue(), context.sharedContext.presentationData, context.engine.themes.getChatThemes(accountManager: context.sharedContext.accountManager, onlyCached: true), themeEmoticon).startStrict(next: { [weak self] presentationData, chatThemes, themeEmoticon in + self.presentationDataDisposable = combineLatest( + queue: Queue.mainQueue(), + context.sharedContext.presentationData, + context.engine.themes.getChatThemes(accountManager: context.sharedContext.accountManager, onlyCached: true), + chatTheme + ).startStrict(next: { [weak self] presentationData, chatThemes, chatTheme in if let strongSelf = self { let previousTheme = strongSelf.presentationData.theme let previousStrings = strongSelf.presentationData.strings var presentationData = presentationData - if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon == themeEmoticon }) { - if let theme = makePresentationTheme(cloudTheme: theme, dark: presentationData.theme.overallDarkAppearance) { - presentationData = presentationData.withUpdated(theme: theme) - presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper) + if let chatTheme { + switch chatTheme { + case let .emoticon(emoticon): + if let theme = chatThemes.first(where: { $0.emoticon == emoticon }), let theme = makePresentationTheme(cloudTheme: theme, dark: presentationData.theme.overallDarkAppearance) { + presentationData = presentationData.withUpdated(theme: theme) + presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper) + } + case let .gift(gift, wallpaper): + let _ = gift + let _ = wallpaper + //TODO:release } } diff --git a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift index efb36b911a..46503735dc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendStarsScreen/Sources/ChatSendStarsScreen.swift @@ -1426,8 +1426,8 @@ private final class ChatSendStarsScreenComponent: Component { self.environment?.controller()?.dismiss() let _ = (context.engine.payments.starsTopUpOptions() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { options in + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { options in let controller = context.sharedContext.makeStarsPurchaseScreen( context: context, starsContext: starsContext, diff --git a/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/BUILD b/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/BUILD index ab8dc02d74..9579870f15 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/BUILD +++ b/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/BUILD @@ -28,6 +28,7 @@ swift_library( "//submodules/TelegramUI/Components/EmojiStatusComponent", "//submodules/AnimatedStickerNode", "//submodules/TelegramAnimatedStickerNode", + "//submodules/UIKitRuntimeUtils", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/Sources/GiftCompositionComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/Sources/GiftCompositionComponent.swift index 2f3eb20f16..78fe8a36ad 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/Sources/GiftCompositionComponent.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftAnimationComponent/Sources/GiftCompositionComponent.swift @@ -13,6 +13,7 @@ import PeerInfoCoverComponent import AnimatedStickerNode import TelegramAnimatedStickerNode import EmojiStatusComponent +import UIKitRuntimeUtils public final class GiftCompositionComponent: Component { public class ExternalState { @@ -24,7 +25,7 @@ public final class GiftCompositionComponent: Component { public enum Subject: Equatable { case generic(TelegramMediaFile) - case unique(StarGift.UniqueGift) + case unique([StarGift.UniqueGift.Attribute]?, StarGift.UniqueGift) case preview([StarGift.UniqueGift.Attribute]) } @@ -34,8 +35,9 @@ public final class GiftCompositionComponent: Component { let animationOffset: CGPoint? let animationScale: CGFloat? let displayAnimationStars: Bool + let revealedAttributes: Set let externalState: ExternalState? - let requestUpdate: () -> Void + let requestUpdate: (ComponentTransition) -> Void public init( context: AccountContext, @@ -44,8 +46,9 @@ public final class GiftCompositionComponent: Component { animationOffset: CGPoint? = nil, animationScale: CGFloat? = nil, displayAnimationStars: Bool = false, + revealedAttributes: Set = Set(), externalState: ExternalState? = nil, - requestUpdate: @escaping () -> Void = {} + requestUpdate: @escaping (ComponentTransition) -> Void = { _ in } ) { self.context = context self.theme = theme @@ -53,6 +56,7 @@ public final class GiftCompositionComponent: Component { self.animationOffset = animationOffset self.animationScale = animationScale self.displayAnimationStars = displayAnimationStars + self.revealedAttributes = revealedAttributes self.externalState = externalState self.requestUpdate = requestUpdate } @@ -76,6 +80,9 @@ public final class GiftCompositionComponent: Component { if lhs.displayAnimationStars != rhs.displayAnimationStars { return false } + if lhs.revealedAttributes != rhs.revealedAttributes { + return false + } return true } @@ -102,10 +109,43 @@ public final class GiftCompositionComponent: Component { private var previewBackdropIndex: Int32 = 0 private var previewPatternIndex: Int32 = 0 private var animatePreviewTransition = false + private var animateBackdropSwipe = false + private enum SpinState { case idle, spinning, decelerating, settled } + private var spinState: SpinState = .idle + private var spinLink: SharedDisplayLinkDriver.Link? + private var lastSpawnTime: CFTimeInterval? + private var lastPatternChangeTime: CFTimeInterval? + private var lastBackdropChangeTime: CFTimeInterval? + private var currentInterval: Double = 0.0 + + private var deceleraionQueue: [StarGift.UniqueGift.Attribute] = [] + private var decelerationTotalSteps: Int = 0 + private var decelerationStepIndex: Int = 0 + private var decelContainer: UIView? + private var decelItemHosts: [UIView] = [] + private let decelAnimationKey = "decel.container.move" + + private var activeWrappers: [UIView] = [] + + private struct SpinGeom { + var availableSize: CGSize + var iconSize: CGSize + var scale: CGFloat + var centerX: CGFloat + var centerY: CGFloat + } + private var spinGeom: SpinGeom? + + private var spinPool: [StarGift.UniqueGift.Attribute] = [] + private var spinPoolIndex: Int = 0 + + private let baseAnimDuration: Double = 0.4 + private let maxAnimDuration: Double = 1.3 + private let spacingX: CGFloat = 50.0 + override init(frame: CGRect) { super.init(frame: frame) - self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.handleTap))) } @@ -115,17 +155,443 @@ public final class GiftCompositionComponent: Component { deinit { self.disposables.dispose() + self.previewTimer?.invalidate() } @objc private func handleTap() { - guard let animationNode = animationNode as? DefaultAnimatedStickerNodeImpl else { - return - } + guard let animationNode = animationNode as? DefaultAnimatedStickerNodeImpl else { return } if case .once = animationNode.playbackMode, !animationNode.isPlaying { animationNode.playOnce() } } + private func stopSpinIfNeeded() { + self.spinState = .idle + self.spinLink?.invalidate() + self.spinLink = nil + self.lastSpawnTime = nil + self.currentInterval = 0.0 + self.deceleraionQueue.removeAll() + self.decelerationTotalSteps = 0 + self.decelerationStepIndex = 0 + self.spinPool.removeAll() + self.spinPoolIndex = 0 + self.spinGeom = nil + + for wrapper in self.activeWrappers { + wrapper.layer.removeAllAnimations() + wrapper.removeFromSuperview() + } + self.activeWrappers.removeAll() + + if let c = self.decelContainer { + c.layer.removeAllAnimations() + c.removeFromSuperview() + } + self.decelContainer = nil + self.decelItemHosts.removeAll() + } + + private func ensureDisplayLink() { + if self.spinLink != nil { return } + self.spinLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { [weak self] _ in + self?.tick() + }) + } + + private func spawnModelItem( + _ attribute: StarGift.UniqueGift.Attribute, + animDuration: Double + ) { + guard let geom = self.spinGeom, case let .model(_, file, _) = attribute else { + return + } + + let node = DefaultAnimatedStickerNodeImpl() + node.isUserInteractionEnabled = false + let pathPrefix = self.component!.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) + node.setup( + source: AnimatedStickerResourceSource(account: self.component!.context.account, resource: file.resource, isVideo: file.isVideoSticker), + width: Int(geom.iconSize.width * 1.6), + height: Int(geom.iconSize.height * 1.6), + playbackMode: .still(.start), + mode: .direct(cachePathPrefix: pathPrefix) + ) + node.updateLayout(size: geom.iconSize) + + let scaleValue = geom.scale + let visualSize = CGSize(width: geom.iconSize.width * scaleValue, height: geom.iconSize.height * scaleValue) + let wrapper = UIView(frame: CGRect(origin: .zero, size: visualSize)) + wrapper.clipsToBounds = false + + let host = node.view + host.frame = CGRect(origin: .zero, size: geom.iconSize) + host.layer.bounds = CGRect(origin: .zero, size: geom.iconSize) + host.layer.position = CGPoint(x: geom.iconSize.width / 2.0, y: geom.iconSize.height / 2.0) + host.layer.transform = CATransform3DMakeScale(scaleValue, scaleValue, 1.0) + wrapper.addSubview(host) + + self.addSubview(wrapper) + self.activeWrappers.append(wrapper) + + let centerY = geom.centerY - visualSize.height / 2.0 + let startX = -visualSize.width * 1.5 + let endX = geom.availableSize.width + visualSize.width + + wrapper.frame.origin = CGPoint(x: endX, y: centerY) + + let travelDistance = abs(startX - endX) + let pitch = visualSize.width + self.spacingX + + wrapper.layer.animatePosition( + from: CGPoint(x: -travelDistance, y: 0.0), + to: .zero, + duration: animDuration, + timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, + additive: true, + completion: { [weak self, weak wrapper] _ in + if let self, let w = wrapper { + self.activeWrappers.removeAll { $0 === w } + w.removeFromSuperview() + } + } + ) + + self.currentInterval = Double(pitch / travelDistance) * animDuration * 0.6 + } + + private func finishSettled() { + guard self.spinState != .settled else { return } + self.spinState = .settled + self.spinLink?.invalidate() + self.spinLink = nil + + for v in self.activeWrappers { + v.layer.removeAllAnimations() + v.removeFromSuperview() + } + self.activeWrappers.removeAll() + } + + private func startSpinningUnique( + availableSize: CGSize, + iconSize: CGSize, + scale: CGFloat, + pool: [StarGift.UniqueGift.Attribute] + ) { + self.stopSpinIfNeeded() + + self.spinPool = pool + self.spinPoolIndex = 0 + let centerY = 88.0 + (self.component?.animationOffset?.y ?? 0.0) + + self.spinGeom = SpinGeom( + availableSize: availableSize, + iconSize: iconSize, + scale: scale, + centerX: availableSize.width / 2.0 + (self.component?.animationOffset?.x ?? 0.0), + centerY: centerY + ) + + self.spinState = .spinning + self.lastSpawnTime = nil + self.currentInterval = 0 + self.ensureDisplayLink() + } + + private func beginDecelerationWithQueue( + tail: [StarGift.UniqueGift.Attribute], + availableSize: CGSize, + iconSize: CGSize, + scale: CGFloat + ) { + guard let geom = self.spinGeom, !tail.isEmpty else { return } + + let visualSize = CGSize(width: iconSize.width * scale, height: iconSize.height * scale) + let pitch = visualSize.width + self.spacingX + let count = tail.count + let containerWidth = CGFloat(count) * visualSize.width + CGFloat(max(count - 1, 0)) * self.spacingX + let containerHeight = visualSize.height + + let container = UIView(frame: CGRect(origin: .zero, size: CGSize(width: containerWidth, height: containerHeight))) + container.isUserInteractionEnabled = false + container.clipsToBounds = false + + let containerY = geom.centerY - containerHeight / 2.0 + container.frame.origin.y = containerY + self.addSubview(container) + self.decelContainer = container + self.decelItemHosts.removeAll() + + for (i, attribute) in tail.reversed().enumerated() { + guard case let .model(_, file, _) = attribute else { continue } + + let node = DefaultAnimatedStickerNodeImpl() + node.isUserInteractionEnabled = false + let pathPrefix = self.component!.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) + node.setup( + source: AnimatedStickerResourceSource(account: self.component!.context.account, resource: file.resource, isVideo: file.isVideoSticker), + width: Int(iconSize.width * 1.6), + height: Int(iconSize.height * 1.6), + playbackMode: .still(.start), + mode: .direct(cachePathPrefix: pathPrefix) + ) + node.updateLayout(size: iconSize) + node.visibility = true + if i < 4 { + node.playOnce(); + } + + let host = node.view + host.bounds = CGRect(origin: .zero, size: iconSize) + host.layer.transform = CATransform3DMakeScale(scale, scale, 1.0) + + let hostView = UIView(frame: CGRect(origin: CGPoint(x: CGFloat(i) * pitch, y: 0), size: visualSize)) + host.center = CGPoint(x: visualSize.width / 2.0, y: visualSize.height / 2.0) + hostView.addSubview(host) + container.addSubview(hostView) + self.decelItemHosts.append(hostView) + + if i == 0 { + self.animationNode = node + + let factors: [CGFloat] = [1.0, 1.3, 0.92, 1.18, 0.98, 1.0] + let values = factors.map { NSNumber(value: Double($0)) } + let scaleAnim = CAKeyframeAnimation(keyPath: "transform.scale") + scaleAnim.beginTime = CACurrentMediaTime() + 0.6 + scaleAnim.values = values + scaleAnim.keyTimes = [0.0, 0.35, 0.55, 0.75, 0.9, 1.0].map(NSNumber.init) + scaleAnim.timingFunctions = [ + CAMediaTimingFunction(name: .easeOut), + CAMediaTimingFunction(name: .easeIn), + CAMediaTimingFunction(name: .easeOut), + CAMediaTimingFunction(name: .easeIn), + CAMediaTimingFunction(name: .easeOut) + ] + scaleAnim.duration = 0.85 + scaleAnim.isRemovedOnCompletion = true + host.layer.add(scaleAnim, forKey: "bounce") + } + + if i == 1 { + hostView.alpha = 0.0 + hostView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: 0.7) + } + } + + container.frame.origin.x = floor((availableSize.width - visualSize.width) / 2.0) + + container.layer.animatePosition( + from: CGPoint(x: -containerWidth - visualSize.width * 0.5 + containerWidth / 2.0 - self.spacingX - 120.0, y: container.frame.center.y), + to: CGPoint(x: container.frame.center.x, y: container.frame.center.y), + duration: self.maxAnimDuration, + delay: 0.05, + timingFunction: kCAMediaTimingFunctionSpring, + completion: { [weak self] _ in + guard let self, let container = self.decelContainer else { + return + } + let _ = container + //self.handleDecelArrived(container: container, iconSize: iconSize, visualSize: visualSize) + } + ) + + self.spinState = .decelerating + self.ensureDisplayLink() + } + + private func handleDecelArrived(container: UIView, iconSize: CGSize, visualSize: CGSize) { + let isFinalIndex = self.decelItemHosts.count - 1 + guard isFinalIndex >= 0, let finalHostView = self.decelItemHosts.last else { return } + + guard let node = self.animationNode as? DefaultAnimatedStickerNodeImpl else { return } + node.playbackMode = .once + node.visibility = true + + let finalCenterInSelf = container.convert(finalHostView.center, to: self) + + let host = node.view + if host.superview !== self { self.addSubview(host) } + node.updateLayout(size: iconSize) + host.bounds = CGRect(origin: .zero, size: iconSize) + host.layer.position = finalCenterInSelf + + container.removeFromSuperview() + self.decelContainer = nil + self.decelItemHosts.removeAll() + + let factors: [CGFloat] = [1.0, 1.3, 0.92, 1.18, 0.98, 1.0] + let values = factors.map { NSNumber(value: Double($0)) } + let scaleAnim = CAKeyframeAnimation(keyPath: "transform.scale") + scaleAnim.values = values + scaleAnim.keyTimes = [0.0, 0.35, 0.55, 0.75, 0.9, 1.0].map(NSNumber.init) + scaleAnim.timingFunctions = [ + CAMediaTimingFunction(name: .easeOut), + CAMediaTimingFunction(name: .easeIn), + CAMediaTimingFunction(name: .easeOut), + CAMediaTimingFunction(name: .easeIn), + CAMediaTimingFunction(name: .easeOut) + ] + scaleAnim.duration = 0.85 + scaleAnim.isRemovedOnCompletion = true + host.layer.add(scaleAnim, forKey: "bounce") + + node.playOnce() + self.finishSettled() + } + + private func tick() { + guard let component = self.component else { return } + let now = CACurrentMediaTime() + + switch self.spinState { + case .spinning: + if self.lastSpawnTime == nil || now - (self.lastSpawnTime ?? now) >= self.currentInterval { + self.lastSpawnTime = now + + guard !self.spinPool.isEmpty else { return } + + if self.spinPoolIndex >= self.spinPool.count { self.spinPoolIndex = 0 } + let next = self.spinPool[self.spinPoolIndex] + self.spinPoolIndex += 1 + + self.spawnModelItem(next, animDuration: self.baseAnimDuration) + } + + var updateNeeded = false + if self.lastPatternChangeTime == nil || now - (self.lastPatternChangeTime ?? now) >= self.currentInterval * 6.0 { + self.lastPatternChangeTime = now + + if component.revealedAttributes.contains(.pattern) { + if self.previewPatternIndex != -1 { + self.previewPatternIndex = -1 + self.animatePreviewTransition = true + updateNeeded = true + } + } else { + let previousPatternIndex = self.previewPatternIndex + var randomPatternIndex = previousPatternIndex + while randomPatternIndex == previousPatternIndex && !self.previewPatterns.isEmpty { + randomPatternIndex = Int32.random(in: 0 ..< Int32(self.previewPatterns.count)) + } + if !self.previewPatterns.isEmpty { self.previewPatternIndex = randomPatternIndex } + + self.animatePreviewTransition = true + updateNeeded = true + } + } + if self.lastBackdropChangeTime == nil || now - (self.lastBackdropChangeTime ?? now) >= self.currentInterval * 3.55 { + self.lastBackdropChangeTime = now + + if component.revealedAttributes.contains(.backdrop) { + if self.previewBackdropIndex != -1 { + self.previewBackdropIndex = -1 + self.animateBackdropSwipe = true + updateNeeded = true + } + } else { + let previousBackdropIndex = self.previewBackdropIndex + var randomBackdropIndex = previousBackdropIndex + while randomBackdropIndex == previousBackdropIndex && !self.previewBackdrops.isEmpty { + randomBackdropIndex = Int32.random(in: 0 ..< Int32(self.previewBackdrops.count)) + } + if !self.previewBackdrops.isEmpty { self.previewBackdropIndex = randomBackdropIndex } + + self.animateBackdropSwipe = true + updateNeeded = true + } + } + + if updateNeeded { + self.componentState?.updated(transition: .easeInOut(duration: 0.25)) + self.component?.requestUpdate(.easeInOut(duration: 0.25)) + } + self.applyEdge3DHorizontal() + case .decelerating: + self.applyEdge3DHorizontal() + case .idle, .settled: + self.spinLink?.invalidate() + self.spinLink = nil + } + } + + private let minScaleAtEdgeX: CGFloat = 0.7 + private let yawAtEdgeDegrees: CGFloat = 25.0 + private let edgeFalloffX: CGFloat = 0.25 + + @inline(__always) + private func smoothstep01(_ x: CGFloat) -> CGFloat { + let t = max(0.0, min(1.0, x)) + return t * t * (3.0 - 2.0 * t) + } + + @inline(__always) + private func liveMidX(in container: UIView, of view: UIView) -> CGFloat { + if let pres = view.layer.presentation() { + let p = container.layer.convert(pres.position, from: view.layer.superlayer) + return p.x + } + return view.center.x + } + + @inline(__always) + private func midXInsideAnimatedContainer(in selfView: UIView, container: UIView, hostView: UIView) -> CGFloat { + let contPres = container.layer.presentation() ?? container.layer + let hostPres = hostView.layer.presentation() ?? hostView.layer + + let hostOffsetFromContainerCenter = hostPres.position.x - container.bounds.midX + return contPres.position.x + hostOffsetFromContainerCenter + } + + private func edge3DTransformFor(midX: CGFloat, containerWidth: CGFloat, baseScale: CGFloat = 1.0) -> CATransform3D { + guard containerWidth > 0 else { + return CATransform3DMakeScale(baseScale, baseScale, 1.0) + } + let d = abs((midX - containerWidth * 0.5) / (containerWidth * 0.5)) + + let uRaw = (d - edgeFalloffX) / (1.0 - edgeFalloffX) + let u = smoothstep01(max(0.0, min(1.0, uRaw))) + + let scale = (1.0 - u) * baseScale + (minScaleAtEdgeX * baseScale) * u + let yawSign: CGFloat = (midX < containerWidth * 0.5) ? 1.0 : -1.0 + let yawRadians = (yawAtEdgeDegrees * .pi / 180.0) * u * yawSign + + var t = CATransform3DIdentity + t = CATransform3DRotate(t, yawRadians, 0.0, 1.0, 0.0) + t = CATransform3DScale(t, scale, scale, 1.0) + return t + } + + private func applyEdge3DHorizontal() { + let containerWidth = self.bounds.width + guard containerWidth > 0.0 else { return } + + CATransaction.begin() + CATransaction.setDisableActions(true) + + for w in self.activeWrappers { + guard w.superview === self else { continue } + let midX = liveMidX(in: self, of: w) + if let host = w.subviews.first { + let baseScale = max(0.01, w.bounds.width / max(host.bounds.width, 0.01)) + host.layer.transform = edge3DTransformFor(midX: midX, containerWidth: containerWidth, baseScale: baseScale) + } + } + + for hostView in self.decelItemHosts { + guard let container = self.decelContainer, hostView.superview === container && hostView !== self.decelItemHosts.first else { + continue + } + let midX = midXInsideAnimatedContainer(in: self, container: container, hostView: hostView) + if let host = hostView.subviews.first { + let baseScale = max(0.01, hostView.bounds.width / max(host.bounds.width, 0.01)) + host.layer.transform = edge3DTransformFor(midX: midX, containerWidth: containerWidth, baseScale: baseScale) + } + } + + CATransaction.commit() + } + public func update(component: GiftCompositionComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { let previousComponent = self.component @@ -140,21 +606,30 @@ public final class GiftCompositionComponent: Component { var files: [Int64: TelegramMediaFile] = [:] var loop = false + + var uniqueSpinContext: (previewAttributes: [StarGift.UniqueGift.Attribute], mainGift: StarGift.UniqueGift)? = nil + switch component.subject { case let .generic(file): animationFile = file self.currentFile = file + self.stopSpinIfNeeded() if let previewTimer = self.previewTimer { previewTimer.invalidate() self.previewTimer = nil } - if !self.fetchedFiles.contains(file.fileId.id) { self.disposables.add(freeMediaFileResourceInteractiveFetched(account: component.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) self.fetchedFiles.insert(file.fileId.id) } - case let .unique(gift): + + case let .unique(previewAttributesOpt, gift): + if let previewTimer = self.previewTimer { + previewTimer.invalidate() + self.previewTimer = nil + } + for attribute in gift.attributes { switch attribute { case let .model(_, file, _): @@ -174,13 +649,23 @@ public final class GiftCompositionComponent: Component { break } } - - if let previewTimer = self.previewTimer { - previewTimer.invalidate() - self.previewTimer = nil + if let previewAttributes = previewAttributesOpt, !previewAttributes.isEmpty { + if self.previewPatternIndex != -1, case let .pattern(_, file, _) = self.previewPatterns[Int(self.previewPatternIndex)] { + patternFile = file + files[file.fileId.id] = file + } + if self.previewBackdropIndex != -1, case let .backdrop(_, _, innerColorValue, outerColorValue, patternColorValue, _, _) = self.previewBackdrops[Int(self.previewBackdropIndex)] { + backgroundColor = UIColor(rgb: UInt32(bitPattern: outerColorValue)) + secondBackgroundColor = UIColor(rgb: UInt32(bitPattern: innerColorValue)) + patternColor = UIColor(rgb: UInt32(bitPattern: patternColorValue)) + } + uniqueSpinContext = (previewAttributes, gift) + } else { + self.stopSpinIfNeeded() } case let .preview(sampleAttributes): loop = true + self.stopSpinIfNeeded() if self.previewModels.isEmpty { var models: [StarGift.UniqueGift.Attribute] = [] @@ -188,14 +673,10 @@ public final class GiftCompositionComponent: Component { var backdrops: [StarGift.UniqueGift.Attribute] = [] for attribute in sampleAttributes { switch attribute { - case .model: - models.append(attribute) - case .pattern: - patterns.append(attribute) - case .backdrop: - backdrops.append(attribute) - default: - break + case .model: models.append(attribute) + case .pattern: patterns.append(attribute) + case .backdrop: backdrops.append(attribute) + default: break } } self.previewModels = models @@ -203,67 +684,72 @@ public final class GiftCompositionComponent: Component { self.previewBackdrops = backdrops } - for case let .model(_, file, _) in self.previewModels { - if !self.fetchedFiles.contains(file.fileId.id) { - self.disposables.add(freeMediaFileResourceInteractiveFetched(account: component.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) - self.fetchedFiles.insert(file.fileId.id) - } + for case let .model(_, file, _) in self.previewModels where !self.fetchedFiles.contains(file.fileId.id) { + self.disposables.add(freeMediaFileResourceInteractiveFetched(account: component.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) + self.fetchedFiles.insert(file.fileId.id) } - for case let .pattern(_, file, _) in self.previewModels { - if !self.fetchedFiles.contains(file.fileId.id) { - self.disposables.add(freeMediaFileResourceInteractiveFetched(account: component.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) - self.fetchedFiles.insert(file.fileId.id) - } + for case let .pattern(_, file, _) in self.previewPatterns where !self.fetchedFiles.contains(file.fileId.id) { + self.disposables.add(freeMediaFileResourceInteractiveFetched(account: component.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) + self.fetchedFiles.insert(file.fileId.id) } if !self.previewModels.isEmpty { + if self.previewPatternIndex < 0 { + self.previewPatternIndex = 0 + } + if self.previewBackdropIndex < 0 { + self.previewBackdropIndex = 0 + } if case let .model(_, file, _) = self.previewModels[Int(self.previewModelIndex)] { animationFile = file } - if case let .pattern(_, file, _) = self.previewPatterns[Int(self.previewPatternIndex)] { patternFile = file files[file.fileId.id] = file } - if case let .backdrop(_, _, innerColorValue, outerColorValue, patternColorValue, _, _) = self.previewBackdrops[Int(self.previewBackdropIndex)] { backgroundColor = UIColor(rgb: UInt32(bitPattern: outerColorValue)) secondBackgroundColor = UIColor(rgb: UInt32(bitPattern: innerColorValue)) patternColor = UIColor(rgb: UInt32(bitPattern: patternColorValue)) } } - + if self.previewTimer == nil { self.previewTimer = SwiftSignalKit.Timer(timeout: 2.0, repeat: true, completion: { [weak self] in - guard let self, !self.previewModels.isEmpty else { - return - } + guard let self, !self.previewModels.isEmpty else { return } self.previewModelIndex = (self.previewModelIndex + 1) % Int32(self.previewModels.count) let previousPatternIndex = self.previewPatternIndex var randomPatternIndex = previousPatternIndex - while randomPatternIndex == previousPatternIndex { + while randomPatternIndex == previousPatternIndex && !self.previewPatterns.isEmpty { randomPatternIndex = Int32.random(in: 0 ..< Int32(self.previewPatterns.count)) } - self.previewPatternIndex = randomPatternIndex + if !self.previewPatterns.isEmpty { self.previewPatternIndex = randomPatternIndex } let previousBackdropIndex = self.previewBackdropIndex var randomBackdropIndex = previousBackdropIndex - while randomBackdropIndex == previousBackdropIndex { + while randomBackdropIndex == previousBackdropIndex && !self.previewBackdrops.isEmpty { randomBackdropIndex = Int32.random(in: 0 ..< Int32(self.previewBackdrops.count)) } - self.previewBackdropIndex = randomBackdropIndex + if !self.previewBackdrops.isEmpty { self.previewBackdropIndex = randomBackdropIndex } self.animatePreviewTransition = true self.componentState?.updated(transition: .easeInOut(duration: 0.25)) + self.component?.requestUpdate(.easeInOut(duration: 0.25)) }, queue: Queue.mainQueue()) self.previewTimer?.start() } } component.externalState?.previewPatternColor = secondBackgroundColor - + + var animateBackdropSwipe = false + if self.animateBackdropSwipe { + animateBackdropSwipe = true + self.animateBackdropSwipe = false + } + var animateTransition = false if self.animatePreviewTransition { animateTransition = true @@ -278,16 +764,24 @@ public final class GiftCompositionComponent: Component { if let backgroundColor { var backgroundTransition = transition - - if animateTransition, let backgroundView = self.background.view as? PeerInfoCoverComponent.View { - backgroundView.animateTransition() + if let backgroundView = self.background.view as? PeerInfoCoverComponent.View { + if animateTransition { + var bounce = true + var background = true + if case .unique = component.subject { + bounce = self.previewPatternIndex == -1 + background = false + } + backgroundView.animateTransition(background: background, bounce: bounce) + } + if animateBackdropSwipe { + backgroundView.animateSwipeTransition() + } } - var avatarCenter = CGPoint(x: availableSize.width / 2.0, y: 104.0) if let _ = component.animationScale { avatarCenter = CGPoint(x: avatarCenter.x, y: 67.0) } - let _ = self.background.update( transition: backgroundTransition, component: AnyComponent(PeerInfoCoverComponent( @@ -311,7 +805,6 @@ public final class GiftCompositionComponent: Component { backgroundView.clipsToBounds = true backgroundView.isUserInteractionEnabled = false self.insertSubview(backgroundView, at: 0) - if previousComponent != nil { backgroundView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } @@ -323,9 +816,99 @@ public final class GiftCompositionComponent: Component { backgroundView.removeFromSuperview() }) } - + let iconSize = CGSize(width: 136.0, height: 136.0) + if let (previewAttributes, mainGift) = uniqueSpinContext { + var mainModelFile: TelegramMediaFile? + for attribute in mainGift.attributes { + if case let .model(_, file, _) = attribute { mainModelFile = file; break } + } + + var models: [StarGift.UniqueGift.Attribute] = [] + for attribute in previewAttributes { + if case let .model(_, file, _) = attribute, + file.fileId.id != mainModelFile?.fileId.id { + models.append(attribute) + } + } + + if models.isEmpty, let _ = mainModelFile { + return availableSize + } + + for case let .model(_, file, _) in models where !self.fetchedFiles.contains(file.fileId.id) { + self.disposables.add(freeMediaFileResourceInteractiveFetched( + account: component.context.account, + userLocation: .other, + fileReference: .standalone(media: file), + resource: file.resource + ).start()) + self.fetchedFiles.insert(file.fileId.id) + } + if let mainModelFile, !self.fetchedFiles.contains(mainModelFile.fileId.id) { + self.disposables.add(freeMediaFileResourceInteractiveFetched( + account: component.context.account, + userLocation: .other, + fileReference: .standalone(media: mainModelFile), + resource: mainModelFile.resource + ).start()) + self.fetchedFiles.insert(mainModelFile.fileId.id) + } + + let wasAnimatingModel = previousComponent != nil && !(previousComponent!.revealedAttributes.contains(.model)) + let isAnimatingModel = !component.revealedAttributes.contains(.model) + + let wasAnimating = wasAnimatingModel + let nowAnimating = isAnimatingModel + + if nowAnimating { + if let disappearing = self.animationNode { + self.animationNode = nil + disappearing.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.12, removeOnCompletion: false, completion: { _ in + disappearing.view.removeFromSuperview() + }) + } + } + + let scaleValue: CGFloat = component.animationScale ?? 1.0 + + if nowAnimating && (!wasAnimating || self.spinState != .spinning) { + self.startSpinningUnique( + availableSize: availableSize, + iconSize: iconSize, + scale: scaleValue, + pool: models + ) + } else if !nowAnimating && wasAnimating { + var tail = Array(models.shuffled().prefix(6)) + if let mainModelFile { + tail.append(.model(name: "", file: mainModelFile, rarity: 0)) + } + self.beginDecelerationWithQueue( + tail: tail, + availableSize: availableSize, + iconSize: iconSize, + scale: scaleValue + ) + } else if self.spinState == .spinning { + let centerY = 88.0 + (component.animationOffset?.y ?? 0.0) + self.spinGeom = SpinGeom( + availableSize: availableSize, + iconSize: iconSize, + scale: scaleValue, + centerX: availableSize.width / 2.0 + (component.animationOffset?.x ?? 0.0), + centerY: centerY + ) + } + + return availableSize + } + + if self.spinState != .idle && self.spinState != .settled { + self.stopSpinIfNeeded() + } + var startFromIndex: Int? var animationTransition = transition if animateTransition, let disappearingAnimationNode = self.animationNode { @@ -337,46 +920,39 @@ public final class GiftCompositionComponent: Component { animationTransition = .immediate } - if let file = animationFile { - let animationNode: AnimatedStickerNode - if self.animationNode == nil { - animationTransition = .immediate - animationNode = DefaultAnimatedStickerNodeImpl() - animationNode.isUserInteractionEnabled = false - self.animationNode = animationNode - - self.addSubview(animationNode.view) - - let pathPrefix = component.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) - animationNode.setup(source: AnimatedStickerResourceSource(account: component.context.account, resource: file.resource, isVideo: file.isVideoSticker), width: Int(iconSize.width * 1.6), height: Int(iconSize.height * 1.6), playbackMode: .loop, mode: .direct(cachePathPrefix: pathPrefix)) - - if let startFromIndex { - if let animationNode = animationNode as? DefaultAnimatedStickerNodeImpl { - animationNode.playbackMode = loop ? .loop : .once - } - animationNode.play(firstFrame: false, fromIndex: startFromIndex) - } else { - if loop { - animationNode.playLoop() - } else { - animationNode.playOnce() - } - } - animationNode.visibility = true - animationNode.updateLayout(size: iconSize) - - if animateTransition { - animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) - } + if let file = animationFile, self.animationNode == nil { + animationTransition = .immediate + let node = DefaultAnimatedStickerNodeImpl() + node.isUserInteractionEnabled = false + self.animationNode = node + self.addSubview(node.view) + let pathPrefix = component.context.account.postbox.mediaBox.shortLivedResourceCachePathPrefix(file.resource.id) + node.setup(source: AnimatedStickerResourceSource(account: component.context.account, resource: file.resource, isVideo: file.isVideoSticker), + width: Int(iconSize.width * 1.6), height: Int(iconSize.height * 1.6), + playbackMode: loop ? .loop : .once, + mode: .direct(cachePathPrefix: pathPrefix)) + if let startFromIndex { + node.play(firstFrame: false, fromIndex: startFromIndex) + } else { + if loop { node.playLoop() } else { node.playOnce() } + } + node.visibility = true + node.updateLayout(size: iconSize) + if animateTransition { + node.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } } + if let animationNode = self.animationNode { let offset = component.animationOffset ?? .zero var size = CGSize(width: iconSize.width, height: iconSize.height) if let scale = component.animationScale { size = CGSize(width: size.width * scale, height: size.height * scale) } - let animationFrame = CGRect(origin: CGPoint(x: availableSize.width / 2.0 + offset.x - size.width / 2.0, y: 88.0 + offset.y - size.height / 2.0), size: size) + let animationFrame = CGRect( + origin: CGPoint(x: availableSize.width / 2.0 + offset.x - size.width / 2.0, y: 88.0 + offset.y - size.height / 2.0), + size: size + ) animationNode.layer.bounds = CGRect(origin: .zero, size: iconSize) animationTransition.setPosition(layer: animationNode.layer, position: animationFrame.center) animationTransition.setScale(layer: animationNode.layer, scale: size.width / iconSize.width) @@ -405,7 +981,7 @@ public final class GiftCompositionComponent: Component { }) } } - + return availableSize } } @@ -424,7 +1000,6 @@ private final class StarsEffectLayer: SimpleLayer { override init() { super.init() - self.addSublayer(self.emitterLayer) } diff --git a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift index 6881c00ac3..901d9dfd33 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift @@ -154,6 +154,7 @@ public final class GiftItemComponent: Component { let isSelected: Bool let isPinned: Bool let isEditing: Bool + let isDateLocked: Bool let mode: Mode let action: (() -> Void)? let contextAction: ((UIView, ContextGesture) -> Void)? @@ -176,6 +177,7 @@ public final class GiftItemComponent: Component { isSelected: Bool = false, isPinned: Bool = false, isEditing: Bool = false, + isDateLocked: Bool = false, mode: Mode = .generic, action: (() -> Void)? = nil, contextAction: ((UIView, ContextGesture) -> Void)? = nil @@ -197,6 +199,7 @@ public final class GiftItemComponent: Component { self.isSelected = isSelected self.isPinned = isPinned self.isEditing = isEditing + self.isDateLocked = isDateLocked self.mode = mode self.action = action self.contextAction = contextAction @@ -254,6 +257,9 @@ public final class GiftItemComponent: Component { if lhs.isEditing != rhs.isEditing { return false } + if lhs.isDateLocked != rhs.isDateLocked { + return false + } if lhs.mode != rhs.mode { return false } @@ -298,6 +304,7 @@ public final class GiftItemComponent: Component { private var iconBackground: UIVisualEffectView? private var hiddenIcon: UIImageView? private var pinnedIcon: UIImageView? + private var dateLockedIcon: UIImageView? private var resellBackground: BlurredBackgroundView? private let reselLabel = ComponentView() @@ -902,6 +909,22 @@ public final class GiftItemComponent: Component { }) pinnedIcon.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false) } + + if component.isDateLocked { + let dateLockedIcon: UIImageView + if let currentIcon = self.dateLockedIcon { + dateLockedIcon = currentIcon + } else { + dateLockedIcon = UIImageView(image: UIImage(bundleImageName: "Peer Info/DateLockedIcon")?.withRenderingMode(.alwaysTemplate)) + self.dateLockedIcon = dateLockedIcon + self.addSubview(dateLockedIcon) + } + dateLockedIcon.frame = CGRect(origin: CGPoint(x: 3.0, y: 3.0), size: CGSize(width: 24.0, height: 24.0)) + dateLockedIcon.tintColor = component.theme.list.itemDestructiveColor + } else if let dateLockedIcon = self.dateLockedIcon { + self.dateLockedIcon = nil + dateLockedIcon.removeFromSuperview() + } if component.isHidden && !component.isEditing { let hiddenIcon: UIImageView diff --git a/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift index 90a8a1ae83..d38abd89a4 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftOptionsScreen/Sources/GiftOptionsScreen.swift @@ -143,6 +143,8 @@ final class GiftOptionsScreenComponent: Component { private var starsFilter: StarsFilter = .all private var switchingFilter = false + private var loadingGiftId: Int64? + private var _effectiveStarGifts: ([StarGift], StarsFilter)? private var effectiveStarGifts: [StarGift]? { get { @@ -274,6 +276,122 @@ final class GiftOptionsScreenComponent: Component { func scrollViewDidScroll(_ scrollView: UIScrollView) { self.updateScrolling(interactive: true, transition: self.nextScrollTransition ?? .immediate) } + + private func openGift(gift: StarGift, skipDateCheck: Bool = false) { + guard let component = self.component, let environment = self.environment else { + return + } + let context = component.context + let strings = environment.strings + let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) + let starGift = gift + + if let controller = environment.controller() as? GiftOptionsScreen { + let mainController: ViewController + if let parentController = controller.parentController() { + mainController = parentController + } else { + mainController = controller + } + if case let .generic(gift) = gift { + if let lockedUntilDate = gift.lockedUntilDate, currentTime < lockedUntilDate { + self.loadingGiftId = gift.id + Queue.mainQueue().after(0.25) { + if self.loadingGiftId != nil { + self.state?.updated() + } + } + + let _ = (component.context.engine.payments.checkCanSendStarGift(giftId: gift.id) + |> deliverOnMainQueue).start(next: { [weak self, weak controller] result in + guard let self, let controller else { + return + } + self.loadingGiftId = nil + self.state?.updated() + + switch result { + case .available: + self.openGift(gift: starGift, skipDateCheck: true) + case let .unavailable(text, entities): + let theme = AlertControllerTheme(presentationData: component.context.sharedContext.currentPresentationData.with { $0 }) + let font = Font.regular(floor(theme.baseFontSize * 13.0 / 17.0)) + let boldFont = Font.semibold(floor(theme.baseFontSize * 13.0 / 17.0)) + let attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: theme.primaryColor, linkColor: theme.accentColor, baseFont: font, linkFont: font, boldFont: boldFont, italicFont: font, boldItalicFont: font, fixedFont: font, blockQuoteFont: font, message: nil, paragraphAlignment: .center) + + var dismissImpl: (() -> Void)? + let alertController = textAlertController(theme: theme, title: NSAttributedString(string: strings.Gift_Options_GiftLocked_Title, font: Font.semibold(theme.baseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center), text: attributedText, actions: [TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: { + dismissImpl?() + })], actionLayout: .horizontal, dismissOnOutsideTap: true, linkAction: { [weak controller] attributes, _ in + if let value = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { + dismissImpl?() + if let navigationController = controller?.navigationController as? NavigationController { + context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: value, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: navigationController, dismissInput: {}) + } + } + }) + dismissImpl = { [weak alertController] in + alertController?.dismissAnimated() + } + controller.present(alertController, in: .window(.root)) + case .failed: + break + } + }) + return + } + + if let perUserLimit = gift.perUserLimit, perUserLimit.remains == 0 { + let text = environment.strings.Gift_Options_Gift_BuyLimitReached(perUserLimit.total) + let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } + let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: gift.file, loop: true, title: nil, text: text, undoText: nil, customAction: nil), action: { _ in return false }) + mainController.present(controller, in: .current) + return + } + if gift.flags.contains(.requiresPremium) && !component.context.isPremium { + let controller = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .premiumGift(gift.file), forceDark: false, dismissed: nil) + mainController.push(controller) + return + } + + if let availability = gift.availability, availability.remains == 0 { + if availability.resale > 0 { + let storeController = component.context.sharedContext.makeGiftStoreController( + context: component.context, + peerId: component.peerId, + gift: gift + ) + mainController.push(storeController) + } else { + let giftController = GiftViewScreen( + context: component.context, + subject: .soldOutGift(gift) + ) + mainController.push(giftController) + } + } else { + var forceUnique: Bool? + if let disallowedGifts = self.state?.disallowedGifts { + if disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) { + forceUnique = true + } else if !disallowedGifts.contains(.limited) && disallowedGifts.contains(.unique) { + forceUnique = false + } + } + + let giftController = GiftSetupScreen( + context: component.context, + peerId: component.peerId, + subject: .starGift(gift, forceUnique), + completion: component.completion + ) + mainController.push(giftController) + } + } else if case let .unique(gift) = gift { + self.transferGift(gift) + } + } + } private func updateScrolling(interactive: Bool = false, transition: ComponentTransition) { guard let environment = self.environment, let component = self.component else { @@ -344,8 +462,6 @@ final class GiftOptionsScreenComponent: Component { var validIds: [AnyHashable] = [] var itemFrame = CGRect(origin: CGPoint(x: sideInset, y: self.starsItemsOrigin), size: starsOptionSize) - let controller = environment.controller - for gift in starGifts { var isVisible = false if visibleBounds.intersects(itemFrame) { @@ -371,6 +487,7 @@ final class GiftOptionsScreenComponent: Component { var ribbon: GiftItemComponent.Ribbon? var outline: GiftItemComponent.Outline? var isSoldOut = false + var isLoading = false switch gift { case let .generic(gift): if let _ = gift.soldOut { @@ -399,6 +516,10 @@ final class GiftOptionsScreenComponent: Component { ) outline = .orange } + + if gift.id == self.loadingGiftId { + isLoading = true + } case let .unique(gift): var ribbonColor: GiftItemComponent.Ribbon.Color = .blue for attribute in gift.attributes { @@ -414,6 +535,7 @@ final class GiftOptionsScreenComponent: Component { ) } + var lockedUntilDate: Int32? let subject: GiftItemComponent.Subject switch gift { case let .generic(gift): @@ -427,6 +549,7 @@ final class GiftOptionsScreenComponent: Component { } else { subject = .starGift(gift: gift, price: "# \(presentationStringsFormattedNumber(Int32(gift.price), environment.dateTimeFormat.groupingSeparator))") } + lockedUntilDate = gift.lockedUntilDate case let .unique(gift): subject = .uniqueGift(gift: gift, price: nil) } @@ -444,71 +567,17 @@ final class GiftOptionsScreenComponent: Component { subject: subject, ribbon: ribbon, outline: outline, - isSoldOut: isSoldOut + isLoading: isLoading, + isSoldOut: isSoldOut, + isDateLocked: lockedUntilDate != nil ) ), effectAlignment: .center, action: { [weak self] in - if let self, let component = self.component { - if let controller = controller() as? GiftOptionsScreen { - let mainController: ViewController - if let parentController = controller.parentController() { - mainController = parentController - } else { - mainController = controller - } - if case let .generic(gift) = gift { - if let perUserLimit = gift.perUserLimit, perUserLimit.remains == 0 { - let text = environment.strings.Gift_Options_Gift_BuyLimitReached(perUserLimit.total) - let presentationData = component.context.sharedContext.currentPresentationData.with { $0 } - let controller = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: gift.file, loop: true, title: nil, text: text, undoText: nil, customAction: nil), action: { _ in return false }) - mainController.present(controller, in: .current) - return - } - if gift.flags.contains(.requiresPremium) && !component.context.isPremium { - let controller = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .premiumGift(gift.file), forceDark: false, dismissed: nil) - mainController.push(controller) - return - } - - if let availability = gift.availability, availability.remains == 0 { - if availability.resale > 0 { - let storeController = component.context.sharedContext.makeGiftStoreController( - context: component.context, - peerId: component.peerId, - gift: gift - ) - mainController.push(storeController) - } else { - let giftController = GiftViewScreen( - context: component.context, - subject: .soldOutGift(gift) - ) - mainController.push(giftController) - } - } else { - var forceUnique: Bool? - if let disallowedGifts = self.state?.disallowedGifts { - if disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) { - forceUnique = true - } else if !disallowedGifts.contains(.limited) && disallowedGifts.contains(.unique) { - forceUnique = false - } - } - - let giftController = GiftSetupScreen( - context: component.context, - peerId: component.peerId, - subject: .starGift(gift, forceUnique), - completion: component.completion - ) - mainController.push(giftController) - } - } else if case let .unique(gift) = gift { - self.transferGift(gift) - } - } + guard let self else { + return } + self.openGift(gift: gift) }, animateAlpha: false ) diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift index 8045042ac1..1606a4ee30 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/ChatGiftPreviewItem.swift @@ -239,7 +239,7 @@ final class ChatGiftPreviewItemNode: ListViewItemNode { case let .starGift(gift): media = [ TelegramMediaAction( - action: .starGift(gift: .generic(gift), convertStars: gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false, upgraded: false, canUpgrade: gift.upgradeStars != nil, upgradeStars: item.upgradeStars, isRefunded: false, isPrepaidUpgrade: false, upgradeMessageId: nil, peerId: nil, senderId: nil, savedId: nil, prepaidUpgradeHash: nil, giftMessageId: nil) + action: .starGift(gift: .generic(gift), convertStars: gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false, upgraded: false, canUpgrade: gift.upgradeStars != nil, upgradeStars: item.upgradeStars, isRefunded: false, isPrepaidUpgrade: false, upgradeMessageId: nil, peerId: nil, senderId: nil, savedId: nil, prepaidUpgradeHash: nil, giftMessageId: nil, upgradeSeparate: false) ) ] } diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index e976012283..b7c8c81f79 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -752,6 +752,10 @@ final class GiftSetupScreenComponent: Component { } else if isChannelGift { navigationTitleString = environment.strings.Gift_SendChannel_Title } else { + var peerName = peerName + if peerName.count > 22 { + peerName = "\(peerName.prefix(22))…" + } navigationTitleString = environment.strings.Gift_Send_TitleTo(peerName).string } let navigationTitleSize = self.navigationTitle.update( diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/BUILD b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/BUILD index a2e66c96b7..9e0aca1b52 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/BUILD +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/BUILD @@ -53,6 +53,7 @@ swift_library( "//submodules/ActivityIndicator", "//submodules/TelegramUI/Components/TabSelectorComponent", "//submodules/TelegramUI/Components/Stars/BalanceNeededScreen", + "//submodules/ImageBlur", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftValueScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftValueScreen.swift index 775f7a183f..f0b757f8ee 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftValueScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftValueScreen.swift @@ -276,7 +276,7 @@ private final class GiftValueSheetContent: CombinedComponent { animationScale: nil, displayAnimationStars: false, externalState: giftCompositionExternalState, - requestUpdate: { [weak state] in + requestUpdate: { [weak state] _ in state?.updated() } ), @@ -446,7 +446,7 @@ private final class GiftValueSheetContent: CombinedComponent { ) let percentage = Int32(floor(Double(lastSalePrice) / Double(component.valueInfo.initialSalePrice) * 100.0 - 100.0)) - let percentageString = percentage > 0 ? "+\(percentage)" : "\(percentage)" + let percentageString = (percentage > 0 ? "+\(percentage)" : "\(percentage)") + "%" items.append(AnyComponentWithIdentity( id: AnyHashable(1), diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 503bdb7141..80e9d9241e 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -28,7 +28,6 @@ import ConfettiEffect import PlainButtonComponent import CheckComponent import TooltipUI -import GiftAnimationComponent import LottieComponent import ContextUI import TelegramNotices @@ -36,6 +35,7 @@ import PremiumLockButtonSubtitleComponent import StarsBalanceOverlayComponent import BalanceNeededScreen import GiftItemComponent +import GiftAnimationComponent private final class GiftViewSheetContent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -75,6 +75,9 @@ private final class GiftViewSheetContent: CombinedComponent { private let context: AccountContext private(set) var subject: GiftViewScreen.Subject + var justUpgraded = false + var revealedAttributes = Set() + var revealedNumberDigits: Int = 0 private let getController: () -> ViewController? @@ -102,6 +105,8 @@ private final class GiftViewSheetContent: CombinedComponent { var inProgress = false + var testUpgradeAnimation = !"".isEmpty + var nextGiftToUpgrade: ProfileGiftsContext.State.StarGift? var inUpgradePreview = false var upgradeForm: BotPaymentForm? @@ -208,6 +213,31 @@ private final class GiftViewSheetContent: CombinedComponent { } }) } + + if self.testUpgradeAnimation { + if gift.giftId != 0 { + self.sampleDisposable.add((context.engine.payments.starGiftUpgradePreview(giftId: gift.giftId) + |> deliverOnMainQueue).start(next: { [weak self] attributes in + guard let self else { + return + } + self.sampleGiftAttributes = attributes + + for attribute in attributes { + switch attribute { + case let .model(_, file, _): + self.sampleDisposable.add(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) + case let .pattern(_, file, _): + self.sampleDisposable.add(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start()) + default: + break + } + } + + self.updated() + })) + } + } } else if case let .generic(gift) = arguments.gift { if let releasedBy = gift.releasedBy { peerIds.append(releasedBy) @@ -632,15 +662,18 @@ private final class GiftViewSheetContent: CombinedComponent { controller.push(introController) } + private var isOpeningValue = false func openValue() { - guard let controller = self.getController(), let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift else { + guard let controller = self.getController(), let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, !self.isOpeningValue else { return } + self.isOpeningValue = true let _ = (self.context.engine.payments.getUniqueStarGiftValueInfo(slug: uniqueGift.slug) |> deliverOnMainQueue).start(next: { [weak self] valueInfo in guard let self, let valueInfo else { return } + self.isOpeningValue = false let valueController = GiftValueScreen(context: self.context, gift: gift, valueInfo: valueInfo) controller.push(valueController) }) @@ -1176,7 +1209,7 @@ private final class GiftViewSheetContent: CombinedComponent { self.inUpgradePreview = true self.updated(transition: .spring(duration: 0.4)) - if let controller = self.getController() as? GiftViewScreen { + if let controller = self.getController() as? GiftViewScreen, self.upgradeForm != nil { controller.showBalance = true } } @@ -1496,6 +1529,53 @@ private final class GiftViewSheetContent: CombinedComponent { } func commitUpgrade() { + if self.testUpgradeAnimation, let arguments = self.subject.arguments, case let .unique(uniqueGift) = arguments.gift { + self.inProgress = true + self.updated() + + if let controller = self.getController() as? GiftViewScreen { + controller.showBalance = false + } + + Queue.mainQueue().after(0.5, { + self.inUpgradePreview = false + self.inProgress = false + + self.justUpgraded = true + self.revealedNumberDigits = -1 + + for i in 0 ..< "\(uniqueGift.number)".count { + Queue.mainQueue().after(0.2 + Double(i) * 0.3) { + self.revealedNumberDigits += 1 + self.updated(transition: .immediate) + } + } + self.updated(transition: .spring(duration: 0.4)) + + Queue.mainQueue().after(1.2) { + self.revealedAttributes.insert(.backdrop) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.7) { + self.revealedAttributes.insert(.pattern) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.7) { + self.revealedAttributes.insert(.model) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.6) { + if let controller = self.getController() as? GiftViewScreen { + controller.animateSuccess() + } + } + } + } + } + }) + return + } + guard let arguments = self.subject.arguments, let peerId = arguments.peerId, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else { return } @@ -1547,6 +1627,39 @@ private final class GiftViewSheetContent: CombinedComponent { self.nextGiftToUpgrade = controller.nextUpgradableGift } + self.justUpgraded = true + self.revealedNumberDigits = -1 + + if case let .unique(uniqueGift) = result.gift { + for i in 0 ..< "\(uniqueGift.number)".count { + Queue.mainQueue().after(0.2 + Double(i) * 0.3) { + self.revealedNumberDigits += 1 + self.updated(transition: .immediate) + } + } + } + + Queue.mainQueue().after(1.2) { + self.revealedAttributes.insert(.backdrop) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.7) { + self.revealedAttributes.insert(.pattern) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.7) { + self.revealedAttributes.insert(.model) + self.updated(transition: .immediate) + + Queue.mainQueue().after(0.6) { + if let controller = self.getController() as? GiftViewScreen { + controller.animateSuccess() + } + } + } + } + } + self.subject = .profileGift(peerId, result) controller.animateSuccess() self.updated(transition: .spring(duration: 0.4)) @@ -1594,9 +1707,9 @@ private final class GiftViewSheetContent: CombinedComponent { } } - if let controller = self.getController() as? GiftViewScreen { - controller.showBalance = true - } +// if let controller = self.getController() as? GiftViewScreen { +// controller.showBalance = true +// } } func commitPrepaidUpgrade() { @@ -1636,7 +1749,6 @@ private final class GiftViewSheetContent: CombinedComponent { guard let self else { return } - self.dismiss(animated: true) Queue.mainQueue().after(0.5) { starsContext?.load(force: true) } @@ -1708,6 +1820,7 @@ private final class GiftViewSheetContent: CombinedComponent { let descriptionButton = Child(PlainButtonComponent.self) let description = Child(MultilineTextComponent.self) + let animatedDescription = Child(HStack.self) let transferButton = Child(PlainButtonComponent.self) let wearButton = Child(PlainButtonComponent.self) @@ -1888,6 +2001,11 @@ private final class GiftViewSheetContent: CombinedComponent { } }, morePressed: { [weak state] node, gesture in + if state?.testUpgradeAnimation == true { + state?.requestUpgradePreview() + return + } + state?.openMore(node: node, gesture: gesture) } ), @@ -1899,7 +2017,7 @@ private final class GiftViewSheetContent: CombinedComponent { let headerHeight: CGFloat let headerSubject: GiftCompositionComponent.Subject? - if let uniqueGift { + if let uniqueGift, !state.inUpgradePreview { if showWearPreview { headerHeight = 200.0 } else if case let .peerId(peerId) = uniqueGift.owner, peerId == component.context.account.peerId || isChannelGift { @@ -1907,7 +2025,7 @@ private final class GiftViewSheetContent: CombinedComponent { } else { headerHeight = 240.0 } - headerSubject = .unique(uniqueGift) + headerSubject = .unique(state.justUpgraded ? state.sampleGiftAttributes : nil, uniqueGift) } else if state.inUpgradePreview, let attributes = state.sampleGiftAttributes { headerHeight = 258.0 headerSubject = .preview(attributes) @@ -2009,6 +2127,8 @@ private final class GiftViewSheetContent: CombinedComponent { animationScale = 0.19 } + var headerComponents: [() -> Void] = [] + if let headerSubject { let animation = animation.update( component: GiftCompositionComponent( @@ -2018,17 +2138,20 @@ private final class GiftViewSheetContent: CombinedComponent { animationOffset: animationOffset, animationScale: animationScale, displayAnimationStars: showWearPreview, + revealedAttributes: state.revealedAttributes, externalState: giftCompositionExternalState, - requestUpdate: { [weak state] in - state?.updated() + requestUpdate: { [weak state] transition in + state?.updated(transition: transition) } ), availableSize: CGSize(width: context.availableSize.width, height: headerHeight), transition: context.transition ) - context.add(animation - .position(CGPoint(x: context.availableSize.width / 2.0, y: headerHeight / 2.0)) - ) + headerComponents.append({ + context.add(animation + .position(CGPoint(x: context.availableSize.width / 2.0, y: headerHeight / 2.0)) + ) + }) } originY += headerHeight @@ -2051,11 +2174,13 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: 100.0, height: 100.0), transition: context.transition ) - context.add(wearAvatar - .position(CGPoint(x: context.availableSize.width / 2.0, y: 67.0)) - .appear(.default(scale: true, alpha: true)) - .disappear(.default(scale: true, alpha: true)) - ) + headerComponents.append({ + context.add(wearAvatar + .position(CGPoint(x: context.availableSize.width / 2.0, y: 67.0)) + .appear(.default(scale: true, alpha: true)) + .disappear(.default(scale: true, alpha: true)) + ) + }) } let wearPeerStatus = wearPeerStatus.update( @@ -2074,21 +2199,19 @@ private final class GiftViewSheetContent: CombinedComponent { transition: .immediate ) - context.add(wearPeerNameChild - .position(CGPoint(x: context.availableSize.width / 2.0 - 12.0, y: 144.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) - context.add(wearPeerStatus - .position(CGPoint(x: context.availableSize.width / 2.0, y: 174.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) - originY += 18.0 - originY += 28.0 - originY += 18.0 - originY += 20.0 - originY += 24.0 + headerComponents.append({ + context.add(wearPeerNameChild + .position(CGPoint(x: context.availableSize.width / 2.0 - 12.0, y: 144.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + context.add(wearPeerStatus + .position(CGPoint(x: context.availableSize.width / 2.0, y: 174.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) + originY += 108.0 let textColor = theme.actionSheet.primaryTextColor let secondaryTextColor = theme.actionSheet.secondaryTextColor @@ -2144,11 +2267,13 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: context.availableSize.width - perksSideInset * 2.0, height: 10000.0), transition: context.transition ) - context.add(wearPerks - .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + wearPerks.size.height / 2.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) + headerComponents.append({ + context.add(wearPerks + .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + wearPerks.size.height / 2.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) originY += wearPerks.size.height originY += 16.0 } else if showUpgradePreview { @@ -2158,15 +2283,22 @@ private final class GiftViewSheetContent: CombinedComponent { let transferableText: String let tradableText: String if !incoming, case let .profileGift(peerId, _) = subject, let peer = state.peerMap[peerId] { - let name = peer.compactDisplayTitle + var peerName = peer.compactDisplayTitle + if peerName.count > 22 { + peerName = "\(peerName.prefix(22))…" + } title = environment.strings.Gift_Upgrade_GiftTitle - description = environment.strings.Gift_Upgrade_GiftDescription(name).string - uniqueText = strings.Gift_Upgrade_Unique_GiftDescription(name).string - transferableText = strings.Gift_Upgrade_Transferable_GiftDescription(name).string - tradableText = strings.Gift_Upgrade_Tradable_GiftDescription(name).string - } else if case let .upgradePreview(_, name) = component.subject { + description = environment.strings.Gift_Upgrade_GiftDescription(peerName).string + uniqueText = strings.Gift_Upgrade_Unique_GiftDescription(peerName).string + transferableText = strings.Gift_Upgrade_Transferable_GiftDescription(peerName).string + tradableText = strings.Gift_Upgrade_Tradable_GiftDescription(peerName).string + } else if case let .upgradePreview(_, peerName) = component.subject { + var peerName = peerName + if peerName.count > 22 { + peerName = "\(peerName.prefix(22))…" + } title = environment.strings.Gift_Upgrade_IncludeTitle - description = environment.strings.Gift_Upgrade_IncludeDescription(name).string + description = environment.strings.Gift_Upgrade_IncludeDescription(peerName).string uniqueText = strings.Gift_Upgrade_Unique_IncludeDescription transferableText = strings.Gift_Upgrade_Transferable_IncludeDescription tradableText = strings.Gift_Upgrade_Tradable_IncludeDescription @@ -2197,31 +2329,34 @@ private final class GiftViewSheetContent: CombinedComponent { text: .plain(NSAttributedString( string: description, font: Font.regular(13.0), - textColor: vibrantColor, + textColor: .white, paragraphAlignment: .center )), horizontalAlignment: .center, maximumNumberOfLines: 5, - lineSpacing: 0.2 + lineSpacing: 0.2, + tintColor: vibrantColor ), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude), - transition: .immediate + transition: context.transition ) let spacing: CGFloat = 6.0 let totalHeight: CGFloat = upgradeTitle.size.height + spacing + upgradeDescription.size.height - context.add(upgradeTitle - .position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 - totalHeight / 2.0 + upgradeTitle.size.height / 2.0))) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) - - context.add(upgradeDescription - .position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 + totalHeight / 2.0 - upgradeDescription.size.height / 2.0))) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) + headerComponents.append({ + context.add(upgradeTitle + .position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 - totalHeight / 2.0 + upgradeTitle.size.height / 2.0))) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + + context.add(upgradeDescription + .position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 + totalHeight / 2.0 - upgradeDescription.size.height / 2.0))) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) originY += 24.0 let textColor = theme.actionSheet.primaryTextColor @@ -2415,11 +2550,13 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude), transition: .immediate ) - context.add(title - .position(CGPoint(x: context.availableSize.width / 2.0, y: uniqueGift != nil ? 190.0 : 173.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) + headerComponents.append({ + context.add(title + .position(CGPoint(x: context.availableSize.width / 2.0, y: uniqueGift != nil ? 190.0 : 173.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) var descriptionOffset: CGFloat = 0.0 if let subtitleString { @@ -2455,14 +2592,16 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude), transition: .immediate ) - context.add(subtitle - .position(CGPoint(x: context.availableSize.width / 2.0, y: uniqueGift != nil ? 210.0 : 196.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) + headerComponents.append({ + context.add(subtitle + .position(CGPoint(x: context.availableSize.width / 2.0, y: uniqueGift != nil ? 210.0 : 196.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) descriptionOffset += subtitle.size.height } - + var useDescriptionTint = false if !descriptionText.isEmpty { var linkColor = theme.actionSheet.controlAccentColor if hasDescriptionButton { @@ -2478,18 +2617,20 @@ private final class GiftViewSheetContent: CombinedComponent { let textFont: UIFont let textColor: UIColor + if let _ = uniqueGift { textFont = Font.regular(13.0) if hasDescriptionButton { textColor = vibrantColor.mixedWith(UIColor.white, alpha: 0.4) } else { textColor = vibrantColor + useDescriptionTint = true } } else { textFont = soldOut ? Font.medium(15.0) : Font.regular(15.0) textColor = soldOut ? theme.list.itemDestructiveColor : theme.list.itemPrimaryTextColor } - let markdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: textFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: linkColor), linkAttribute: { contents in + let markdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: useDescriptionTint ? .white : textColor), bold: MarkdownAttributeSet(font: textFont, textColor: useDescriptionTint ? .white : textColor), link: MarkdownAttributeSet(font: textFont, textColor: linkColor), linkAttribute: { contents in return (TelegramTextAttributes.URL, contents) }) @@ -2504,59 +2645,126 @@ private final class GiftViewSheetContent: CombinedComponent { attributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: attributedString.string)) } - let description = description.update( - component: MultilineTextComponent( - text: .plain(attributedString), - horizontalAlignment: .center, - maximumNumberOfLines: 5, - lineSpacing: 0.2, - highlightColor: linkColor.withAlphaComponent(0.1), - highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), - highlightAction: { attributes in - if !hasDescriptionButton, let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { - return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + var descriptionSize = CGSize() + if state.justUpgraded { + var items: [AnyComponentWithIdentity] = [ + AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: "\(strings.Gift_Unique_Collectible) #", font: textFont, color: .white, tintColor: textColor))) + ] + + let numberFont = Font.with(size: 13.0, traits: .monospacedNumbers) + let spinningItems: [AnyComponentWithIdentity] = [ + AnyComponentWithIdentity(id: "0", component: AnyComponent(Text(text: "0", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "1", component: AnyComponent(Text(text: "1", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "2", component: AnyComponent(Text(text: "2", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "3", component: AnyComponent(Text(text: "3", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "4", component: AnyComponent(Text(text: "4", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "5", component: AnyComponent(Text(text: "5", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "6", component: AnyComponent(Text(text: "6", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "7", component: AnyComponent(Text(text: "7", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "8", component: AnyComponent(Text(text: "8", font: numberFont, color: textColor))), + AnyComponentWithIdentity(id: "9", component: AnyComponent(Text(text: "9", font: numberFont, color: textColor))) + ] + if let numberValue = uniqueGift?.number { + let numberString = formatCollectibleNumber(numberValue, dateTimeFormat: environment.dateTimeFormat) + var i = 0 + var index = 0 + for c in numberString { + let s = String(c) + if s == "\u{00A0}" { + items.append(AnyComponentWithIdentity(id: "c\(i)", component: AnyComponent(Text(text: s, font: textFont, color: .white, tintColor: textColor))) + ) + } else if ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].contains(s) { + items.append(AnyComponentWithIdentity(id: "c\(i)", component: AnyComponent(SlotsComponent( + item: AnyComponent(Text(text: String(c), font: numberFont, color: .white)), + items: spinningItems, + isAnimating: index > state.revealedNumberDigits, + tintColor: textColor, + verticalOffset: -1.0 - UIScreenPixel, + motionBlur: false, + size: CGSize(width: 8.0, height: 14.0)))) + ) + index += 1 } else { - return nil - } - }, - tapAction: { [weak state] attributes, _ in - if !hasDescriptionButton, let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { - state?.openStarsIntro() + items.append(AnyComponentWithIdentity(id: "c\(i)", component: AnyComponent(Text(text: s, font: numberFont, color: .white, tintColor: textColor))) + ) } + i += 1 } - ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude), - transition: .immediate - ) - context.add(description - .position(CGPoint(x: context.availableSize.width / 2.0, y: 207.0 + descriptionOffset + description.size.height / 2.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) - ) - - if hasDescriptionButton { - let descriptionButton = descriptionButton.update( - component: PlainButtonComponent( - content: AnyComponent( - RoundedRectangle(color: UIColor.white.withAlphaComponent(0.15), cornerRadius: 9.5) - ), - effectAlignment: .center, - action: { [weak state] in - if let releasedByPeer { - state?.openPeer(releasedByPeer) + } + let animatedDescription = animatedDescription.update( + component: HStack(items, spacing: 0.0), + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude), + transition: context.transition + ) + descriptionSize = animatedDescription.size + headerComponents.append({ + context.add(animatedDescription + .position(CGPoint(x: context.availableSize.width / 2.0, y: 207.0 + descriptionOffset + animatedDescription.size.height / 2.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) + } else { + let description = description.update( + component: MultilineTextComponent( + text: .plain(attributedString), + horizontalAlignment: .center, + maximumNumberOfLines: 5, + lineSpacing: 0.2, + tintColor: useDescriptionTint ? textColor : nil, + highlightColor: linkColor.withAlphaComponent(0.1), + highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0), + highlightAction: { attributes in + if !hasDescriptionButton, let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { + return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + } else { + return nil } }, - animateScale: false + tapAction: { [weak state] attributes, _ in + if !hasDescriptionButton, let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String { + state?.openStarsIntro() + } + } ), - environment: {}, - availableSize: CGSize(width: description.size.width + 18.0, height: 19.0), - transition: .immediate - ) - context.add(descriptionButton - .position(CGPoint(x: context.availableSize.width / 2.0, y: 207.0 + descriptionOffset + description.size.height / 2.0 - 1.0)) - .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude), + transition: context.transition ) + descriptionSize = description.size + headerComponents.append({ + context.add(description + .position(CGPoint(x: context.availableSize.width / 2.0, y: 207.0 + descriptionOffset + description.size.height / 2.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) + + if hasDescriptionButton { + let descriptionButton = descriptionButton.update( + component: PlainButtonComponent( + content: AnyComponent( + RoundedRectangle(color: UIColor.white.withAlphaComponent(0.15), cornerRadius: 9.5) + ), + effectAlignment: .center, + action: { [weak state] in + if let releasedByPeer { + state?.openPeer(releasedByPeer) + } + }, + animateScale: false + ), + environment: {}, + availableSize: CGSize(width: description.size.width + 18.0, height: 19.0), + transition: .immediate + ) + headerComponents.append({ + context.add(descriptionButton + .position(CGPoint(x: context.availableSize.width / 2.0, y: 207.0 + descriptionOffset + description.size.height / 2.0 - 1.0)) + .appear(.default(alpha: true)) + .disappear(.default(alpha: true)) + ) + }) + } } originY += descriptionOffset @@ -2564,7 +2772,7 @@ private final class GiftViewSheetContent: CombinedComponent { if uniqueGift != nil { originY += 16.0 } else { - originY += description.size.height + 21.0 + originY += descriptionSize.height + 21.0 if soldOut { originY -= 7.0 } @@ -2581,7 +2789,11 @@ private final class GiftViewSheetContent: CombinedComponent { if incoming { hiddenDescription = text != nil ? strings.Gift_View_NameAndMessageHidden : strings.Gift_View_NameHidden } else if let peerId = subject.arguments?.peerId, let peer = state.peerMap[peerId], subject.arguments?.fromPeerId != nil { - hiddenDescription = text != nil ? strings.Gift_View_Outgoing_NameAndMessageHidden(peer.compactDisplayTitle).string : strings.Gift_View_Outgoing_NameHidden(peer.compactDisplayTitle).string + var peerName = peer.compactDisplayTitle + if peerName.count > 30 { + peerName = "\(peerName.prefix(30))…" + } + hiddenDescription = text != nil ? strings.Gift_View_Outgoing_NameAndMessageHidden(peerName).string : strings.Gift_View_Outgoing_NameHidden(peerName).string } else { hiddenDescription = "" } @@ -2876,11 +3088,14 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: buttonWidth, height: buttonHeight), transition: context.transition ) - context.add(transferButton - .position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0)) - .appear(.default(scale: true, alpha: true)) - .disappear(.default(scale: true, alpha: true)) - ) + let buttonPosition = buttonOriginX + buttonWidth / 2.0 + headerComponents.append({ + context.add(transferButton + .position(CGPoint(x: buttonPosition, y: headerHeight - buttonHeight / 2.0 - 16.0)) + .appear(.default(scale: true, alpha: true)) + .disappear(.default(scale: true, alpha: true)) + ) + }) buttonOriginX += buttonWidth + buttonSpacing } @@ -2936,11 +3151,14 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: buttonWidth, height: buttonHeight), transition: context.transition ) - context.add(wearButton - .position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0)) - .appear(.default(scale: true, alpha: true)) - .disappear(.default(scale: true, alpha: true)) - ) + let buttonPosition = buttonOriginX + buttonWidth / 2.0 + headerComponents.append({ + context.add(wearButton + .position(CGPoint(x: buttonPosition, y: headerHeight - buttonHeight / 2.0 - 16.0)) + .appear(.default(scale: true, alpha: true)) + .disappear(.default(scale: true, alpha: true)) + ) + }) buttonOriginX += buttonWidth + buttonSpacing if canResell { @@ -2961,16 +3179,19 @@ private final class GiftViewSheetContent: CombinedComponent { availableSize: CGSize(width: buttonWidth, height: buttonHeight), transition: context.transition ) - context.add(resellButton - .position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0)) - .appear(.default(scale: true, alpha: true)) - .disappear(.default(scale: true, alpha: true)) - ) + let buttonPosition = buttonOriginX + buttonWidth / 2.0 + headerComponents.append({ + context.add(resellButton + .position(CGPoint(x: buttonPosition, y: headerHeight - buttonHeight / 2.0 - 16.0)) + .appear(.default(scale: true, alpha: true)) + .disappear(.default(scale: true, alpha: true)) + ) + }) } } let order: [StarGift.UniqueGift.Attribute.AttributeType] = [ - .model, .backdrop, .pattern, .originalInfo + .model, .pattern, .backdrop, .originalInfo ] var attributeMap: [StarGift.UniqueGift.Attribute.AttributeType: StarGift.UniqueGift.Attribute] = [:] @@ -2981,13 +3202,15 @@ private final class GiftViewSheetContent: CombinedComponent { var hasOriginalInfo = false for type in order { if let attribute = attributeMap[type] { - let id: String + var id: String let title: String? let value: NSAttributedString let percentage: Float? let tag: AnyObject? var hasBackground = false + var otherValuesAndPercentages: [(value: String, percentage: Float)] = [] + switch attribute { case let .model(name, _, rarity): id = "model" @@ -2995,18 +3218,42 @@ private final class GiftViewSheetContent: CombinedComponent { value = NSAttributedString(string: name, font: tableFont, textColor: tableTextColor) percentage = Float(rarity) * 0.1 tag = state.modelButtonTag + + if state.justUpgraded, let sampleAttributes = state.sampleGiftAttributes { + for sampleAttribute in sampleAttributes { + if case let .model(name, _, rarity) = sampleAttribute { + otherValuesAndPercentages.append((name, Float(rarity) * 0.1)) + } + } + } case let .backdrop(name, _, _, _, _, _, rarity): id = "backdrop" title = strings.Gift_Unique_Backdrop value = NSAttributedString(string: name, font: tableFont, textColor: tableTextColor) percentage = Float(rarity) * 0.1 tag = state.backdropButtonTag + + if state.justUpgraded, let sampleAttributes = state.sampleGiftAttributes { + for sampleAttribute in sampleAttributes { + if case let .backdrop(name, _, _, _, _, _, rarity) = sampleAttribute { + otherValuesAndPercentages.append((name, Float(rarity) * 0.1)) + } + } + } case let .pattern(name, _, rarity): id = "pattern" title = strings.Gift_Unique_Symbol value = NSAttributedString(string: name, font: tableFont, textColor: tableTextColor) percentage = Float(rarity) * 0.1 tag = state.symbolButtonTag + + if state.justUpgraded, let sampleAttributes = state.sampleGiftAttributes { + for sampleAttribute in sampleAttributes { + if case let .pattern(name, _, rarity) = sampleAttribute { + otherValuesAndPercentages.append((name, Float(rarity) * 0.1)) + } + } + } case let .originalInfo(senderPeerId, recipientPeerId, date, text, entities): id = "originalInfo" title = nil @@ -3058,6 +3305,10 @@ private final class GiftViewSheetContent: CombinedComponent { hasOriginalInfo = true } + if !otherValuesAndPercentages.isEmpty { + id += "_reel" + } + var items: [AnyComponentWithIdentity] = [] items.append( AnyComponentWithIdentity( @@ -3108,9 +3359,41 @@ private final class GiftViewSheetContent: CombinedComponent { ).tagged(tag)) )) } - let itemComponent = AnyComponent( + var itemComponent = AnyComponent( HStack(items, spacing: 4.0) ) + + if !otherValuesAndPercentages.isEmpty { + var subitems: [AnyComponentWithIdentity] = [] + var index = 0 + + for (title, percentage) in otherValuesAndPercentages { + subitems.append( + AnyComponentWithIdentity(id: "anim_\(index)", component: AnyComponent( + HStack([ + AnyComponentWithIdentity(id: "label", component: AnyComponent(Text(text: title, font: tableFont, color: tableTextColor))), + AnyComponentWithIdentity(id: "rarity", component: AnyComponent(ButtonContentComponent( + context: component.context, + text: formatPercentage(percentage), + color: theme.list.itemAccentColor + ))) + ], spacing: 4.0) + )) + ) + index += 1 + } + + itemComponent = AnyComponent( + SlotsComponent( + item: itemComponent, + items: subitems, + isAnimating: !state.revealedAttributes.contains(type), + motionBlur: false, + size: CGSize(width: 160.0, height: 18.0) + ) + ) + } + tableItems.append(.init( id: id, title: title, @@ -3130,11 +3413,10 @@ private final class GiftViewSheetContent: CombinedComponent { ) ), at: hasOriginalInfo ? tableItems.count - 1 : tableItems.count) - //TODO:localize if let valueAmount = uniqueGift.valueAmount, let valueCurrency = uniqueGift.valueCurrency { tableItems.insert(.init( id: "fiatValue", - title: "Value", + title: strings.Gift_Unique_Value, component: AnyComponent( HStack([ AnyComponentWithIdentity( @@ -3146,7 +3428,7 @@ private final class GiftViewSheetContent: CombinedComponent { component: AnyComponent(Button( content: AnyComponent(ButtonContentComponent( context: component.context, - text: "learn more", + text: strings.Gift_Unique_LearnMore, color: theme.list.itemAccentColor )), action: { [weak state] in @@ -3325,10 +3607,19 @@ private final class GiftViewSheetContent: CombinedComponent { context.add(table .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + table.size.height / 2.0)) .appear(.default(alpha: true)) - .disappear(.default(alpha: true)) + .disappear(ComponentTransition.Disappear({ view, transition, completion in + view.superview?.insertSubview(view, at: 0) + transition.setAlpha(view: view, alpha: 0.0, completion: { _ in + completion() + }) + })) ) originY += table.size.height + 23.0 } + + for component in headerComponents { + component() + } var resellAmount: CurrencyAmount? var selling = false @@ -3597,9 +3888,8 @@ private final class GiftViewSheetContent: CombinedComponent { } var upgradeString = strings.Gift_Upgrade_Upgrade if !incoming { - //TODO:localize if let gift = state.starGiftsMap[giftId], let upgradeStars = gift.upgradeStars { - upgradeString = "Pay # \(upgradeStars) for Upgrade" + upgradeString = strings.Gift_Upgrade_GiftUpgrade(" # \(upgradeStars)").string } } else if let upgradeForm = state.upgradeForm, let price = upgradeForm.invoice.prices.first?.amount { upgradeString += " # \(presentationStringsFormattedNumber(Int32(price), environment.dateTimeFormat.groupingSeparator))" @@ -3653,8 +3943,7 @@ private final class GiftViewSheetContent: CombinedComponent { } else if (incoming && !converted && !upgraded && canUpgrade) || canGiftUpgrade { let buttonTitle: String if canGiftUpgrade { - //TODO:localize - buttonTitle = "Gift an Upgrade" + buttonTitle = strings.Gift_View_GiftUpgrade } else if let upgradeStars, upgradeStars > 0 { buttonTitle = strings.Gift_View_UpgradeForFree } else { @@ -3994,7 +4283,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { case let .message(message): if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction { switch action.action { - case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, _, upgradeMessageId, peerId, senderId, savedId, prepaidUpgradeHash, giftMessageId): + case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded, _, upgradeMessageId, peerId, senderId, savedId, prepaidUpgradeHash, giftMessageId, _): var reference: StarGiftReference if let peerId, let giftMessageId { reference = .message(messageId: EngineMessage.Id(peerId: peerId, namespace: Namespaces.Message.Cloud, id: giftMessageId)) @@ -4187,9 +4476,15 @@ public class GiftViewScreen: ViewControllerComponentContainer { } fileprivate func switchToNextUpgradable() { - guard let upgradableGifts = self.upgradableGifts, case let .profileGift(peerId, _) = self.subject else { + guard let upgradableGifts = self.upgradableGifts else { return } + let peerId: EnginePeer.Id + if case let .profileGift(peerIdValue, _) = self.subject { + peerId = peerIdValue + } else { + peerId = self.context.account.peerId + } var effectiveUpgradableGifts: [ProfileGiftsContext.State.StarGift] = [] for gift in upgradableGifts { if let reference = gift.reference { @@ -4367,7 +4662,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { } func formatPercentage(_ value: Float) -> String { - return String(format: "%0.1f%%", value).replacingOccurrences(of: ".0%", with: "%").replacingOccurrences(of: ",0%", with: "%") + return String(format: "%0.1f", value).replacingOccurrences(of: ".0", with: "").replacingOccurrences(of: ",0", with: "") + "%" } private final class PeerCellComponent: Component { diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/SlotsComponent.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/SlotsComponent.swift new file mode 100644 index 0000000000..93d348a966 --- /dev/null +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/SlotsComponent.swift @@ -0,0 +1,496 @@ +import Foundation +import UIKit +import Display +import ComponentFlow +import ImageBlur + +private let additionalInset: CGFloat = 4.0 +private let maskInset: CGFloat = 8.0 + +final class SlotsComponent: Component { + public typealias EnvironmentType = ChildEnvironment + + private let item: AnyComponent + private let items: [AnyComponentWithIdentity] + private let isAnimating: Bool + private let tintColor: UIColor? + private let verticalOffset: CGFloat + private let motionBlur: Bool + private let size: CGSize + + public init( + item: AnyComponent, + items: [AnyComponentWithIdentity], + isAnimating: Bool, + tintColor: UIColor? = nil, + verticalOffset: CGFloat = 0.0, + motionBlur: Bool = true, + size: CGSize + ) { + self.item = item + self.items = items + self.isAnimating = isAnimating + self.tintColor = tintColor + self.verticalOffset = verticalOffset + self.motionBlur = motionBlur + self.size = size + } + + public static func == (lhs: SlotsComponent, rhs: SlotsComponent) -> Bool { + if lhs.item != rhs.item { + return false + } + if lhs.items != rhs.items { + return false + } + if lhs.isAnimating != rhs.isAnimating { + return false + } + if lhs.tintColor != rhs.tintColor { + return false + } + if lhs.verticalOffset != rhs.verticalOffset { + return false + } + if lhs.motionBlur != rhs.motionBlur { + return false + } + if lhs.size != rhs.size { + return false + } + return true + } + + public final class View: UIView { + private var itemViews: [AnyHashable: ComponentView] = [:] + private var motionBlurLayers: [AnyHashable: SimpleLayer] = [:] + private var order: [AnyHashable] = [] + + private let containerView = UIView() + private let maskLayer = SimpleGradientLayer() + + private enum SpinState { + case idle + case spinning + case decelerating + case settled + } + + private var spinState: SpinState = .idle + private var isAnimating = false + private var animationLink: SharedDisplayLinkDriver.Link? + + private var currentIds = Set() + private var lastSpawnTime: Double? + private var currentInterval: Double = 0.09 + + private var motionBlurFactor: CGFloat = 1.0 + private var decelQueue: [AnyComponentWithIdentity] = [] + private var decelTotalSteps: Int = 0 + private var decelStepIndex: Int = 0 + + private let minSpawnInterval: Double = 0.10 + private let maxSpawnInterval: Double = 0.80 + + private let baseAnimDuration: Double = 0.18 + private let maxAnimDuration: Double = 0.5 + + private var component: SlotsComponent? + private var environment: Environment? + private var availableSize: CGSize? + + @inline(__always) private func lerp(_ a: Double, _ b: Double, _ t: Double) -> Double { a + (b - a) * t } + @inline(__always) private func clamp01(_ x: Double) -> Double { max(0.0, min(1.0, x)) } + + override init(frame: CGRect) { + super.init(frame: frame) + self.addSubview(self.containerView) + + self.containerView.clipsToBounds = true + + self.maskLayer.startPoint = CGPoint(x: 0.5, y: 0.0) + self.maskLayer.endPoint = CGPoint(x: 0.5, y: 1.0) + + let fade: CGFloat = 0.2 + self.maskLayer.locations = [0.0, NSNumber(value: Float(fade)), NSNumber(value: Float(1.0 - fade)), 1.0] + self.maskLayer.colors = [ + UIColor.black.withAlphaComponent(0.0).cgColor, + UIColor.black.withAlphaComponent(1.0).cgColor, + UIColor.black.withAlphaComponent(1.0).cgColor, + UIColor.black.withAlphaComponent(0.0).cgColor + ] + self.containerView.layer.mask = self.maskLayer + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func spawnRandomSlot(availableSize: CGSize) { + guard var items = self.component?.items, !items.isEmpty else { return } + items = items.filter { !self.currentIds.contains($0.id) } + guard let randomItem = items.randomElement() else { return } + + self.spawnSlot(item: randomItem, availableSize: availableSize) {} + } + + private func spawnSlot( + item: AnyComponentWithIdentity, + isFinal: Bool = false, + availableSize: CGSize, + animDuration: Double? = nil, + completion: @escaping () -> Void + ) { + guard let component = self.component, let environment = self.environment else { return } + + self.currentIds.insert(item.id) + self.lastSpawnTime = CACurrentMediaTime() + + let itemView = self.itemViews[item.id] ?? ComponentView() + self.itemViews[item.id] = itemView + + let size = itemView.update( + transition: .immediate, + component: item.component, + environment: { environment[ChildEnvironment.self] }, + containerSize: availableSize + ) + if let view = itemView.view { + if view.superview == nil { + if let tintColor = component.tintColor { + view.layer.layerTintColor = tintColor.cgColor + } + view.layer.allowsGroupOpacity = true + self.containerView.addSubview(view) + } + view.frame = CGRect(origin: CGPoint(x: 0.0, y: -size.height - additionalInset), size: size) + + let travelDistance = (size.height + maskInset + additionalInset) * 2.0 + let pitch = (size.height + additionalInset) + + if isFinal { + var finalFrame = view.frame + finalFrame.origin.y = maskInset + view.frame = finalFrame + + let fromY = size.height + maskInset + additionalInset + let overshoot: CGFloat = 7.0 + + let anim = CAKeyframeAnimation(keyPath: "position.y") + anim.isAdditive = true + anim.values = [ fromY, -overshoot, 0.0 ] + anim.keyTimes = [0.0, 0.7, 1.0] + anim.timingFunctions = [ + CAMediaTimingFunction(name: .easeOut), + CAMediaTimingFunction(name: .easeInEaseOut) + ] + anim.duration = 0.5 + + CATransaction.begin() + CATransaction.setCompletionBlock { + completion() + self.currentIds.remove(item.id) + self.finishSettled() + } + view.layer.add(anim, forKey: "finalOvershoot") + CATransaction.commit() + } + else { + let duration: Double = animDuration ?? baseAnimDuration + + view.layer.animatePosition( + from: CGPoint(x: 0.0, y: (size.height + maskInset + additionalInset) * 2.0), + to: .zero, + duration: duration, + timingFunction: CAMediaTimingFunctionName.linear.rawValue, + additive: true, + completion: { _ in + completion() + self.currentIds.remove(item.id) + } + ) + + let intervalForConstantSpacing = Double(pitch / travelDistance) * duration + self.currentInterval = intervalForConstantSpacing + } + } + + self.setMotionBlurFactor(id: item.id, factor: self.motionBlurFactor, transition: .immediate) + } + + private func setMotionBlurFactor(id: AnyHashable, factor: CGFloat, transition: ComponentTransition) { + guard let component = self.component, component.motionBlur, let itemView = self.itemViews[id]?.view else { + return + } + + if factor != 0.0 { + let motionBlurLayer: SimpleLayer + if let current = self.motionBlurLayers[id] { + motionBlurLayer = current + } else { + motionBlurLayer = SimpleLayer() + + let image = generateImage(itemView.bounds.size, rotatedContext: { size, context in + UIGraphicsPushContext(context) + defer { UIGraphicsPopContext() } + context.clear(CGRect(origin: CGPoint(), size: size)) + itemView.layer.render(in: context) + }) + if let image { + motionBlurLayer.contents = verticalBlurredImage(image, radius: 8.0)?.cgImage + } + motionBlurLayer.contentsScale = itemView.layer.contentsScale + self.motionBlurLayers[id] = motionBlurLayer + itemView.layer.addSublayer(motionBlurLayer) + + motionBlurLayer.position = CGPoint(x: itemView.bounds.size.width * 0.5, y: itemView.bounds.size.height * 0.5) + motionBlurLayer.bounds = CGRect(origin: CGPoint(), size: itemView.bounds.size) + + if let tintColor = component.tintColor { + motionBlurLayer.layerTintColor = tintColor.cgColor + } + } + + let scaleFactor = 1.0 * (1.0 - factor) + 1.25 * factor + let opacityFactor = 1.0 * (1.0 - factor) + 0.6 * factor + transition.setTransform(layer: motionBlurLayer, transform: CATransform3DMakeScale(1.0, scaleFactor, 1.0)) + transition.setAlpha(layer: itemView.layer, alpha: opacityFactor) + } else if let motionBlurLayer = self.motionBlurLayers[id] { + self.motionBlurLayers.removeValue(forKey: id) + transition.setAlpha(layer: motionBlurLayer, alpha: 0.0, completion: { [weak motionBlurLayer] _ in + motionBlurLayer?.removeFromSuperlayer() + }) + transition.setTransform(layer: motionBlurLayer, transform: CATransform3DIdentity) + } + } + + private func beginSpinning() { + self.spinState = .spinning + self.isAnimating = true + self.motionBlurFactor = 1.0 + self.currentInterval = 0.1 + + self.ensureDisplayLink() + } + + private func beginDeceleration() { + guard let component = self.component, self.spinState == .spinning || self.spinState == .decelerating else { return } + + self.spinState = .decelerating + self.isAnimating = false + + var queue: [AnyComponentWithIdentity] = [] + if !component.items.isEmpty { + let shuffled = Array(component.items.shuffled().prefix(3)) + queue.append(contentsOf: shuffled) + } + queue.append(AnyComponentWithIdentity(id: "final", component: component.item)) + + self.decelQueue = queue + self.decelTotalSteps = queue.count + self.decelStepIndex = 0 + + self.motionBlurFactor = max(self.motionBlurFactor, 0.0001) + + self.ensureDisplayLink() + } + + private func ensureDisplayLink() { + guard self.animationLink == nil else { + return + } + self.animationLink = SharedDisplayLinkDriver.shared.add(framesPerSecond: .max, { [weak self] _ in + self?.tick() + }) + } + + private func invalidateDisplayLinkIfIdle() { + if self.spinState == .idle || self.spinState == .settled { + self.animationLink?.invalidate() + self.animationLink = nil + } + } + + private func applyEdge3DSquish() { + let H = self.containerView.bounds.height + guard H > 0 else { return } + + CATransaction.begin() + CATransaction.setDisableActions(true) + for (_, cv) in self.itemViews { + guard let v = cv.view, v.superview === self.containerView else { continue } + let midY = liveMidY(in: self.containerView, of: v) + let scaleY = edgeScaleY(for: midY, containerHeight: H) + var t = CATransform3DIdentity + t = CATransform3DScale(t, 1.0, scaleY, 1.0) + v.layer.transform = t + } + CATransaction.commit() + } + + private func tick() { + guard let availableSize = self.availableSize else { + return + } + let now = CACurrentMediaTime() + + switch self.spinState { + case .spinning: + if let last = self.lastSpawnTime, now - last >= self.currentInterval || self.lastSpawnTime == nil { + self.spawnRandomSlot(availableSize: availableSize) + } + case .decelerating: + let t = clamp01(self.decelTotalSteps > 1 ? Double(self.decelStepIndex) / Double(self.decelTotalSteps - 1) : 1.0) + + if let last = self.lastSpawnTime, now - last >= self.currentInterval { + if !self.decelQueue.isEmpty { + let next = self.decelQueue.removeFirst() + let isFinal = self.decelQueue.isEmpty + let animDuration = isFinal ? nil : lerp(baseAnimDuration, maxAnimDuration, t) + self.spawnSlot(item: next, isFinal: isFinal, availableSize: availableSize, animDuration: animDuration, completion: {}) + + self.motionBlurFactor = CGFloat(1.0 - t) + + self.decelStepIndex += 1 + } + } else if self.lastSpawnTime == nil { + if !self.decelQueue.isEmpty { + let next = self.decelQueue.removeFirst() + self.spawnSlot(item: next, availableSize: availableSize) {} + } + } + + case .settled, .idle: + self.invalidateDisplayLinkIfIdle() + } + + self.applyEdge3DSquish() + } + + private func finishSettled() { + for (id, _) in self.motionBlurLayers { + self.setMotionBlurFactor(id: id, factor: 0.0, transition: .easeInOut(duration: 0.2)) + } + self.motionBlurLayers.removeAll() + + self.spinState = .settled + self.decelQueue.removeAll() + self.invalidateDisplayLinkIfIdle() + } + + func update( + component: SlotsComponent, + availableSize: CGSize, + state: EmptyComponentState, + environment: Environment, + transition: ComponentTransition + ) -> CGSize { + self.component = component + self.environment = environment + self.availableSize = availableSize + + let size = component.size + self.containerView.frame = CGRect(origin: CGPoint(x: 0.0, y: component.verticalOffset), size: size).insetBy(dx: 0.0, dy: -maskInset) + self.maskLayer.frame = CGRect(origin: .zero, size: self.containerView.bounds.size) + + let wasAnimating = self.isAnimating + let nowAnimating = component.isAnimating + + if nowAnimating && !wasAnimating { + self.beginSpinning() + self.spawnRandomSlot(availableSize: availableSize) + } else if !nowAnimating && wasAnimating { + self.beginDeceleration() + } else if nowAnimating && self.spinState == .settled { + self.beginSpinning() + self.spawnRandomSlot(availableSize: availableSize) + } + + if let tintColor = component.tintColor { + for (id, itemView) in self.itemViews { + if let itemLayer = itemView.view?.layer { + transition.setTintColor(layer: itemLayer, color: tintColor) + } + if let blurLayer = self.motionBlurLayers[id] { + transition.setTintColor(layer: blurLayer, color: tintColor) + } + } + } + + return size + } + } + + public func makeView() -> View { + return View() + } + + public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} + +private let minScaleYAtEdge: CGFloat = 0.7 +private let squishFalloff: CGFloat = 0.12 + +private func smoothstep(_ x: CGFloat) -> CGFloat { + let t = max(0.0, min(1.0, x)) + return t * t * (3.0 - 2.0 * t) +} + +private func liveMidY(in container: UIView, of view: UIView) -> CGFloat { + if let pres = view.layer.presentation() { + let p = container.layer.convert(pres.position, from: view.layer.superlayer) + return p.y + } + return view.center.y +} + +private func edgeScaleY(for midY: CGFloat, containerHeight H: CGFloat) -> CGFloat { + guard H > 0 else { return 1.0 } + let d = abs((midY - H * 0.5) / (H * 0.5)) + let uRaw = (d - squishFalloff) / (1.0 - squishFalloff) + let u = smoothstep(max(0.0, min(1.0, uRaw))) + return (1.0 - u) + minScaleYAtEdge * u +} + + +final class SpacerComponent: Component { + let size: CGSize + + init( + size: CGSize + ) { + self.size = size + } + + static func ==(lhs: SpacerComponent, rhs: SpacerComponent) -> Bool { + return lhs.size == rhs.size + } + + final class View: UIView { + private var component: SpacerComponent? + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func update(component: SpacerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + self.component = component + + return component.size + } + } + + func makeView() -> View { + return View(frame: CGRect()) + } + + func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment, transition: ComponentTransition) -> CGSize { + return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition) + } +} diff --git a/submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/BUILD b/submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/BUILD new file mode 100644 index 0000000000..25de730ac0 --- /dev/null +++ b/submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/BUILD @@ -0,0 +1,25 @@ +load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library") + +swift_library( + name = "PeerMessagesMediaPlaylist", + module_name = "PeerMessagesMediaPlaylist", + srcs = glob([ + "Sources/**/*.swift", + ]), + copts = [ + "-warnings-as-errors", + ], + deps = [ + "//submodules/Display", + "//submodules/ComponentFlow", + "//submodules/SSignalKit/SwiftSignalKit", + "//submodules/TelegramCore", + "//submodules/TelegramUIPreferences", + "//submodules/AccountContext", + "//submodules/MusicAlbumArtResources", + "//submodules/TextFormat", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/Sources/PeerMessagesMediaPlaylist.swift similarity index 91% rename from submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift rename to submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/Sources/PeerMessagesMediaPlaylist.swift index e919761504..6565bf17c5 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist/Sources/PeerMessagesMediaPlaylist.swift @@ -47,22 +47,29 @@ private func extractFileMedia(_ message: Message) -> TelegramMediaFile? { return file } -final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { - let id: SharedMediaPlaylistItemId - let message: Message +public final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { + public let id: SharedMediaPlaylistItemId + public let message: Message + public let isSavedMusic: Bool - init(message: Message) { + public init(message: Message, isSavedMusic: Bool) { self.id = PeerMessagesMediaPlaylistItemId(messageId: message.id, messageIndex: message.index) self.message = message + self.isSavedMusic = isSavedMusic } - var stableId: AnyHashable { + public var stableId: AnyHashable { return MessageMediaPlaylistItemStableId(stableId: message.stableId) } - lazy var playbackData: SharedMediaPlaybackData? = { + public lazy var playbackData: SharedMediaPlaybackData? = { if let file = extractFileMedia(self.message) { - let fileReference = FileMediaReference.message(message: MessageReference(self.message), media: file) + let fileReference: FileMediaReference + if self.isSavedMusic, let peer = self.message.peers[self.message.id.peerId], let peerReference = PeerReference(peer) { + fileReference = .savedMusic(peer: peerReference, media: file) + } else { + fileReference = .message(message: MessageReference(self.message), media: file) + } let source = SharedMediaPlaybackDataSource.telegramFile(reference: fileReference, isCopyProtected: self.message.isCopyProtected(), isViewOnce: self.message.minAutoremoveOrClearTimeout == viewOnceTimeout) for attribute in file.attributes { switch attribute { @@ -95,7 +102,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { return nil }() - lazy var displayData: SharedMediaPlaybackDisplayData? = { + public lazy var displayData: SharedMediaPlaybackDisplayData? = { if let file = extractFileMedia(self.message) { let text = self.message.text var entities: [MessageTextEntity] = [] @@ -385,16 +392,16 @@ private struct PlaybackStack { } } -final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { - let context: AccountContext +public final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { + public let context: AccountContext private let messagesLocation: PeerMessagesPlaylistLocation private let chatLocationContextHolder: Atomic? - var location: SharedMediaPlaylistLocation { + public var location: SharedMediaPlaylistLocation { return self.messagesLocation } - var currentItemDisappeared: (() -> Void)? + public var currentItemDisappeared: (() -> Void)? private let navigationDisposable = MetaDisposable() private let loadMoreDisposable = MetaDisposable() @@ -408,16 +415,16 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { private var loadingMore: Bool = false private var playedToEnd: Bool = false private var order: MusicPlaybackSettingsOrder = .regular - private(set) var looping: MusicPlaybackSettingsLooping = .none + public private(set) var looping: MusicPlaybackSettingsLooping = .none - let id: SharedMediaPlaylistId + public let id: SharedMediaPlaylistId private let stateValue = Promise() - var state: Signal { + public var state: Signal { return self.stateValue.get() } - init(context: AccountContext, location: PeerMessagesPlaylistLocation, chatLocationContextHolder: Atomic?) { + public init(context: AccountContext, location: PeerMessagesPlaylistLocation, chatLocationContextHolder: Atomic?) { assert(Queue.mainQueue().isCurrent()) self.id = location.playlistId @@ -426,13 +433,15 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { self.chatLocationContextHolder = chatLocationContextHolder self.messagesLocation = location - switch self.messagesLocation { + switch self.messagesLocation.effectiveLocation(context: context) { case let .messages(_, _, messageId), let .singleMessage(messageId), let .custom(_, _, messageId, _): self.loadItem(anchor: .messageId(messageId), navigation: .later, reversed: self.order == .reversed) case let .recentActions(message): self.loadingItem = false self.currentItem = (message, []) self.updateState() + case .savedMusic: + break } } @@ -442,7 +451,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { self.currentlyObservedMessageDisposable.dispose() } - func control(_ action: SharedMediaPlaylistControlAction) { + public func control(_ action: SharedMediaPlaylistControlAction) { assert(Queue.mainQueue().isCurrent()) switch action { @@ -488,7 +497,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } } - func setOrder(_ order: MusicPlaybackSettingsOrder) { + public func setOrder(_ order: MusicPlaybackSettingsOrder) { if self.order != order { self.order = order self.playbackStack.clear() @@ -499,7 +508,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } } - func setLooping(_ looping: MusicPlaybackSettingsLooping) { + public func setLooping(_ looping: MusicPlaybackSettingsLooping) { if self.looping != looping { self.looping = looping self.updateState() @@ -507,21 +516,26 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } private func updateState() { + var isSavedMusic = false + if case .savedMusic = self.messagesLocation { + isSavedMusic = true + } + var item: MessageMediaPlaylistItem? var nextItem: MessageMediaPlaylistItem? var previousItem: MessageMediaPlaylistItem? if let (message, aroundMessages) = self.currentItem { - item = MessageMediaPlaylistItem(message: message) + item = MessageMediaPlaylistItem(message: message, isSavedMusic: isSavedMusic) for around in aroundMessages { if around.index < message.index { - previousItem = MessageMediaPlaylistItem(message: around) + previousItem = MessageMediaPlaylistItem(message: around, isSavedMusic: isSavedMusic) } else { - nextItem = MessageMediaPlaylistItem(message: around) + nextItem = MessageMediaPlaylistItem(message: around, isSavedMusic: isSavedMusic) } } } self.stateValue.set(.single(SharedMediaPlaylistState(loading: self.loadingItem, playedToEnd: self.playedToEnd, item: item, nextItem: nextItem, previousItem: previousItem, order: self.order, looping: self.looping))) - if case .custom = self.messagesLocation { + if case .custom = self.messagesLocation.effectiveLocation(context: self.context) { } else if item?.message.id != self.currentlyObservedMessageId { self.currentlyObservedMessageId = item?.message.id if let id = item?.message.id { @@ -555,10 +569,10 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } else { namespaces = .not(Namespaces.Message.allNonRegular) } - + switch anchor { case let .messageId(messageId): - switch self.messagesLocation { + switch self.messagesLocation.effectiveLocation(context: self.context) { case let .messages(chatLocation, tagMask, _): let historySignal = self.context.account.postbox.messageAtId(messageId) |> take(1) @@ -598,25 +612,26 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { self.navigationDisposable.set((messages |> take(1) |> deliverOnMainQueue).startStrict(next: { [weak self] messages in - if let strongSelf = self { - assert(strongSelf.loadingItem) - - strongSelf.loadingItem = false - if let message = messages.0.first(where: { $0.id == at }) { - strongSelf.playbackStack.clear() - strongSelf.playbackStack.push(message.id) - if let (message, aroundMessages, _) = navigatedMessageFromMessages(messages.0, anchorIndex: message.index, position: .exact) { - strongSelf.currentItem = (message, aroundMessages) - } else { - strongSelf.currentItem = (message, []) - } - strongSelf.playedToEnd = false - } else { - strongSelf.currentItem = nil - strongSelf.playedToEnd = true - } - strongSelf.updateState() + guard let self else { + return } + assert(self.loadingItem) + + self.loadingItem = false + if let message = messages.0.first(where: { $0.id == at }) { + self.playbackStack.clear() + self.playbackStack.push(message.id) + if let (message, aroundMessages, _) = navigatedMessageFromMessages(messages.0, anchorIndex: message.index, position: .exact) { + self.currentItem = (message, aroundMessages) + } else { + self.currentItem = (message, []) + } + self.playedToEnd = false + } else { + self.currentItem = nil + self.playedToEnd = true + } + self.updateState() })) default: self.navigationDisposable.set((self.context.account.postbox.messageAtId(messageId) @@ -638,7 +653,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { })) } case let .index(index): - switch self.messagesLocation { + switch self.messagesLocation.effectiveLocation(context: self.context) { case let .messages(chatLocation, tagMask, _): var inputIndex: Signal? let looping = self.looping @@ -770,6 +785,8 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { self.loadingItem = false self.currentItem = (message, []) self.updateState() + case .savedMusic: + fatalError() case let .custom(messages, _, _, loadMore): let inputIndex: Signal let looping = self.looping @@ -823,6 +840,16 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } if case .all = looping { + if let first = messages.first { + if let (message, aroundMessages, _) = navigatedMessageFromMessages(messages, anchorIndex: first.index, position: .exact) { + switch navigation { + case .random: + return .single(((message, []), messages.count, false)) + default: + return .single(((message, aroundMessages), messages.count, false)) + } + } + } return .single((nil, messages.count, false)) } else { if hasMore { @@ -880,7 +907,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist { } } - func onItemPlaybackStarted(_ item: SharedMediaPlaylistItem) { + public func onItemPlaybackStarted(_ item: SharedMediaPlaylistItem) { if let item = item as? MessageMediaPlaylistItem { switch self.messagesLocation { case .recentActions: diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift index 24b3b1e1ac..dccc9e198b 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent/Sources/PeerInfoCoverComponent.swift @@ -278,8 +278,38 @@ public final class PeerInfoCoverComponent: Component { } } - public func animateTransition() { + public func animateSwipeTransition() { if let gradientSnapshotLayer = self.backgroundGradientLayer.snapshotContentTree() { + let backgroundSnapshotLayer = SimpleLayer() + backgroundSnapshotLayer.masksToBounds = true + backgroundSnapshotLayer.allowsGroupOpacity = true + backgroundSnapshotLayer.backgroundColor = self.backgroundView.backgroundColor?.cgColor + backgroundSnapshotLayer.frame = self.backgroundView.frame + self.layer.insertSublayer(backgroundSnapshotLayer, above: self.backgroundGradientLayer) + + gradientSnapshotLayer.frame = self.backgroundGradientLayer.convert(self.backgroundGradientLayer.bounds, to: self.backgroundView.layer) + backgroundSnapshotLayer.addSublayer(gradientSnapshotLayer) + + let mask = CAGradientLayer() + mask.startPoint = CGPoint(x: 0.0, y: 0.5) + mask.endPoint = CGPoint(x: 1.0, y: 0.5) + mask.frame = CGRect(origin: CGPoint(x: backgroundSnapshotLayer.bounds.width, y: 0.0), size: CGSize(width: backgroundSnapshotLayer.bounds.width * 2.0, height: backgroundSnapshotLayer.bounds.height)) + mask.colors = [ + UIColor.white.withAlphaComponent(0.0).cgColor, + UIColor.white.cgColor, + UIColor.white.cgColor, + ] + mask.locations = [0.0, 0.5, 1.0] + backgroundSnapshotLayer.mask = mask + + mask.animatePosition(from: CGPoint(x: -backgroundSnapshotLayer.bounds.width * 2.0, y: 0.0), to: .zero, duration: 0.35, timingFunction: CAMediaTimingFunctionName.linear.rawValue, additive: true, completion: { [weak backgroundSnapshotLayer] _ in + backgroundSnapshotLayer?.removeFromSuperlayer() + }) + } + } + + public func animateTransition(background: Bool = true, bounce: Bool = true) { + if background, let gradientSnapshotLayer = self.backgroundGradientLayer.snapshotContentTree() { let backgroundSnapshotLayer = SimpleLayer() backgroundSnapshotLayer.allowsGroupOpacity = true backgroundSnapshotLayer.backgroundColor = self.backgroundView.backgroundColor?.cgColor @@ -301,8 +331,10 @@ public final class PeerInfoCoverComponent: Component { } layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) } - let values: [NSNumber] = [1.0, 1.08, 1.0] - self.avatarBackgroundPatternContentsLayer.animateKeyframes(values: values, duration: 0.25, keyPath: "sublayerTransform.scale") + if bounce { + let values: [NSNumber] = [1.0, 1.14, 1.0] + self.avatarBackgroundPatternContentsLayer.animateKeyframes(values: values, duration: 0.4, keyPath: "sublayerTransform.scale") + } } private func loadPatternFromFile() { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift index 32e3928b92..99ae063a1a 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoPaneNode/Sources/PeerInfoPaneNode.swift @@ -10,7 +10,6 @@ public enum PeerInfoPaneKey: Int32 { case botPreview case members case stories - case storyArchive case gifts case media case savedMessagesChats @@ -23,6 +22,7 @@ public enum PeerInfoPaneKey: Int32 { case groupsInCommon case similarChannels case similarBots + case storyArchive public init(tab: TelegramProfileTab) { switch tab { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD index 6096e4a327..9e56ec5e89 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/BUILD @@ -164,6 +164,7 @@ swift_library( "//submodules/TelegramUI/Components/TabSelectorComponent", "//submodules/TelegramUI/Components/BottomButtonPanelComponent", "//submodules/TelegramUI/Components/MarqueeComponent", + "//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift index 3da3eb6fe2..41133017a6 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/Panes/PeerInfoListPaneNode.swift @@ -406,7 +406,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode { } else { controllerContext = strongSelf.context.sharedContext.makeTempAccountContext(account: account) } - let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: strongSelf.chatControllerInteraction.navigationController(), updateMusicSaved: nil, reorderSavedMusic: nil) + let controller = strongSelf.context.sharedContext.makeOverlayAudioPlayerController(context: controllerContext, chatLocation: chatLocation, type: type, initialMessageId: id.messageId, initialOrder: order, playlistLocation: nil, parentNavigationController: strongSelf.chatControllerInteraction.navigationController()) strongSelf.view.window?.endEditing(true) strongSelf.chatControllerInteraction.presentController(controller, nil) } else if index.1 { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift index 52f8be80f5..34fa05787e 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoHeaderNode.swift @@ -557,6 +557,36 @@ final class PeerInfoHeaderNode: ASDisplayNode { } } + let actionButtonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderActionButtons(peer: peer, isSecretChat: isSecretChat, isContact: isContact) + let buttonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info) + + let backgroundCoverSubject: PeerInfoCoverComponent.Subject? + var backgroundCoverAnimateIn = false + var backgroundDefaultHeight: CGFloat = 254.0 + var hasBackground = false + if let status = peer?.emojiStatus, case .starGift = status.content { + backgroundCoverSubject = .status(status) + if !self.didSetupBackgroundCover { + if !self.isSettings { + backgroundCoverAnimateIn = true + } + self.didSetupBackgroundCover = true + } + if !buttonKeys.isEmpty { + backgroundDefaultHeight = 327.0 + if metrics.isTablet { + backgroundDefaultHeight += 60.0 + } + } + hasBackground = true + } else if let peer { + backgroundCoverSubject = .peer(EnginePeer(peer)) + if peer.profileColor != nil { + hasBackground = true + } + } else { + backgroundCoverSubject = nil + } var currentSavedMusic: TelegramMediaFile? if !self.isSettings, let screenData { @@ -566,8 +596,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { currentSavedMusic = cachedUserData.savedMusic } } - let musicHeight: CGFloat = 24.0 - let bottomInset: CGFloat = currentSavedMusic != nil ? 24.0 : 0.0 + let musicHeight: CGFloat = hasBackground ? 24.0 : 16.0 + let bottomInset: CGFloat = currentSavedMusic != nil ? musicHeight : 0.0 let isLandscape = containerInset > 16.0 @@ -1187,10 +1217,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } let expandedAvatarListSize = CGSize(width: width, height: expandedAvatarListHeight) - - let actionButtonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderActionButtons(peer: peer, isSecretChat: isSecretChat, isContact: isContact) - let buttonKeys: [PeerInfoHeaderButtonKey] = (self.isSettings || self.isMyProfile) ? [] : peerInfoHeaderButtons(peer: peer, cachedData: cachedData, isOpenedFromChat: self.isOpenedFromChat, isExpanded: true, videoCallsEnabled: width > 320.0 && self.videoCallsEnabled, isSecretChat: isSecretChat, isContact: isContact, threadInfo: threadData?.info) - + var isPremium = false var isVerified = false var isFake = false @@ -1453,7 +1480,15 @@ final class PeerInfoHeaderNode: ASDisplayNode { if let previousPanelStatusData = previousPanelStatusData, let currentPanelStatusData = panelStatusData.0, let previousPanelStatusDataKey = previousPanelStatusData.key, let currentPanelStatusDataKey = currentPanelStatusData.key, previousPanelStatusDataKey != currentPanelStatusDataKey { if let snapshotView = self.panelSubtitleNode.view.snapshotContentTree() { - let direction: CGFloat = previousPanelStatusDataKey.rawValue > currentPanelStatusDataKey.rawValue ? 1.0 : -1.0 + let previousIndex = screenData?.availablePanes.firstIndex(of: previousPanelStatusDataKey) + let currentIndex = screenData?.availablePanes.firstIndex(of: currentPanelStatusDataKey) + + let direction: CGFloat + if let previousIndex, let currentIndex { + direction = previousIndex > currentIndex ? 1.0 : -1.0 + } else { + direction = previousPanelStatusDataKey.rawValue > currentPanelStatusDataKey.rawValue ? 1.0 : -1.0 + } self.panelSubtitleNode.view.superview?.addSubview(snapshotView) snapshotView.frame = self.panelSubtitleNode.frame @@ -2451,35 +2486,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else { transition.updateFrame(view: self.backgroundBannerView, frame: bannerFrame) } - - let backgroundCoverSubject: PeerInfoCoverComponent.Subject? - var backgroundCoverAnimateIn = false - var backgroundDefaultHeight: CGFloat = 254.0 - var hasBackground = false - if let status = peer?.emojiStatus, case .starGift = status.content { - backgroundCoverSubject = .status(status) - if !self.didSetupBackgroundCover { - if !self.isSettings { - backgroundCoverAnimateIn = true - } - self.didSetupBackgroundCover = true - } - if !buttonKeys.isEmpty { - backgroundDefaultHeight = 327.0 - if metrics.isTablet { - backgroundDefaultHeight += 60.0 - } - } - hasBackground = true - } else if let peer { - backgroundCoverSubject = .peer(EnginePeer(peer)) - if peer.profileColor != nil { - hasBackground = true - } - } else { - backgroundCoverSubject = nil - } - + let backgroundCoverSize = self.backgroundCover.update( transition: ComponentTransition(transition), component: AnyComponent(PeerInfoCoverComponent( @@ -2634,6 +2641,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { return musicBackground }() musicTransition.updateFrame(view: musicBackground, frame: CGRect(origin: CGPoint(x: 0.0, y: backgroundHeight - musicHeight - buttonRightOrigin.y), size: CGSize(width: backgroundFrame.width, height: musicHeight))) + + if let _ = self.navigationTransition { + transition.updateAlpha(layer: musicBackground.layer, alpha: 1.0 - transitionFraction) + } else { + musicTransition.updateAlpha(layer: musicBackground.layer, alpha: 1.0) + } } else if let musicBackground = self.musicBackground { self.musicBackground = nil if transition.isAnimated { @@ -2685,10 +2698,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { environment: {}, containerSize: CGSize(width: backgroundFrame.width, height: musicHeight) ) - let musicFrame = CGRect(origin: CGPoint(x: 0.0, y: backgroundHeight - musicHeight), size: musicSize) + let musicFrame = CGRect(origin: CGPoint(x: 0.0, y: (apparentBackgroundHeight - backgroundHeight) + backgroundHeight - musicHeight - (hasBackground ? 0.0 : 4.0)), size: musicSize) if let musicView = music.view { if musicView.superview == nil { - self.view.addSubview(musicView) + self.regularContentNode.view.addSubview(musicView) if transition.isAnimated { musicView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) } @@ -2698,7 +2711,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { } else { musicTransition.updateFrame(view: musicView, frame: musicFrame) } - musicTransition.updateAlpha(layer: musicView.layer, alpha: backgroundBannerAlpha) + + if let _ = self.navigationTransition { + transition.updateAlpha(layer: musicView.layer, alpha: 1.0 - transitionFraction) + } else { + musicTransition.updateAlpha(layer: musicView.layer, alpha: backgroundBannerAlpha) + } } } else { if let musicBackground = self.musicBackground { @@ -2825,6 +2843,10 @@ final class PeerInfoHeaderNode: ASDisplayNode { return giftsCoverView } + if let musicView = self.music?.view, let result = musicView.hitTest(self.view.convert(point, to: musicView), with: event) { + return result + } + if result == self.view || result == self.regularContentNode.view || result == self.editingContentNode.view { return nil } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift index 15eb470c1e..4a7afc830c 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift @@ -1639,7 +1639,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat environment: {}, containerSize: tabsContainerSize ) - let tabContainerFrameOriginX = floorToScreenPixels((size.width - tabsContainerEffectiveSize.width) / 2.0) + let tabContainerFrameOriginX = items.count == 1 ? sideInset : floorToScreenPixels((size.width - tabsContainerEffectiveSize.width) / 2.0) let tabContainerFrame = CGRect(origin: CGPoint(x: tabContainerFrameOriginX, y: 10.0 - tabsOffset), size: tabsContainerSize) if let tabsContainerView = self.tabsContainer.view { if tabsContainerView.superview == nil { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 68ecabb5b0..21c72e8719 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -112,6 +112,7 @@ import OldChannelsController import UrlHandling import VerifyAlertController import GiftViewScreen +import PeerMessagesMediaPlaylist public enum PeerInfoAvatarEditingMode { case generic @@ -6008,66 +6009,57 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro } } + var previousSavedMusicTimestamp: Double? private func displaySavedMusic() { guard let savedMusicContext = self.data?.savedMusicContext else { return } - let peerId = self.peerId - let peer = self.data?.peer - let initialMessageId: MessageId - if let initialFileId = self.data?.savedMusicState?.files.first?.fileId { - initialMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: Int32(clamping: initialFileId.id % Int64(Int32.max))) - } else { - initialMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: 0) - } - let musicController = self.context.sharedContext.makeOverlayAudioPlayerController( - context: self.context, - chatLocation: .peer(id: peerId), - type: .music, - initialMessageId: initialMessageId, - initialOrder: .regular, - playlistLocation: PeerMessagesPlaylistLocation.custom( - messages: savedMusicContext.state - |> map { state in - var messages: [Message] = [] - var peers = SimpleDictionary() - peers[peerId] = peer - for file in state.files { - let stableId = UInt32(clamping: file.fileId.id % Int64(Int32.max)) - messages.append(Message(stableId: stableId, stableVersion: 0, id: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: Int32(stableId)), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], customTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [file], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])) - - } - return (messages, Int32(messages.count), true) - }, - canReorder: peerId == self.context.account.peerId, - at: initialMessageId, - loadMore: { [weak savedMusicContext] in - guard let savedMusicContext else { - return - } - savedMusicContext.loadMore() - } - ), - parentNavigationController: self.controller?.navigationController as? NavigationController, - updateMusicSaved: { [weak savedMusicContext] file, isSaved in - guard let savedMusicContext else { - return - } - if isSaved { - let _ = savedMusicContext.addMusic(file: file).start() - } else { - let _ = savedMusicContext.removeMusic(file: file).start() - } - }, - reorderSavedMusic: { [weak savedMusicContext] file, afterFile in - guard let savedMusicContext else { - return - } - let _ = savedMusicContext.addMusic(file: file, afterFile: afterFile, apply: true).start() + let currentTimestamp = CACurrentMediaTime() + if let previousTimestamp = self.previousSavedMusicTimestamp, currentTimestamp < previousTimestamp + 1.0 { + return + } + self.previousSavedMusicTimestamp = currentTimestamp + + let _ = (self.context.sharedContext.mediaManager.globalMediaPlayerState + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] accountStateAndType in + guard let self else { + return } - ) - self.controller?.present(musicController, in: .window(.root)) + let peerId = self.peerId + var initialId: Int32 + if let initialFileId = self.data?.savedMusicState?.files.first?.fileId { + initialId = Int32(clamping: initialFileId.id % Int64(Int32.max)) + } else { + initialId = 0 + } + + let canReorder = peerId == self.context.account.peerId + var playlistLocation: PeerMessagesPlaylistLocation = .savedMusic(context: savedMusicContext, at: initialId, canReorder: canReorder) + + if let (account, stateOrLoading, _) = accountStateAndType, self.context.account.peerId == account.peerId, case let .state(state) = stateOrLoading, let location = state.playlistLocation as? PeerMessagesPlaylistLocation, case let .savedMusic(savedMusicContext, _, _) = location, savedMusicContext.peerId == peerId { + if let itemId = state.item.id as? PeerMessagesMediaPlaylistItemId { + initialId = itemId.messageId.id + } + playlistLocation = .savedMusic(context: savedMusicContext, at: initialId, canReorder: canReorder) + } else { + self.context.sharedContext.mediaManager.setPlaylist((self.context, PeerMessagesMediaPlaylist(context: self.context, location: playlistLocation, chatLocationContextHolder: nil)), type: .music, control: .playback(.play)) + } + + Queue.mainQueue().after(0.1) { + let musicController = self.context.sharedContext.makeOverlayAudioPlayerController( + context: self.context, + chatLocation: .peer(id: peerId), + type: .music, + initialMessageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: initialId), + initialOrder: .regular, + playlistLocation: playlistLocation, + parentNavigationController: self.controller?.navigationController as? NavigationController + ) + self.controller?.present(musicController, in: .window(.root)) + } + }) } private func performButtonAction(key: PeerInfoHeaderButtonKey, gesture: ContextGesture?) { @@ -13560,27 +13552,39 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc if let updatedPresentationData = updatedPresentationData { presentationDataSignal = updatedPresentationData.signal } else if self.peerId != self.context.account.peerId { - let themeEmoticon: Signal = self.cachedDataPromise.get() - |> map { cachedData -> String? in + let chatTheme: Signal = self.cachedDataPromise.get() + |> map { cachedData -> ChatTheme? in if let cachedData = cachedData as? CachedUserData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedData as? CachedGroupData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else if let cachedData = cachedData as? CachedChannelData { - return cachedData.themeEmoticon + return cachedData.chatTheme } else { return nil } } |> distinctUntilChanged - presentationDataSignal = combineLatest(queue: Queue.mainQueue(), context.sharedContext.presentationData, context.engine.themes.getChatThemes(accountManager: context.sharedContext.accountManager, onlyCached: false), themeEmoticon) - |> map { presentationData, chatThemes, themeEmoticon -> PresentationData in + presentationDataSignal = combineLatest( + queue: Queue.mainQueue(), + context.sharedContext.presentationData, + context.engine.themes.getChatThemes(accountManager: context.sharedContext.accountManager, onlyCached: false), + chatTheme + ) + |> map { presentationData, chatThemes, chatTheme -> PresentationData in var presentationData = presentationData - if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon == themeEmoticon }) { - if let theme = makePresentationTheme(cloudTheme: theme, dark: presentationData.theme.overallDarkAppearance) { - presentationData = presentationData.withUpdated(theme: theme) - presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper) + if let chatTheme { + switch chatTheme { + case let .emoticon(emoticon): + if let theme = chatThemes.first(where: { $0.emoticon == emoticon }) { + if let theme = makePresentationTheme(cloudTheme: theme, dark: presentationData.theme.overallDarkAppearance) { + presentationData = presentationData.withUpdated(theme: theme) + presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper) + } + } + case .gift: + break } } return presentationData diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftContextPreviewController.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftContextPreviewController.swift index f65937faf1..3ec904d2a4 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftContextPreviewController.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftContextPreviewController.swift @@ -69,7 +69,7 @@ private final class GiftContextPreviewComponent: Component { case let .generic(gift): subject = .generic(gift.file) case let .unique(gift): - subject = .unique(gift) + subject = .unique(nil, gift) } let animationSize = self.animation.update( @@ -82,7 +82,7 @@ private final class GiftContextPreviewComponent: Component { animationScale: nil, displayAnimationStars: false, externalState: self.giftCompositionExternalState, - requestUpdate: { [weak state] in + requestUpdate: { [weak state] _ in state?.updated() } )), diff --git a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift index 97e399a610..6a5acba10c 100644 --- a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift @@ -676,7 +676,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { case let .gift(peerId): purpose = .starsGift(peerId: peerId, count: product.count, currency: currency, amount: amount) default: - purpose = .stars(count: product.count, currency: currency, amount: amount) + purpose = .stars(count: product.count, currency: currency, amount: amount, peerId: self.purpose.commercialPeerId) } let _ = (self.context.engine.payments.canPurchasePremium(purpose: purpose) @@ -1264,6 +1264,21 @@ private extension StarsPurchasePurpose { } } + var commercialPeerId: EnginePeer.Id? { + switch self { + case let .transfer(peerId, _): + return peerId + case let .reactions(peerId, _): + return peerId + case let .subscription(peerId, _, _): + return peerId + case let .sendMessage(peerId, _): + return peerId + default: + return nil + } + } + var requiredStars: Int64? { switch self { case let .topUp(requiredStars, _): diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift index 846115bada..9d36fd41a0 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift @@ -390,7 +390,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { giftAnimationSubject = .generic(gift.file) giftAvailability = gift.availability case let .unique(gift): - giftAnimationSubject = .unique(gift) + giftAnimationSubject = .unique(nil, gift) } isGiftUpgrade = transaction.flags.contains(.isStarGiftUpgrade) } else if let giveawayMessageIdValue = transaction.giveawayMessageId { diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift index 0c5af23a24..6f928dde21 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionsScreen.swift @@ -1286,11 +1286,24 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer { } if subscription.untilDate > Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) { var updated = false - if let channel = subscription.peer._asPeer() as? TelegramChannel, channel.participationStatus == .left && !subscription.flags.contains(.isCancelled) { + + var hasLeft = false + var isKicked = false + if let channel = subscription.peer._asPeer() as? TelegramChannel { + switch channel.participationStatus { + case .left: + hasLeft = true + case .kicked: + isKicked = true + default: + break + } + } + + if hasLeft && !subscription.flags.contains(.isCancelled) { let _ = self.context.engine.payments.fulfillStarsSubscription(peerId: context.account.peerId, subscriptionId: subscription.id).startStandalone() updated = true - } - if let _ = subscription.inviteHash, !subscription.flags.contains(.isCancelledByBot) { + } else if let _ = subscription.inviteHash, hasLeft && !isKicked && !subscription.flags.contains(.isCancelledByBot) { let _ = self.context.engine.payments.fulfillStarsSubscription(peerId: context.account.peerId, subscriptionId: subscription.id).startStandalone() updated = true } diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/Contents.json new file mode 100644 index 0000000000..562f9b14b9 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "TimeLocked.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/TimeLocked.pdf b/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/TimeLocked.pdf new file mode 100644 index 0000000000..5a20922cb0 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Peer Info/DateLockedIcon.imageset/TimeLocked.pdf differ diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift index f5bc2b2e52..a0ea346e17 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerLoadDisplayNode.swift @@ -186,7 +186,7 @@ extension ChatControllerImpl { self.contentDataUpdated(synchronous: true, forceAnimationTransition: forceAnimationTransition, previousState: contentData.state) - self.chatThemeEmoticonPromise.set(contentData.chatThemeEmoticonPromise.get()) + self.chatThemePromise.set(contentData.chatThemePromise.get()) self.chatWallpaperPromise.set(contentData.chatWallpaperPromise.get()) if let historyNode { @@ -848,12 +848,12 @@ extension ChatControllerImpl { } if let peerId = self.chatLocation.peerId { - self.chatThemeEmoticonPromise.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ThemeEmoticon(id: peerId))) + self.chatThemePromise.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ChatTheme(id: peerId))) let chatWallpaper = self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Wallpaper(id: peerId)) |> take(1) self.chatWallpaperPromise.set(chatWallpaper) } else { - self.chatThemeEmoticonPromise.set(.single(nil)) + self.chatThemePromise.set(.single(nil)) self.chatWallpaperPromise.set(.single(nil)) } diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerThemeManagement.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerThemeManagement.swift index dadcc49e02..4d9aa139cf 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerThemeManagement.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerThemeManagement.swift @@ -161,8 +161,8 @@ extension ChatControllerImpl { return animatedEmojiStickers } - let _ = (combineLatest(queue: Queue.mainQueue(), self.chatThemeEmoticonPromise.get(), animatedEmojiStickers) - |> take(1)).startStandalone(next: { [weak self] themeEmoticon, animatedEmojiStickers in + let _ = (combineLatest(queue: Queue.mainQueue(), self.chatThemePromise.get(), animatedEmojiStickers) + |> take(1)).startStandalone(next: { [weak self] chatTheme, animatedEmojiStickers in guard let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer else { return } @@ -176,13 +176,13 @@ extension ChatControllerImpl { context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, - initiallySelectedEmoticon: themeEmoticon, + initiallySelectedTheme: chatTheme, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer.flatMap(EnginePeer.init)?.compactDisplayTitle ?? "", canResetWallpaper: canResetWallpaper, - previewTheme: { [weak self] emoticon, dark in + previewTheme: { [weak self] chatTheme, dark in if let strongSelf = self { strongSelf.presentCrossfadeSnapshot() - strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark))) + strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), dark))) } }, changeWallpaper: { [weak self] in @@ -258,17 +258,17 @@ extension ChatControllerImpl { } let _ = strongSelf.context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil, forBoth: false).startStandalone() }, - completion: { [weak self] emoticon in + completion: { [weak self] chatTheme in guard let strongSelf = self, let peerId else { return } - if canResetWallpaper && emoticon != nil { + if canResetWallpaper && chatTheme != nil { let _ = context.engine.themes.setChatWallpaper(peerId: peerId, wallpaper: nil, forBoth: false).startStandalone() } - strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon ?? "", nil))) - let _ = context.engine.themes.setChatTheme(peerId: peerId, emoticon: emoticon).startStandalone(completed: { [weak self] in + strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((chatTheme ?? .emoticon(""), nil))) + let _ = context.engine.themes.setChatTheme(peerId: peerId, chatTheme: chatTheme ?? .emoticon("")).startStandalone(completed: { [weak self] in if let strongSelf = self { - strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((nil, nil))) + strongSelf.chatThemeAndDarkAppearancePreviewPromise.set(.single((nil, nil))) } }) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index afbf2d5762..a6353274f4 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -287,7 +287,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return self.presentationInterfaceState.interfaceState.selectionState?.selectedIds } - let chatThemeEmoticonPromise = Promise() + let chatThemePromise = Promise() let chatWallpaperPromise = Promise() var chatTitleView: ChatTitleView? @@ -412,7 +412,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var canReadHistoryDisposable: Disposable? var computedCanReadHistoryPromise = ValuePromise(false, ignoreRepeated: true) - var themeEmoticonAndDarkAppearancePreviewPromise = Promise<(String?, Bool?)>((nil, nil)) + var chatThemeAndDarkAppearancePreviewPromise = Promise<(ChatTheme?, Bool?)>((nil, nil)) var didSetPresentationData = false var presentationData: PresentationData var presentationDataPromise = Promise() @@ -5705,7 +5705,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) } - let themeEmoticon: Signal = self.chatThemeEmoticonPromise.get() + let chatTheme: Signal = self.chatThemePromise.get() |> distinctUntilChanged let uploadingChatWallpaper: Signal @@ -5741,18 +5741,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } let accountManager = context.sharedContext.accountManager - let currentThemeEmoticon = Atomic<(String?, Bool)?>(value: nil) + let currentChatTheme = Atomic<(ChatTheme?, Bool)?>(value: nil) self.presentationDataDisposable = combineLatest( queue: Queue.mainQueue(), context.sharedContext.presentationData, themeSettings, context.engine.themes.getChatThemes(accountManager: accountManager, onlyCached: true), - themeEmoticon, - self.themeEmoticonAndDarkAppearancePreviewPromise.get(), + chatTheme, + self.chatThemeAndDarkAppearancePreviewPromise.get(), chatWallpaper - ).startStrict(next: { [weak self] presentationData, themeSettings, chatThemes, themeEmoticon, themeEmoticonAndDarkAppearance, chatWallpaper in + ).startStrict(next: { [weak self] presentationData, themeSettings, chatThemes, chatTheme, chatThemeAndDarkAppearance, chatWallpaper in if let strongSelf = self { - let (themeEmoticonPreview, darkAppearancePreview) = themeEmoticonAndDarkAppearance + let (chatThemePreview, darkAppearancePreview) = chatThemeAndDarkAppearance var chatWallpaper = chatWallpaper @@ -5760,19 +5760,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let previousStrings = strongSelf.presentationData.strings let previousChatWallpaper = strongSelf.presentationData.chatWallpaper - var themeEmoticon = themeEmoticon - if let themeEmoticonPreview = themeEmoticonPreview { - if !themeEmoticonPreview.isEmpty { - if themeEmoticon?.strippedEmoji != themeEmoticonPreview.strippedEmoji { + var chatTheme = chatTheme + if let chatThemePreview { + if !chatThemePreview.isEmpty { + if chatTheme?.id != chatThemePreview.id { chatWallpaper = nil - themeEmoticon = themeEmoticonPreview + chatTheme = chatThemePreview } } else { - themeEmoticon = nil + chatTheme = nil } } if strongSelf.chatLocation.peerId == strongSelf.context.account.peerId { - themeEmoticon = nil + chatTheme = nil } var presentationData = presentationData @@ -5792,17 +5792,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G chatWallpaper = themeWallpaper } } - if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == themeEmoticon.strippedEmoji }) { - if let darkAppearancePreview = darkAppearancePreview { - useDarkAppearance = darkAppearancePreview - } - if let theme = makePresentationTheme(cloudTheme: theme, dark: useDarkAppearance) { - theme.forceSync = true - presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper) - - Queue.mainQueue().after(1.0, { - theme.forceSync = false - }) + if let chatTheme { + switch chatTheme { + case let .emoticon(emoticon): + if let theme = chatThemes.first(where: { $0.emoticon?.strippedEmoji == emoticon.strippedEmoji }) { + if let darkAppearancePreview = darkAppearancePreview { + useDarkAppearance = darkAppearancePreview + } + if let theme = makePresentationTheme(cloudTheme: theme, dark: useDarkAppearance) { + theme.forceSync = true + presentationData = presentationData.withUpdated(theme: theme).withUpdated(chatWallpaper: theme.chat.defaultWallpaper) + + Queue.mainQueue().after(1.0, { + theme.forceSync = false + }) + } + } + case let .gift(gift, wallpaper): + let _ = gift + let _ = wallpaper + //TODO:release } } else if let darkAppearancePreview = darkAppearancePreview { useDarkAppearance = darkAppearancePreview @@ -5897,7 +5906,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.presentationData = presentationData strongSelf.didSetPresentationData = true - let previousThemeEmoticon = currentThemeEmoticon.swap((themeEmoticon, useDarkAppearance)) + let previousChatTheme = currentChatTheme.swap((chatTheme, useDarkAppearance)) if isFirstTime || previousTheme != presentationData.theme || previousStrings !== presentationData.strings || presentationData.chatWallpaper != previousChatWallpaper { strongSelf.themeAndStringsUpdated() @@ -5905,7 +5914,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G controllerInteraction.updatedPresentationData = strongSelf.updatedPresentationData strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData)) - if !isFirstTime && (previousThemeEmoticon?.0 != themeEmoticon || previousThemeEmoticon?.1 != useDarkAppearance) { + if !isFirstTime && (previousChatTheme?.0 != chatTheme || previousChatTheme?.1 != useDarkAppearance) { strongSelf.presentCrossfadeSnapshot() } } diff --git a/submodules/TelegramUI/Sources/ChatControllerContentData.swift b/submodules/TelegramUI/Sources/ChatControllerContentData.swift index 886e38e849..0fa02f6527 100644 --- a/submodules/TelegramUI/Sources/ChatControllerContentData.swift +++ b/submodules/TelegramUI/Sources/ChatControllerContentData.swift @@ -218,7 +218,7 @@ extension ChatControllerImpl { var historyNavigationStack = ChatHistoryNavigationStack() - let chatThemeEmoticonPromise = Promise() + let chatThemePromise = Promise() let chatWallpaperPromise = Promise() private(set) var inviteRequestsContext: PeerInvitationImportersContext? @@ -2240,19 +2240,19 @@ extension ChatControllerImpl { let (cachedData, messages) = cachedDataAndMessages if cachedData != nil { - var themeEmoticon: String? = nil + var chatTheme: ChatTheme? = nil var chatWallpaper: TelegramWallpaper? if let cachedData = cachedData as? CachedUserData { - themeEmoticon = cachedData.themeEmoticon + chatTheme = cachedData.chatTheme chatWallpaper = cachedData.wallpaper } else if let cachedData = cachedData as? CachedGroupData { - themeEmoticon = cachedData.themeEmoticon + chatTheme = cachedData.chatTheme } else if let cachedData = cachedData as? CachedChannelData { - themeEmoticon = cachedData.themeEmoticon + chatTheme = cachedData.chatTheme chatWallpaper = cachedData.wallpaper } - strongSelf.chatThemeEmoticonPromise.set(.single(themeEmoticon)) + strongSelf.chatThemePromise.set(.single(chatTheme)) strongSelf.chatWallpaperPromise.set(.single(chatWallpaper)) } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 2ae1613ee7..bcd4b9a5a6 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -553,7 +553,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { return (messages, Int32(messages.count), false) } - source = .custom(messages: messages, messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: nil, updateAll: true, canReorder: false, loadMore: nil) + source = .custom(messages: messages, messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: nil, isSavedMusic: false, canReorder: false, loadMore: nil) case let .reply(reply): let messages = combineLatest(context.account.postbox.messagesAtIds(messageIds), context.account.postbox.loadedPeerWithId(context.account.peerId)) |> map { messages, accountPeer -> ([Message], Int32, Bool) in @@ -567,7 +567,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { return (messages, Int32(messages.count), false) } - source = .custom(messages: messages, messageId: messageIds.first ?? MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: reply.quote.flatMap { quote in ChatHistoryListSource.Quote(text: quote.text, offset: quote.offset) }, updateAll: true, canReorder: false, loadMore: nil) + source = .custom(messages: messages, messageId: messageIds.first ?? MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: reply.quote.flatMap { quote in ChatHistoryListSource.Quote(text: quote.text, offset: quote.offset) }, isSavedMusic: false, canReorder: false, loadMore: nil) case let .link(link): let messages = link.options |> mapToSignal { options -> Signal<(ChatControllerSubject.LinkOptions, Peer, Message?, [StoryId: CodableEntry]), NoError> in @@ -668,13 +668,13 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { return ([message], 1, false) } - source = .custom(messages: messages, messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: nil, updateAll: true, canReorder: false, loadMore: nil) + source = .custom(messages: messages, messageId: MessageId(peerId: PeerId(0), namespace: 0, id: 0), quote: nil, isSavedMusic: false, canReorder: false, loadMore: nil) } } else if case .customChatContents = chatLocation { if case let .customChatContents(customChatContents) = subject { source = .customView(historyView: customChatContents.historyView) } else { - source = .custom(messages: .single(([], 0, false)), messageId: nil, quote: nil, updateAll: true, canReorder: false, loadMore: nil) + source = .custom(messages: .single(([], 0, false)), messageId: nil, quote: nil, isSavedMusic: false, canReorder: false, loadMore: nil) } } else { source = .default diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 353975c903..27843831b2 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -216,7 +216,7 @@ extension ListMessageItemInteraction { } } -private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, canReorder: Bool, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] { +private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, isSavedMusic: Bool, canReorder: Bool, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] { var disableFloatingDateHeaders = false if case .customChatContents = chatLocation { disableFloatingDateHeaders = true @@ -239,7 +239,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca case .allButLast: displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId } - item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch, canReorder: canReorder) + item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch, isSavedMusic: isSavedMusic, canReorder: canReorder) } return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .MessageGroupEntry(_, messages, presentationData): @@ -275,7 +275,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca } } -private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, canReorder: Bool, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] { +private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, isSavedMusic: Bool, canReorder: Bool, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] { var disableFloatingDateHeaders = false if case .customChatContents = chatLocation { disableFloatingDateHeaders = true @@ -298,7 +298,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca case .allButLast: displayHeader = listMessageDateHeaderId(timestamp: message.timestamp) != lastHeaderId } - item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch, canReorder: canReorder) + item = ListMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, interaction: ListMessageItemInteraction(controllerInteraction: controllerInteraction), message: message, translateToLanguage: associatedData.translateToLanguage, selection: selection, displayHeader: displayHeader, hintIsLink: hintLinks, isGlobalSearchResult: isGlobalSearch, isSavedMusic: isSavedMusic, canReorder: canReorder) } return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint) case let .MessageGroupEntry(_, messages, presentationData): @@ -334,8 +334,8 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca } } -private func mappedChatHistoryViewListTransition(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, canReorder: Bool, animateFromPreviousFilter: Bool, transition: ChatHistoryViewTransition) -> ChatHistoryListViewTransition { - return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, canReorder: canReorder, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, canReorder: canReorder, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, scrolledToSomeIndex: transition.scrolledToSomeIndex, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, animateIn: transition.animateIn, reason: transition.reason, flashIndicators: transition.flashIndicators, animateFromPreviousFilter: animateFromPreviousFilter) +private func mappedChatHistoryViewListTransition(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, lastHeaderId: Int64, isSavedMusic: Bool, canReorder: Bool, animateFromPreviousFilter: Bool, transition: ChatHistoryViewTransition) -> ChatHistoryListViewTransition { + return ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: transition.deleteItems, insertItems: mappedInsertEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, isSavedMusic: isSavedMusic, canReorder: canReorder, entries: transition.insertEntries), updateItems: mappedUpdateEntries(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, isSavedMusic: isSavedMusic, canReorder: canReorder, entries: transition.updateEntries), options: transition.options, scrollToItem: transition.scrollToItem, stationaryItemRange: transition.stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, scrolledToSomeIndex: transition.scrolledToSomeIndex, peerType: associatedData.automaticDownloadPeerType, networkType: associatedData.automaticDownloadNetworkType, animateIn: transition.animateIn, reason: transition.reason, flashIndicators: transition.flashIndicators, animateFromPreviousFilter: animateFromPreviousFilter) } final class ChatHistoryTransactionOpaqueState { @@ -1397,10 +1397,10 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto var historyViewUpdate: Signal<(ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?, ClosedRange?, Set), NoError> var isFirstTime = true - var updateAllOnEachVersion = false + var isSavedMusic = false var canReorder = false - if case let .custom(messages, at, quote, updateAll, canReorderValue, _) = self.source { - updateAllOnEachVersion = updateAll + if case let .custom(messages, at, quote, isSavedMusicValue, canReorderValue, _) = self.source { + isSavedMusic = isSavedMusicValue canReorder = canReorderValue historyViewUpdate = messages |> map { messages, _, hasMore in @@ -1917,8 +1917,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto let disableAnimations = true let forceSynchronous = true - let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: false, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: nil, scrollAnimationCurve: nil, initialData: initialData?.initialData, keyboardButtonsMessage: nil, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: false, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: false) - var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: previousViewValue.associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: 0, canReorder: canReorder, animateFromPreviousFilter: resetScrolling, transition: rawTransition) + let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: false, chatLocation: chatLocation, source: source, controllerInteraction: controllerInteraction, scrollPosition: nil, scrollAnimationCurve: nil, initialData: initialData?.initialData, keyboardButtonsMessage: nil, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: false, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: false) + var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: previousViewValue.associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: 0, isSavedMusic: isSavedMusic, canReorder: canReorder, animateFromPreviousFilter: resetScrolling, transition: rawTransition) if disableAnimations { mappedTransition.options.remove(.AnimateInsertion) @@ -2308,8 +2308,8 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto keyboardButtonsMessage = nil } - let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: keyboardButtonsMessage, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion || forceUpdateAll) - var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, canReorder: canReorder, animateFromPreviousFilter: resetScrolling, transition: rawTransition) + let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, source: source, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: keyboardButtonsMessage, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: !isSavedMusic || forceUpdateAll) + var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, isSavedMusic: isSavedMusic, canReorder: canReorder, animateFromPreviousFilter: resetScrolling, transition: rawTransition) if disableAnimations { mappedTransition.options.remove(.AnimateInsertion) diff --git a/submodules/TelegramUI/Sources/ChatThemeScreen.swift b/submodules/TelegramUI/Sources/ChatThemeScreen.swift index cdf9b92f22..67c96af618 100644 --- a/submodules/TelegramUI/Sources/ChatThemeScreen.swift +++ b/submodules/TelegramUI/Sources/ChatThemeScreen.swift @@ -24,7 +24,7 @@ import AttachmentUI private struct ThemeSettingsThemeEntry: Comparable, Identifiable { let index: Int - let emoticon: String? + let chatTheme: ChatTheme? let emojiFile: TelegramMediaFile? let themeReference: PresentationThemeReference? let nightMode: Bool @@ -41,10 +41,9 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable { if lhs.index != rhs.index { return false } - if lhs.emoticon != rhs.emoticon { + if lhs.chatTheme != rhs.chatTheme { return false } - if lhs.themeReference?.index != rhs.themeReference?.index { return false } @@ -70,15 +69,15 @@ private struct ThemeSettingsThemeEntry: Comparable, Identifiable { return lhs.index < rhs.index } - func item(context: AccountContext, action: @escaping (String?) -> Void) -> ListViewItem { - return ThemeSettingsThemeIconItem(context: context, emoticon: self.emoticon, emojiFile: self.emojiFile, themeReference: self.themeReference, nightMode: self.nightMode, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action) + func item(context: AccountContext, action: @escaping (ChatTheme?) -> Void) -> ListViewItem { + return ThemeSettingsThemeIconItem(context: context, chatTheme: self.chatTheme, emojiFile: self.emojiFile, themeReference: self.themeReference, nightMode: self.nightMode, selected: self.selected, theme: self.theme, strings: self.strings, wallpaper: self.wallpaper, action: action) } } private class ThemeSettingsThemeIconItem: ListViewItem { let context: AccountContext - let emoticon: String? + let chatTheme: ChatTheme? let emojiFile: TelegramMediaFile? let themeReference: PresentationThemeReference? let nightMode: Bool @@ -86,11 +85,11 @@ private class ThemeSettingsThemeIconItem: ListViewItem { let theme: PresentationTheme let strings: PresentationStrings let wallpaper: TelegramWallpaper? - let action: (String?) -> Void + let action: (ChatTheme?) -> Void - public init(context: AccountContext, emoticon: String?, emojiFile: TelegramMediaFile?, themeReference: PresentationThemeReference?, nightMode: Bool, selected: Bool, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper?, action: @escaping (String?) -> Void) { + public init(context: AccountContext, chatTheme: ChatTheme?, emojiFile: TelegramMediaFile?, themeReference: PresentationThemeReference?, nightMode: Bool, selected: Bool, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper?, action: @escaping (ChatTheme?) -> Void) { self.context = context - self.emoticon = emoticon + self.chatTheme = chatTheme self.emojiFile = emojiFile self.themeReference = themeReference self.nightMode = nightMode @@ -137,7 +136,7 @@ private class ThemeSettingsThemeIconItem: ListViewItem { public var selectable = true public func selected(listView: ListView) { - self.action(self.emoticon) + self.action(self.chatTheme) } } @@ -149,7 +148,7 @@ private struct ThemeSettingsThemeItemNodeTransition { let entries: [ThemeSettingsThemeEntry] } -private func ensureThemeVisible(listNode: ListView, emoticon: String?, animated: Bool) -> Bool { +private func ensureThemeVisible(listNode: ListView, themeId: String?, animated: Bool) -> Bool { var resultNode: ThemeSettingsThemeItemIconNode? var previousNode: ThemeSettingsThemeItemIconNode? var nextNode: ThemeSettingsThemeItemIconNode? @@ -158,7 +157,7 @@ private func ensureThemeVisible(listNode: ListView, emoticon: String?, animated: return } if resultNode == nil { - if node.item?.emoticon == emoticon { + if node.item?.chatTheme?.id == themeId { resultNode = node } else { previousNode = node @@ -183,7 +182,7 @@ private func ensureThemeVisible(listNode: ListView, emoticon: String?, animated: } } -private func preparedTransition(context: AccountContext, action: @escaping (String?) -> Void, from fromEntries: [ThemeSettingsThemeEntry], to toEntries: [ThemeSettingsThemeEntry], crossfade: Bool) -> ThemeSettingsThemeItemNodeTransition { +private func preparedTransition(context: AccountContext, action: @escaping (ChatTheme?) -> Void, from fromEntries: [ThemeSettingsThemeEntry], to toEntries: [ThemeSettingsThemeEntry], crossfade: Bool) -> ThemeSettingsThemeItemNodeTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } @@ -377,7 +376,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { var updatedSelected = false var updatedNightMode = false - if currentItem?.emoticon != item.emoticon { + if currentItem?.chatTheme?.id != item.chatTheme?.id { updatedEmoticon = true } if currentItem?.themeReference != item.themeReference { @@ -399,8 +398,13 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { let text = NSAttributedString(string: item.strings.Conversation_Theme_NoTheme, font: Font.semibold(15.0), textColor: item.theme.actionSheet.controlAccentColor) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: text, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) - let emoticon = item.emoticon - let title = NSAttributedString(string: emoticon != nil ? "" : "❌", font: Font.regular(22.0), textColor: .black) + let emoticon: String + if let _ = item.chatTheme { + emoticon = "" + } else { + emoticon = "❌" + } + let title = NSAttributedString(string: emoticon, font: Font.regular(22.0), textColor: .black) let (_, emojiApply) = makeEmojiLayout(TextNodeLayoutArguments(attributedString: title, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) let itemLayout = ListViewItemNodeLayout(contentSize: CGSize(width: 120.0, height: 90.0), insets: UIEdgeInsets()) @@ -430,7 +434,7 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode { } strongSelf.textNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((90.0 - textLayout.size.width) / 2.0), y: 24.0), size: textLayout.size) - strongSelf.textNode.isHidden = item.emoticon != nil + strongSelf.textNode.isHidden = emoticon.isEmpty strongSelf.containerNode.transform = CATransform3DMakeRotation(CGFloat.pi / 2.0, 0.0, 0.0, 1.0) strongSelf.containerNode.frame = CGRect(origin: CGPoint(x: 15.0, y: -15.0), size: CGSize(width: 90.0, height: 120.0)) @@ -533,13 +537,13 @@ final class ChatThemeScreen: ViewController { private let context: AccountContext private let animatedEmojiStickers: [String: [StickerPackItem]] - private let initiallySelectedEmoticon: String? + private let initiallySelectedTheme: ChatTheme? private let peerName: String let canResetWallpaper: Bool - private let previewTheme: (String?, Bool?) -> Void + private let previewTheme: (ChatTheme?, Bool?) -> Void fileprivate let changeWallpaper: () -> Void fileprivate let resetWallpaper: () -> Void - private let completion: (String?) -> Void + private let completion: (ChatTheme?) -> Void private var presentationData: PresentationData private var presentationDataDisposable: Disposable? @@ -558,18 +562,18 @@ final class ChatThemeScreen: ViewController { context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal), animatedEmojiStickers: [String: [StickerPackItem]], - initiallySelectedEmoticon: String?, + initiallySelectedTheme: ChatTheme?, peerName: String, canResetWallpaper: Bool, - previewTheme: @escaping (String?, Bool?) -> Void, + previewTheme: @escaping (ChatTheme?, Bool?) -> Void, changeWallpaper: @escaping () -> Void, resetWallpaper: @escaping () -> Void, - completion: @escaping (String?) -> Void + completion: @escaping (ChatTheme?) -> Void ) { self.context = context self.presentationData = updatedPresentationData.initial self.animatedEmojiStickers = animatedEmojiStickers - self.initiallySelectedEmoticon = initiallySelectedEmoticon + self.initiallySelectedTheme = initiallySelectedTheme self.peerName = peerName self.canResetWallpaper = canResetWallpaper self.previewTheme = previewTheme @@ -605,25 +609,25 @@ final class ChatThemeScreen: ViewController { } override public func loadDisplayNode() { - self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, controller: self, animatedEmojiStickers: self.animatedEmojiStickers, initiallySelectedEmoticon: self.initiallySelectedEmoticon, peerName: self.peerName) + self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, controller: self, animatedEmojiStickers: self.animatedEmojiStickers, initiallySelectedTheme: self.initiallySelectedTheme, peerName: self.peerName) self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl - self.controllerNode.previewTheme = { [weak self] emoticon, dark in + self.controllerNode.previewTheme = { [weak self] chatTheme, dark in guard let strongSelf = self else { return } - strongSelf.previewTheme((emoticon ?? ""), dark) + strongSelf.previewTheme((chatTheme ?? .emoticon("")), dark) } self.controllerNode.present = { [weak self] c in self?.present(c, in: .current) } - self.controllerNode.completion = { [weak self] emoticon in + self.controllerNode.completion = { [weak self] chatTheme in guard let strongSelf = self else { return } strongSelf.dismiss(animated: true) - if strongSelf.initiallySelectedEmoticon == nil && emoticon == nil { + if strongSelf.initiallySelectedTheme == nil && chatTheme == nil { } else { - strongSelf.completion(emoticon) + strongSelf.completion(chatTheme) } } self.controllerNode.dismiss = { [weak self] in @@ -738,15 +742,17 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega private var enqueuedTransitions: [ThemeSettingsThemeItemNodeTransition] = [] private var initialized = false + private let uniqueGiftChatThemesContext: UniqueGiftChatThemesContext + private let peerName: String - private let initiallySelectedEmoticon: String? - private var selectedEmoticon: String? { + private let initiallySelectedTheme: ChatTheme? + private var selectedTheme: ChatTheme? { didSet { - self.selectedEmoticonPromise.set(self.selectedEmoticon) + self.selectedThemePromise.set(self.selectedTheme) } } - private var selectedEmoticonPromise: ValuePromise + private var selectedThemePromise: ValuePromise private var isDarkAppearancePromise: ValuePromise private var isDarkAppearance: Bool = false { @@ -760,20 +766,22 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega private let disposable = MetaDisposable() var present: ((ViewController) -> Void)? - var previewTheme: ((String?, Bool?) -> Void)? - var completion: ((String?) -> Void)? + var previewTheme: ((ChatTheme?, Bool?) -> Void)? + var completion: ((ChatTheme?) -> Void)? var dismiss: (() -> Void)? var cancel: (() -> Void)? - init(context: AccountContext, presentationData: PresentationData, controller: ChatThemeScreen, animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, peerName: String) { + init(context: AccountContext, presentationData: PresentationData, controller: ChatThemeScreen, animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedTheme: ChatTheme?, peerName: String) { self.context = context self.controller = controller - self.initiallySelectedEmoticon = initiallySelectedEmoticon + self.initiallySelectedTheme = initiallySelectedTheme self.peerName = peerName - self.selectedEmoticon = initiallySelectedEmoticon - self.selectedEmoticonPromise = ValuePromise(initiallySelectedEmoticon) + self.selectedTheme = initiallySelectedTheme + self.selectedThemePromise = ValuePromise(initiallySelectedTheme) self.presentationData = presentationData + self.uniqueGiftChatThemesContext = UniqueGiftChatThemesContext(account: context.account) + self.wrappingScrollNode = ASScrollNode() self.wrappingScrollNode.view.alwaysBounceVertical = true self.wrappingScrollNode.view.delaysContentTouches = false @@ -869,7 +877,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega if let strongSelf = self { strongSelf.doneButton.isUserInteractionEnabled = false if strongSelf.doneButton.font == .bold { - strongSelf.completion?(strongSelf.selectedEmoticon) + strongSelf.completion?(strongSelf.selectedTheme) } else { strongSelf.controller?.changeWallpaper() } @@ -877,28 +885,76 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega } self.otherButton.addTarget(self, action: #selector(self.otherButtonPressed), forControlEvents: .touchUpInside) - self.disposable.set(combineLatest(queue: Queue.mainQueue(), self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), self.selectedEmoticonPromise.get(), self.isDarkAppearancePromise.get()).startStrict(next: { [weak self] themes, selectedEmoticon, isDarkAppearance in + self.disposable.set(combineLatest( + queue: Queue.mainQueue(), + self.context.engine.themes.getChatThemes(accountManager: self.context.sharedContext.accountManager), + self.uniqueGiftChatThemesContext.state, + self.selectedThemePromise.get(), + self.isDarkAppearancePromise.get() + ).startStrict(next: { [weak self] themes, uniqueGiftChatThemes, selectedTheme, isDarkAppearance in guard let strongSelf = self else { return } - - let selectedEmoticon = selectedEmoticon?.strippedEmoji - + let isFirstTime = strongSelf.entries == nil let presentationData = strongSelf.presentationData var entries: [ThemeSettingsThemeEntry] = [] - entries.append(ThemeSettingsThemeEntry(index: 0, emoticon: nil, emojiFile: nil, themeReference: nil, nightMode: false, selected: selectedEmoticon == nil, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil)) + entries.append(ThemeSettingsThemeEntry( + index: 0, + chatTheme: nil, + emojiFile: nil, + themeReference: nil, + nightMode: false, + selected: selectedTheme == nil, + theme: presentationData.theme, + strings: presentationData.strings, + wallpaper: nil + )) for theme in themes { guard let emoticon = theme.emoticon else { continue } - entries.append(ThemeSettingsThemeEntry(index: entries.count, emoticon: emoticon, emojiFile: animatedEmojiStickers[emoticon]?.first?.file._parse(), themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)), nightMode: isDarkAppearance, selected: selectedEmoticon == theme.emoticon?.strippedEmoji, theme: presentationData.theme, strings: presentationData.strings, wallpaper: nil)) + entries.append(ThemeSettingsThemeEntry( + index: entries.count, + chatTheme: .emoticon(emoticon), + emojiFile: animatedEmojiStickers[emoticon]?.first?.file._parse(), + themeReference: .cloud(PresentationCloudTheme(theme: theme, resolvedWallpaper: nil, creatorAccountId: nil)), + nightMode: isDarkAppearance, + selected: selectedTheme?.id == ChatTheme.emoticon(emoticon).id, + theme: presentationData.theme, + strings: presentationData.strings, + wallpaper: nil + )) + } + for theme in uniqueGiftChatThemes.themes { + guard case let .gift(gift, wallpaperFile) = theme else { + continue + } + var emojiFile: TelegramMediaFile? + if case let .unique(uniqueGift) = gift { + for attribute in uniqueGift.attributes { + if case let .model(_, file, _) = attribute { + emojiFile = file + } + } + } + entries.append(ThemeSettingsThemeEntry( + index: entries.count, + chatTheme: theme, + emojiFile: emojiFile, + themeReference: nil, + nightMode: isDarkAppearance, + selected: selectedTheme?.id == theme.id, + theme: presentationData.theme, + strings: presentationData.strings, + wallpaper: .file(TelegramWallpaper.File(id: wallpaperFile.fileId.id, accessHash: 0, isCreator: false, isDefault: false, isPattern: true, isDark: false, slug: "", file: wallpaperFile, settings: WallpaperSettings(blur: false, motion: false, colors: [], intensity: 100, rotation: 0))) + )) } - let action: (String?) -> Void = { [weak self] emoticon in - if let strongSelf = self, strongSelf.selectedEmoticon != emoticon { - strongSelf.setEmoticon(emoticon) + let action: (ChatTheme?) -> Void = { [weak self] chatTheme in + if let self, self.selectedTheme != chatTheme { + self.setChatTheme(chatTheme) } } let previousEntries = strongSelf.entries ?? [] @@ -982,7 +1038,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega var scrollToItem: ListViewScrollToItem? if !self.initialized { if let index = transition.entries.firstIndex(where: { entry in - return entry.emoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji + return entry.chatTheme?.id == self.initiallySelectedTheme?.id }) { scrollToItem = ListViewScrollToItem(index: index, position: .bottom(-57.0), animated: false, curve: .Default(duration: 0.0), directionHint: .Down) self.initialized = true @@ -994,13 +1050,13 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega } private var skipButtonsUpdate = false - private func setEmoticon(_ emoticon: String?) { + private func setChatTheme(_ chatTheme: ChatTheme?) { self.animateCrossfade(animateIcon: true) self.skipButtonsUpdate = true - self.previewTheme?(emoticon, self.isDarkAppearance) - self.selectedEmoticon = emoticon - let _ = ensureThemeVisible(listNode: self.listNode, emoticon: emoticon, animated: true) + self.previewTheme?(chatTheme, self.isDarkAppearance) + self.selectedTheme = chatTheme + let _ = ensureThemeVisible(listNode: self.listNode, themeId: chatTheme?.id, animated: true) UIView.transition(with: self.buttonsContentContainerNode.view, duration: ChatThemeScreen.themeCrossfadeDuration, options: [.transitionCrossDissolve, .curveLinear]) { self.updateButtons() @@ -1018,11 +1074,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega let doneButtonTitle: String var accentButtonTheme = true var otherIsEnabled = false - if self.selectedEmoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji { + if self.selectedTheme?.id == self.initiallySelectedTheme?.id { otherIsEnabled = self.controller?.canResetWallpaper == true doneButtonTitle = otherIsEnabled ? self.presentationData.strings.Conversation_Theme_SetNewPhotoWallpaper : self.presentationData.strings.Conversation_Theme_SetPhotoWallpaper accentButtonTheme = false - } else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil { + } else if self.selectedTheme?.id == nil && self.initiallySelectedTheme?.id != nil { doneButtonTitle = self.presentationData.strings.Conversation_Theme_Reset } else { doneButtonTitle = self.presentationData.strings.Conversation_Theme_Apply @@ -1051,9 +1107,9 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega private func updateCancelButton() { var cancelButtonState: WebAppCancelButtonNode.State = .cancel - if self.selectedEmoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji { + if self.selectedTheme?.id == self.initiallySelectedTheme?.id { - } else if self.selectedEmoticon == nil && self.initiallySelectedEmoticon != nil { + } else if self.selectedTheme == nil && self.initiallySelectedTheme != nil { cancelButtonState = .back } else { cancelButtonState = .back @@ -1120,15 +1176,15 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega @objc func cancelButtonPressed() { if self.cancelButtonNode.state == .back { - self.setEmoticon(self.initiallySelectedEmoticon) + self.setChatTheme(self.initiallySelectedTheme) } else { self.cancel?() } } @objc func otherButtonPressed() { - if self.selectedEmoticon?.strippedEmoji != self.initiallySelectedEmoticon?.strippedEmoji { - self.setEmoticon(self.initiallySelectedEmoticon) + if self.selectedTheme?.id != self.initiallySelectedTheme?.id { + self.setChatTheme(self.initiallySelectedTheme) } else { if self.controller?.canResetWallpaper == true { self.controller?.resetWallpaper() @@ -1140,12 +1196,12 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega } func dimTapped() { - if self.selectedEmoticon?.strippedEmoji == self.initiallySelectedEmoticon?.strippedEmoji { + if self.selectedTheme?.id == self.initiallySelectedTheme?.id { self.cancelButtonPressed() } else { let alertController = textAlertController(context: self.context, updatedPresentationData: (self.presentationData, .single(self.presentationData)), title: nil, text: self.presentationData.strings.Conversation_Theme_DismissAlert, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Conversation_Theme_DismissAlertApply, action: { [weak self] in if let strongSelf = self { - strongSelf.completion?(strongSelf.selectedEmoticon) + strongSelf.completion?(strongSelf.selectedTheme) } })], actionLayout: .horizontal, dismissOnOutsideTap: true) self.present?(alertController) @@ -1165,7 +1221,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, ASScrollViewDelega } let isDarkAppearance = !self.isDarkAppearance - self.previewTheme?(self.selectedEmoticon, isDarkAppearance) + self.previewTheme?(self.selectedTheme, isDarkAppearance) self.isDarkAppearance = isDarkAppearance if isDarkAppearance { diff --git a/submodules/TelegramUI/Sources/MediaManager.swift b/submodules/TelegramUI/Sources/MediaManager.swift index 1d7556ecec..a15b8172b7 100644 --- a/submodules/TelegramUI/Sources/MediaManager.swift +++ b/submodules/TelegramUI/Sources/MediaManager.swift @@ -15,6 +15,7 @@ import TelegramUniversalVideoContent import DeviceProximity import MediaResources import PhotoResources +import PeerMessagesMediaPlaylist enum SharedMediaPlayerGroup: Int { case music = 0 diff --git a/submodules/TelegramUI/Sources/OpenChatMessage.swift b/submodules/TelegramUI/Sources/OpenChatMessage.swift index 6abd752090..8d1943adcc 100644 --- a/submodules/TelegramUI/Sources/OpenChatMessage.swift +++ b/submodules/TelegramUI/Sources/OpenChatMessage.swift @@ -25,6 +25,7 @@ import GalleryData import StoryContainerScreen import WallpaperGalleryScreen import BrowserUI +import PeerMessagesMediaPlaylist func openChatMessageImpl(_ params: OpenChatMessageParams) -> Bool { var story: TelegramMediaStory? diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift index fd9589a119..d365e1f937 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerController.swift @@ -18,8 +18,6 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer let playlistLocation: SharedMediaPlaylistLocation? private(set) weak var parentNavigationController: NavigationController? - private let updateMusicSaved: ((FileMediaReference, Bool) -> Void)? - let reorderSavedMusic: ((FileMediaReference, FileMediaReference?) -> Void)? private var animatedIn = false @@ -36,9 +34,7 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation? = nil, - parentNavigationController: NavigationController?, - updateMusicSaved: ((FileMediaReference, Bool) -> Void)? = nil, - reorderSavedMusic: ((FileMediaReference, FileMediaReference?) -> Void)? = nil + parentNavigationController: NavigationController? ) { self.context = context self.chatLocation = chatLocation @@ -47,8 +43,6 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer self.initialOrder = initialOrder self.playlistLocation = playlistLocation self.parentNavigationController = parentNavigationController - self.updateMusicSaved = updateMusicSaved - self.reorderSavedMusic = reorderSavedMusic super.init(navigationBarPresentationData: nil) @@ -70,95 +64,82 @@ final class OverlayAudioPlayerControllerImpl: ViewController, OverlayAudioPlayer override public func loadDisplayNode() { self.displayNode = OverlayAudioPlayerControllerNode(context: self.context, chatLocation: self.chatLocation, type: self.type, initialMessageId: self.initialMessageId, initialOrder: self.initialOrder, playlistLocation: self.playlistLocation, requestDismiss: { [weak self] in self?.dismiss() - }, requestShare: { [weak self] messageId in + }, requestShare: { [weak self] subject in if let strongSelf = self { - let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) - |> deliverOnMainQueue).startStandalone(next: { message in - if let strongSelf = self, let message = message { - let shareController = ShareController(context: strongSelf.context, subject: .messages([message._asMessage()]), showInChat: { message in - if let strongSelf = self { - strongSelf.context.sharedContext.navigateToChat(accountId: strongSelf.context.account.id, peerId: message.id.peerId, messageId: message.id) - strongSelf.dismiss() - } - }, externalShare: true) - shareController.completed = { [weak self] peerIds in - if let strongSelf = self { - let _ = (strongSelf.context.engine.data.get( - EngineDataList( - peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init) - ) - ) - |> deliverOnMainQueue).startStandalone(next: { [weak self] peerList in - if let strongSelf = self { - let peers = peerList.compactMap { $0 } - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - - let text: String - var savedMessages = false - if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId { - text = presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One - savedMessages = true - } else { - if peers.count == 1, let peer = peers.first { - var peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - peerName = peerName.replacingOccurrences(of: "**", with: "") - text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string - } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { - var firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "") - var secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "") - text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string - } else if let peer = peers.first { - var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) - peerName = peerName.replacingOccurrences(of: "**", with: "") - text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string - } else { - text = "" - } - } - - strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in - if savedMessages, let self, action == .info { - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)) - |> deliverOnMainQueue).start(next: { [weak self] peer in - guard let self, let peer else { - return - } - guard let navigationController = self.parentNavigationController else { - return - } - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), forceOpenChat: true)) - }) - } - return false - }), in: .current) - } - }) - } - } - strongSelf.controllerNode.view.endEditing(true) - strongSelf.present(shareController, in: .window(.root)) + var canShowInChat = false + if case .messages = subject { + canShowInChat = true + } + let shareController = ShareController(context: strongSelf.context, subject: subject, showInChat: canShowInChat ? { message in + if let strongSelf = self { + strongSelf.context.sharedContext.navigateToChat(accountId: strongSelf.context.account.id, peerId: message.id.peerId, messageId: message.id) + strongSelf.dismiss() } - }) + } : nil, externalShare: true) + shareController.completed = { [weak self] peerIds in + if let strongSelf = self { + let _ = (strongSelf.context.engine.data.get( + EngineDataList( + peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init) + ) + ) + |> deliverOnMainQueue).startStandalone(next: { [weak self] peerList in + if let strongSelf = self { + let peers = peerList.compactMap { $0 } + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + + let text: String + var savedMessages = false + if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId { + text = presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One + savedMessages = true + } else { + if peers.count == 1, let peer = peers.first { + var peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + peerName = peerName.replacingOccurrences(of: "**", with: "") + text = presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string + } else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last { + var firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "") + var secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "") + text = presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string + } else if let peer = peers.first { + var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + peerName = peerName.replacingOccurrences(of: "**", with: "") + text = presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").string + } else { + text = "" + } + } + + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { action in + if savedMessages, let self, action == .info { + let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId)) + |> deliverOnMainQueue).start(next: { [weak self] peer in + guard let self, let peer else { + return + } + guard let navigationController = self.parentNavigationController else { + return + } + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), forceOpenChat: true)) + }) + } + return false + }), in: .current) + } + }) + } + } + strongSelf.controllerNode.view.endEditing(true) + strongSelf.present(shareController, in: .window(.root)) } }, requestSearchByArtist: { [weak self] artist in if let strongSelf = self { strongSelf.context.sharedContext.openSearch(filter: .music, query: artist) strongSelf.dismiss() } - }, updateMusicSaved: { [weak self] file, isSaved in - if let self { - if let updateMusicSaved = self.updateMusicSaved { - updateMusicSaved(file, isSaved) - } else { - if isSaved { - let _ = self.context.engine.peers.addSavedMusic(file: file).start() - } else { - let _ = self.context.engine.peers.removeSavedMusic(file: file).start() - } - } - } }, getParentController: { [weak self] in return self diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index acefc1a9fe..b455c391d7 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -25,9 +25,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu private var presentationData: PresentationData private let type: MediaManagerPlayerType private let requestDismiss: () -> Void - private let requestShare: (MessageId) -> Void + private let requestShare: (ShareControllerSubject) -> Void private let requestSearchByArtist: (String) -> Void - private let updateMusicSaved: (FileMediaReference, Bool) -> Void private let playlistLocation: SharedMediaPlaylistLocation? private let isGlobalSearch: Bool @@ -66,9 +65,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, requestDismiss: @escaping () -> Void, - requestShare: @escaping (MessageId) -> Void, + requestShare: @escaping (ShareControllerSubject) -> Void, requestSearchByArtist: @escaping (String) -> Void, - updateMusicSaved: @escaping (FileMediaReference, Bool) -> Void, getParentController: @escaping () -> ViewController? ) { self.context = context @@ -79,11 +77,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.requestShare = requestShare self.requestSearchByArtist = requestSearchByArtist self.playlistLocation = playlistLocation - self.updateMusicSaved = updateMusicSaved self.getParentController = getParentController - if let playlistLocation = playlistLocation as? PeerMessagesPlaylistLocation, case let .custom(messages, canReorder, at, loadMore) = playlistLocation { - self.source = .custom(messages: messages, messageId: at, quote: nil, updateAll: false, canReorder: canReorder, loadMore: loadMore) + if let playlistLocation = playlistLocation as? PeerMessagesPlaylistLocation, case let .custom(messages, canReorder, at, loadMore) = playlistLocation.effectiveLocation(context: context) { + self.source = .custom(messages: messages, messageId: at, quote: nil, isSavedMusic: true, canReorder: canReorder, loadMore: loadMore) self.isGlobalSearch = false } else { self.source = .default @@ -262,7 +259,6 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.historyNode = ChatHistoryListNodeImpl(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, adMessagesContext: nil, tag: .tag(tagMask), source: self.source, subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), isChatPreview: false, messageTransitionNode: { return nil }) self.historyNode.clipsToBounds = true - //self.historyNode.areContentAnimationsEnabled = true super.init() @@ -271,6 +267,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.historyNode.preloadPages = true self.historyNode.stackFromBottom = true + self.historyNode.areContentAnimationsEnabled = true self.historyNode.updateFloatingHeaderOffset = { [weak self] offset, transition in if let strongSelf = self { strongSelf.updateFloatingHeaderOffset(offset: offset, transition: transition) @@ -301,8 +298,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self?.requestDismiss() } - self.controlsNode.requestShare = { [weak self] messageId in - self?.requestShare(messageId) + self.controlsNode.requestShare = { [weak self] subject in + self?.requestShare(subject) } self.controlsNode.requestSearchByArtist = { [weak self] artist in @@ -363,8 +360,12 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu openMessageImpl = { [weak self] id in if let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.historyNode.messageInCurrentHistoryView(id) { var playlistLocation: PeerMessagesPlaylistLocation? - if let location = strongSelf.playlistLocation as? PeerMessagesPlaylistLocation, case let .custom(messages, canReorder, _, loadMore) = location { - playlistLocation = .custom(messages: messages, canReorder: canReorder, at: id, loadMore: loadMore) + if let location = strongSelf.playlistLocation as? PeerMessagesPlaylistLocation { + if case let .custom(messages, canReorder, _, loadMore) = location { + playlistLocation = .custom(messages: messages, canReorder: canReorder, at: id, loadMore: loadMore) + } else if case let .savedMusic(context, _, canReorder) = location { + playlistLocation = .savedMusic(context: context, at: id.id, canReorder: canReorder) + } } return strongSelf.context.sharedContext.openChatMessage(OpenChatMessageParams(context: strongSelf.context, chatLocation: nil, chatFilterTag: nil, chatLocationContextHolder: nil, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: nil, dismissInput: { }, present: { _, _, _ in }, transitionNode: { _, _, _ in return nil }, addToTransitionSurface: { _ in }, openUrl: { _ in }, openPeer: { _, _ in }, callPeer: { _, _ in }, openConferenceCall: { _ in }, enqueueMessage: { _ in }, sendSticker: nil, sendEmoji: nil, setupTemporaryHiddenMedia: { _, _, _ in }, chatAvatarHiddenMedia: { _, _ in }, playlistLocation: playlistLocation)) @@ -452,47 +453,51 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu } private func setupReordering() { - guard let controller = self.getParentController() as? OverlayAudioPlayerControllerImpl, let reorderSavedMusic = controller.reorderSavedMusic, case let .peer(peerId) = self.chatLocation else { + guard let playlistLocation = self.playlistLocation as? PeerMessagesPlaylistLocation, case let .savedMusic(savedMusicContext, _, canReorder) = playlistLocation, canReorder else { return } - let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)) + let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: savedMusicContext.peerId)) |> deliverOnMainQueue).start(next: { [weak self] peer in guard let self, let peer = peer.flatMap({ PeerReference($0._asPeer()) }) else { return } + self.historyNode.reorderItem = { fromIndex, toIndex, transactionOpaqueState -> Signal in - guard let filteredEntries = (transactionOpaqueState as? ChatHistoryTransactionOpaqueState)?.historyView.filteredEntries else { + guard let filteredEntries = (transactionOpaqueState as? ChatHistoryTransactionOpaqueState)?.historyView.filteredEntries, !filteredEntries.isEmpty else { return .single(false) } - let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] - let toEntry: ChatHistoryEntry? - if toIndex == 0 { - toEntry = nil + + func mapIndex(_ uiIndex: Int) -> Int { + return filteredEntries.count - 1 - uiIndex + } + + let mappedFromIndex = mapIndex(fromIndex) + guard filteredEntries.indices.contains(mappedFromIndex), case let .MessageEntry(fromMessage, _, _, _, _, _) = filteredEntries[mappedFromIndex], let fromFile = fromMessage.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile else { + return .single(false) + } + + var afterFile: TelegramMediaFile? + if toIndex > 0 { + let afterMappedIndex = mapIndex(toIndex - 1) + if filteredEntries.indices.contains(afterMappedIndex), case let .MessageEntry(afterMessage, _, _, _, _, _) = filteredEntries[afterMappedIndex], let file = afterMessage.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile { + afterFile = file + } } else { - toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] - } - guard case let .MessageEntry(fromMessage, _, _, _, _, _) = fromEntry else { - return .single(false) - } - - guard let fromFile = fromMessage.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile else { - return .single(false) + afterFile = nil } - var toFile: TelegramMediaFile? - if let toEntry, case let .MessageEntry(toMessage, _, _, _, _, _) = toEntry, let file = toMessage.media.first(where: { $0 is TelegramMediaFile }) as? TelegramMediaFile { - toFile = file - } - if fromFile.id == toFile?.id { - return .single(false) - } - - reorderSavedMusic(.savedMusic(peer: peer, media: fromFile), toFile.flatMap { .savedMusic(peer: peer, media: $0) }) - + let _ = savedMusicContext.addMusic( + file: .savedMusic(peer: peer, media: fromFile), + afterFile: afterFile.flatMap { .savedMusic(peer: peer, media: $0) } + ).start() + return .single(true) } }) + self.historyNode.useMainQueueTransactions = true + self.historyNode.autoScrollWhenReordering = false } + func updatePresentationData(_ presentationData: PresentationData) { self.presentationData = presentationData @@ -533,6 +538,22 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.getParentController()?.present(controller, in: .window(.root)) } + private func updateMusicSaved(file: FileMediaReference, isSaved: Bool) { + if let playlistLocation = self.playlistLocation as? PeerMessagesPlaylistLocation, case let .savedMusic(savedMusicContext, _, _) = playlistLocation, savedMusicContext.peerId == self.context.account.peerId { + if isSaved { + let _ = savedMusicContext.addMusic(file: file).start() + } else { + let _ = savedMusicContext.removeMusic(file: file).start() + } + } else { + if isSaved { + let _ = self.context.engine.peers.addSavedMusic(file: file).start() + } else { + let _ = self.context.engine.peers.removeSavedMusic(file: file).start() + } + } + } + func addToSavedMusic(file: FileMediaReference) { self.dismissAllTooltips() @@ -580,7 +601,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu ) self.getParentController()?.present(controller, in: .window(.root)) - self.updateMusicSaved(file, true) + self.updateMusicSaved(file: file, isSaved: true) } func removeFromSavedMusic(file: FileMediaReference) { @@ -602,7 +623,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu } ) - if self.historyNode.originalHistoryView?.entries.count == 1 { + if let itemId = self.controlsNode.currentItemId as? PeerMessagesMediaPlaylistItemId, itemId.messageId.namespace == Namespaces.Message.Local && itemId.messageId.peerId == self.context.account.peerId, self.historyNode.originalHistoryView?.entries.count == 1 { if let navigationController = (self.getParentController() as? OverlayAudioPlayerControllerImpl)?.parentNavigationController { self.requestDismiss() navigationController.presentOverlay(controller: controller) @@ -613,7 +634,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu self.getParentController()?.present(controller, in: .window(.root)) } - self.updateMusicSaved(file, false) + self.updateMusicSaved(file: file, isSaved: false) } private var isSaved: Bool? { @@ -831,6 +852,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu historyNode.clipsToBounds = true historyNode.preloadPages = true historyNode.stackFromBottom = true + historyNode.areContentAnimationsEnabled = true historyNode.updateFloatingHeaderOffset = { [weak self] offset, _ in self?.replacementHistoryNodeFloatingOffset = offset } @@ -971,7 +993,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu let fileReference: FileMediaReference = message.id.namespace == Namespaces.Message.Local ? .savedMusic(peer: peer, media: file) : .message(message: MessageReference(message), media: file) let canSaveToProfile = !(self.savedIds?.contains(file.fileId.id) == true) - let canSaveToSavedMessages = message.id.peerId != self.context.account.peerId + let canSaveToSavedMessages = message.id.peerId != self.context.account.peerId || message.id.namespace == Namespaces.Message.Local let _ = (context.sharedContext.chatAvailableMessageActions(engine: context.engine, accountPeerId: context.account.peerId, messageIds: [message.id], keepUpdated: false) |> deliverOnMainQueue).startStandalone(next: { [weak self] actions in @@ -995,7 +1017,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu if canSaveToProfile { subActions.append( - .action(ContextMenuActionItem(text: "…Profile", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in + .action(ContextMenuActionItem(text: "Profile", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) if let self { @@ -1007,7 +1029,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu if canSaveToSavedMessages { subActions.append( - .action(ContextMenuActionItem(text: "…Saved Messages", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in + .action(ContextMenuActionItem(text: "Saved Messages", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Fave"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) if let self { @@ -1018,7 +1040,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu } subActions.append( - .action(ContextMenuActionItem(text: "…Files", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in + .action(ContextMenuActionItem(text: "Files", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.default) if let self { @@ -1074,9 +1096,13 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu }))) } - items.append(.separator) + var addedSeparator = false if message.id.namespace == Namespaces.Message.Cloud { + if !addedSeparator { + items.append(.separator) + addedSeparator = true + } items.append( .action(ContextMenuActionItem(text: "Show in Chat", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) @@ -1101,8 +1127,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu // ) var canDelete = false - if message.id.namespace == Namespaces.Message.Local { - canDelete = true + if case .custom = self.source { + if self.savedIds?.contains(file.fileId.id) == true { + canDelete = true + } } else if let peer = message.peers[message.id.peerId] { if peer is TelegramUser || peer is TelegramSecretChat { canDelete = true @@ -1122,6 +1150,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu } if canDelete { + if !addedSeparator { + items.append(.separator) + addedSeparator = true + } var actionTitle = "Delete" if case .custom = self.source { actionTitle = "Remove" @@ -1203,6 +1235,7 @@ private final class OverlayAudioPlayerContextExtractedContentSource: ContextExtr let keepInPlace: Bool = false let ignoreContentTouches: Bool = false let blurBackground: Bool = true + let additionalInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 80.0, right: 0.0) private let contentNode: ContextExtractedContentContainingNode diff --git a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift index d18bc300b3..3132575d1e 100644 --- a/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift +++ b/submodules/TelegramUI/Sources/OverlayPlayerControlsNode.swift @@ -198,7 +198,7 @@ final class OverlayPlayerControlsNode: ASDisplayNode { var updateIsExpanded: (() -> Void)? var requestCollapse: (() -> Void)? - var requestShare: ((MessageId) -> Void)? + var requestShare: ((ShareControllerSubject) -> Void)? var requestSearchByArtist: ((String) -> Void)? var requestSaveToProfile: ((FileMediaReference) -> Void)? var requestRemoveFromProfile: ((FileMediaReference) -> Void)? @@ -1027,26 +1027,30 @@ final class OverlayPlayerControlsNode: ASDisplayNode { if hasSectionHeader { //TODO:localize + let sideInset: CGFloat = 16.0 var sectionTitle = "AUDIO IN THIS CHAT" if let peerName = self.peerName { - sectionTitle = "\(peerName)'S PLAYLIST" + sectionTitle = "\(peerName.uppercased())'S PLAYLIST" } else if case .custom = self.source { sectionTitle = "YOUR PLAYLIST" } let sectionTitleSize = self.sectionTitle.update( transition: .immediate, component: AnyComponent( - MultilineTextComponent(text: .plain(NSAttributedString(string: sectionTitle, font: Font.regular(13.0), textColor: self.presentationData.theme.chatList.sectionHeaderTextColor))) + MultilineTextComponent( + text: .plain(NSAttributedString(string: sectionTitle, font: Font.regular(13.0), textColor: self.presentationData.theme.chatList.sectionHeaderTextColor)), + truncationType: .middle + ) ), environment: {}, - containerSize: CGSize(width: width, height: OverlayPlayerControlsNode.sectionHeaderHeight) + containerSize: CGSize(width: width - leftInset - rightInset - sideInset * 2.0, height: OverlayPlayerControlsNode.sectionHeaderHeight) ) if let sectionTitleView = self.sectionTitle.view { if sectionTitleView.superview == nil { self.view.addSubview(sectionTitleView) } sectionTitleView.bounds = CGRect(origin: .zero, size: sectionTitleSize) - sectionHeaderTransition.updateFrame(view: sectionTitleView, frame: CGRect(origin: CGPoint(x: leftInset + 16.0, y: finalPanelHeight - OverlayPlayerControlsNode.sectionHeaderHeight + 6.0 + UIScreenPixel), size: sectionTitleSize)) + sectionHeaderTransition.updateFrame(view: sectionTitleView, frame: CGRect(origin: CGPoint(x: leftInset + sideInset, y: finalPanelHeight - OverlayPlayerControlsNode.sectionHeaderHeight + 6.0 + UIScreenPixel), size: sectionTitleSize)) } } else if let sectionTitleView = self.sectionTitle.view, sectionTitleView.superview != nil { sectionTitleView.removeFromSuperview() @@ -1184,7 +1188,17 @@ final class OverlayPlayerControlsNode: ASDisplayNode { @objc func sharePressed() { if let itemId = self.currentItemId as? PeerMessagesMediaPlaylistItemId { - self.requestShare?(itemId.messageId) + if itemId.messageId.namespace == Namespaces.Message.Cloud { + let _ = (self.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: itemId.messageId)) + |> deliverOnMainQueue).startStandalone(next: { [weak self] message in + guard let message else { + return + } + self?.requestShare?(.messages([message._asMessage()])) + }) + } else if let fileReference = self.currentFileReference { + self.requestShare?(.media(fileReference.abstract, nil)) + } } } diff --git a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift index 386c91c9ca..67e24534ad 100644 --- a/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift +++ b/submodules/TelegramUI/Sources/PreparedChatHistoryViewTransition.swift @@ -9,7 +9,7 @@ import ChatControllerInteraction import ChatHistoryEntry import ChatMessageBubbleItemNode -func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, scrollAnimationCurve: ListViewAnimationCurve?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNodeImpl?, allUpdated: Bool) -> ChatHistoryViewTransition { +func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, source: ChatHistoryListSource, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, scrollAnimationCurve: ListViewAnimationCurve?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNodeImpl?, allUpdated: Bool) -> ChatHistoryViewTransition { var mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)]) let allUpdated = allUpdated || (fromView?.associatedData != toView.associatedData) if reverse { @@ -141,6 +141,11 @@ func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toVie let curve: ListViewAnimationCurve = scrollAnimationCurve ?? .Default(duration: nil) + var isSavedMusic = false + if case let .custom(_, _, _, isSavedMusicValue, _, _) = source { + isSavedMusic = isSavedMusicValue + } + if let scrollPosition = scrollPosition { switch scrollPosition { case let .unread(unreadIndex): @@ -238,9 +243,17 @@ func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toVie } var index = toView.filteredEntries.count - 1 for entry in toView.filteredEntries { - if scrollIndex.index.isLessOrEqual(to: entry.index) { - scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: curve, directionHint: directionHint, displayLink: displayLink) - break + if isSavedMusic { + if case let .message(messageIndex) = scrollIndex.index, messageIndex.id == entry.index.id { + print(messageIndex.id) + scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: curve, directionHint: directionHint, displayLink: displayLink) + break + } + } else { + if scrollIndex.index.isLessOrEqual(to: entry.index) { + scrollToItem = ListViewScrollToItem(index: index, position: position, animated: animated, curve: curve, directionHint: directionHint, displayLink: displayLink) + break + } } index -= 1 } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 3dc718dbdf..693d64930e 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1786,11 +1786,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { }) } - public func makeOverlayAudioPlayerController(context: AccountContext, chatLocation: ChatLocation, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, parentNavigationController: NavigationController?, updateMusicSaved: ((FileMediaReference, Bool) -> Void)?, reorderSavedMusic: ((FileMediaReference, FileMediaReference?) -> Void)?) -> ViewController & OverlayAudioPlayerController { - if let playlistLocation = playlistLocation as? PeerMessagesPlaylistLocation, case .custom = playlistLocation { - context.sharedContext.mediaManager.setPlaylist((context, PeerMessagesMediaPlaylist(context: context, location: playlistLocation, chatLocationContextHolder: nil)), type: .music, control: .playback(.play)) - } - return OverlayAudioPlayerControllerImpl(context: context, chatLocation: chatLocation, type: type, initialMessageId: initialMessageId, initialOrder: initialOrder, playlistLocation: playlistLocation, parentNavigationController: parentNavigationController, updateMusicSaved: updateMusicSaved, reorderSavedMusic: reorderSavedMusic) + public func makeOverlayAudioPlayerController(context: AccountContext, chatLocation: ChatLocation, type: MediaManagerPlayerType, initialMessageId: MessageId, initialOrder: MusicPlaybackSettingsOrder, playlistLocation: SharedMediaPlaylistLocation?, parentNavigationController: NavigationController?) -> ViewController & OverlayAudioPlayerController { + return OverlayAudioPlayerControllerImpl(context: context, chatLocation: chatLocation, type: type, initialMessageId: initialMessageId, initialOrder: initialOrder, playlistLocation: playlistLocation, parentNavigationController: parentNavigationController) } public func makeTempAccountContext(account: Account) -> AccountContext { diff --git a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift index 709dfaeab8..7d48f091fa 100644 --- a/submodules/TelegramUI/Sources/SharedMediaPlayer.swift +++ b/submodules/TelegramUI/Sources/SharedMediaPlayer.swift @@ -9,6 +9,7 @@ import TelegramAudio import AccountContext import TelegramUniversalVideoContent import DeviceProximity +import PeerMessagesMediaPlaylist private enum SharedMediaPlaybackItem: Equatable { case audio(MediaPlayer) diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index b2537ee679..55f1cc2c25 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -80,7 +80,7 @@ public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [M private let syntaxHighlighter = Syntaxer() -public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, codeBlockTitleColor: UIColor? = nil, codeBlockAccentColor: UIColor? = nil, codeBlockBackgroundColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil) -> NSAttributedString { +public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, codeBlockTitleColor: UIColor? = nil, codeBlockAccentColor: UIColor? = nil, codeBlockBackgroundColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil, paragraphAlignment: NSTextAlignment? = nil) -> NSAttributedString { let baseQuoteTintColor = baseQuoteTintColor ?? baseColor var nsString: NSString? @@ -356,6 +356,12 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti } }) + if let paragraphAlignment = paragraphAlignment { + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.alignment = paragraphAlignment + string.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, string.length)) + } + return string } diff --git a/versions.json b/versions.json index 7816fd08cd..6c85ab5077 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "11.14.1", + "app": "11.15", "xcode": "16.2", "bazel": "8.3.1:0cac3a67dc5429c68272dc6944104952e9e4cf84b29d126a5ff3fbaa59045217", "macos": "15"