diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a356d66a0a..43853e1334 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7419,3 +7419,9 @@ Sorry for the inconvenience."; "WebApp.MessagePreview" = "Message Preview"; "WebApp.Send" = "Send"; + +"Notifications.SystemTones" = "SYSTEM TONES"; +"Notifications.TelegramTones" = "TELEGRAM TONES"; + +"Notifications.UploadSound" = "Upload Sound"; +"Notifications.MessageSoundInfo" = "Long tap on any short voice note or mp3 file in chat\nand select \"Save for Notifications\". It will appear here."; diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index e7de9e8d56..a0dd33aae8 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -464,6 +464,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate { }, openSendAsPeer: { _, _ in }, presentChatRequestAdminInfo: { }, displayCopyProtectionTip: { _, _ in + }, chatController: { + return nil }, statuses: nil) self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData) diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift index dcca2efc29..9420327a45 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatPanelInterfaceInteraction.swift @@ -142,6 +142,7 @@ public final class ChatPanelInterfaceInteraction { public let openSendAsPeer: (ASDisplayNode, ContextGesture?) -> Void public let presentChatRequestAdminInfo: () -> Void public let displayCopyProtectionTip: (ASDisplayNode, Bool) -> Void + public let chatController: () -> ViewController? public let statuses: ChatPanelInterfaceInteractionStatuses? public init( @@ -233,6 +234,7 @@ public final class ChatPanelInterfaceInteraction { openSendAsPeer: @escaping (ASDisplayNode, ContextGesture?) -> Void, presentChatRequestAdminInfo: @escaping () -> Void, displayCopyProtectionTip: @escaping (ASDisplayNode, Bool) -> Void, + chatController: @escaping () -> ViewController?, statuses: ChatPanelInterfaceInteractionStatuses? ) { self.setupReplyMessage = setupReplyMessage @@ -323,6 +325,7 @@ public final class ChatPanelInterfaceInteraction { self.openSendAsPeer = openSendAsPeer self.presentChatRequestAdminInfo = presentChatRequestAdminInfo self.displayCopyProtectionTip = displayCopyProtectionTip + self.chatController = chatController self.statuses = statuses } @@ -420,6 +423,8 @@ public final class ChatPanelInterfaceInteraction { }, openSendAsPeer: { _, _ in }, presentChatRequestAdminInfo: { }, displayCopyProtectionTip: { _, _ in + }, chatController: { + return nil }, statuses: nil) } } diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index 3985b2769a..8a59bc8e9a 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -94,6 +94,8 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin self.addSubnode(self.subtitleNode) self.addSubnode(self.iconNode) + self.isEnabled = self.canBeHighlighted() + self.highligthedChanged = { [weak self] highlighted in guard let strongSelf = self else { return @@ -135,7 +137,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin } func canBeHighlighted() -> Bool { - return true + return self.item.action != nil } func updateIsHighlighted(isHighlighted: Bool) { diff --git a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift index 279192ec90..fb6c35b8dd 100644 --- a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift @@ -225,7 +225,12 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo } private func getActionsStackPositionLock() -> CGFloat? { - return self.actionsStackNode.view.convert(CGPoint(), to: self.view).y + switch self.source { + case .reference: + return nil + case .extracted: + return self.actionsStackNode.view.convert(CGPoint(), to: self.view).y + } } func update( diff --git a/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift b/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift index 0742398138..37f0cb61af 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListCheckboxItem.swift @@ -16,9 +16,15 @@ public enum ItemListCheckboxItemColor { } public class ItemListCheckboxItem: ListViewItem, ItemListItem { + public enum IconPlacement { + case `default` + case check + } + let presentationData: ItemListPresentationData let icon: UIImage? let iconSize: CGSize? + let iconPlacement: IconPlacement let title: String let style: ItemListCheckboxItemStyle let color: ItemListCheckboxItemColor @@ -27,10 +33,11 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem { public let sectionId: ItemListSectionId let action: () -> Void - public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, title: String, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void) { + public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void) { self.presentationData = presentationData self.icon = icon self.iconSize = iconSize + self.iconPlacement = iconPlacement self.title = title self.style = style self.color = color @@ -158,7 +165,12 @@ public class ItemListCheckboxItemNode: ListViewItemNode { let iconInset: CGFloat = 44.0 if item.icon != nil { - leftInset += iconInset + switch item.iconPlacement { + case .default: + leftInset += iconInset + case .check: + break + } } let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize) @@ -273,7 +285,15 @@ public class ItemListCheckboxItemNode: ListViewItemNode { if let icon = item.icon { let iconSize = item.iconSize ?? icon.size strongSelf.imageNode.image = icon - strongSelf.imageNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - iconSize.width) / 2.0), y: floor((layout.contentSize.height - iconSize.height) / 2.0)), size: iconSize) + + let iconFrame: CGRect + switch item.iconPlacement { + case .default: + iconFrame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - iconSize.width) / 2.0), y: floor((layout.contentSize.height - iconSize.height) / 2.0)), size: iconSize) + case .check: + iconFrame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - iconSize.width) / 2.0), y: floor((contentSize.height - iconSize.height) / 2.0)), size: iconSize) + } + strongSelf.imageNode.frame = iconFrame } strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: strongSelf.backgroundNode.frame.height + UIScreenPixel + UIScreenPixel)) diff --git a/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift b/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift index d9346c9003..3d34a6ef96 100644 --- a/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift +++ b/submodules/NotificationMuteSettingsUI/Sources/NotificationMuteSettingsController.swift @@ -20,7 +20,7 @@ public struct NotificationSoundSettings { } } -public func notificationMuteSettingsController(presentationData: PresentationData, notificationSettings: MessageNotificationSettings, soundSettings: NotificationSoundSettings?, openSoundSettings: @escaping () -> Void, updateSettings: @escaping (Int32?) -> Void) -> ViewController { +public func notificationMuteSettingsController(presentationData: PresentationData, notificationSoundList: NotificationSoundList?, notificationSettings: MessageNotificationSettings, soundSettings: NotificationSoundSettings?, openSoundSettings: @escaping () -> Void, updateSettings: @escaping (Int32?) -> Void) -> ViewController { let controller = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak controller] in controller?.dismissAnimated() @@ -81,7 +81,7 @@ public func notificationMuteSettingsController(presentationData: PresentationDat items.append(item) } if let soundSettings = soundSettings { - items.append(ActionSheetButtonItem(title: soundSettings.value.flatMap({ presentationData.strings.Notification_Exceptions_Sound(localizedPeerNotificationSoundString(strings: presentationData.strings, sound: $0)).string }) ?? presentationData.strings.GroupInfo_SetSound, action: { + items.append(ActionSheetButtonItem(title: soundSettings.value.flatMap({ presentationData.strings.Notification_Exceptions_Sound(localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: $0)).string }) ?? presentationData.strings.GroupInfo_SetSound, action: { dismissAction() openSoundSettings() })) diff --git a/submodules/NotificationSoundSelectionUI/BUILD b/submodules/NotificationSoundSelectionUI/BUILD index 8a0519ab3b..0f9fe3632f 100644 --- a/submodules/NotificationSoundSelectionUI/BUILD +++ b/submodules/NotificationSoundSelectionUI/BUILD @@ -19,6 +19,8 @@ swift_library( "//submodules/AccountContext:AccountContext", "//submodules/TelegramStringFormatting:TelegramStringFormatting", "//submodules/PresentationDataUtils:PresentationDataUtils", + "//submodules/LegacyMediaPickerUI:LegacyMediaPickerUI", + "//submodules/UndoUI:UndoUI", ], visibility = [ "//visibility:public", diff --git a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift index 0be8217d1e..a3e43760a5 100644 --- a/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift +++ b/submodules/NotificationSoundSelectionUI/Sources/NotificationSoundSelection.swift @@ -10,6 +10,9 @@ import PresentationDataUtils import AccountContext import TelegramStringFormatting import AppBundle +import LegacyMediaPickerUI +import AVFoundation +import UndoUI private struct NotificationSoundSelectionArguments { let account: Account @@ -17,22 +20,24 @@ private struct NotificationSoundSelectionArguments { let selectSound: (PeerMessageSound) -> Void let complete: () -> Void let cancel: () -> Void + let upload: () -> Void } private enum NotificationSoundSelectionSection: Int32 { + case cloud case modern case classic } private struct NotificationSoundSelectionState: Equatable { - let selectedSound: PeerMessageSound - - static func ==(lhs: NotificationSoundSelectionState, rhs: NotificationSoundSelectionState) -> Bool { - return lhs.selectedSound == rhs.selectedSound - } + var selectedSound: PeerMessageSound } private enum NotificationSoundSelectionEntry: ItemListNodeEntry { + case cloudHeader(String) + case uploadSound(String) + case cloudInfo(String) + case modernHeader(PresentationTheme, String) case classicHeader(PresentationTheme, String) case none(section: NotificationSoundSelectionSection, theme: PresentationTheme, text: String, selected: Bool) @@ -41,6 +46,8 @@ private enum NotificationSoundSelectionEntry: ItemListNodeEntry { var section: ItemListSectionId { switch self { + case .cloudHeader, .uploadSound, .cloudInfo: + return NotificationSoundSelectionSection.cloud.rawValue case .modernHeader: return NotificationSoundSelectionSection.modern.rawValue case .classicHeader: @@ -54,68 +61,102 @@ private enum NotificationSoundSelectionEntry: ItemListNodeEntry { } } - var stableId: Int32 { + var sortId: Int32 { switch self { - case .modernHeader: - return 0 - case .classicHeader: - return 1000 - case let .none(section, _, _, _): - switch section { - case .modern: - return 2 - case .classic: - return 1001 - } - case let .default(section, _, _, _): - switch section { - case .modern: - return 1 - case .classic: - return 1002 - } - case let .sound(section, index, _, _, _, _): - switch section { - case .modern: - return 3 + index - case .classic: - return 1003 + index - } + case .cloudHeader: + return 0 + case .uploadSound: + return 998 + case .cloudInfo: + return 999 + case .modernHeader: + return 1000 + case .classicHeader: + return 2000 + case let .none(section, _, _, _): + switch section { + case .cloud: + return 1 + case .modern: + return 1001 + case .classic: + return 2001 + } + case let .default(section, _, _, _): + switch section { + case .cloud: + return 2 + case .modern: + return 1002 + case .classic: + return 2002 + } + case let .sound(section, index, _, _, _, _): + switch section { + case .cloud: + return 3 + index + case .modern: + return 1003 + index + case .classic: + return 2003 + index + } } } + var stableId: Int32 { + return self.sortId + } + static func ==(lhs: NotificationSoundSelectionEntry, rhs: NotificationSoundSelectionEntry) -> Bool { switch lhs { - case let .modernHeader(lhsTheme, lhsText): - if case let .modernHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .classicHeader(lhsTheme, lhsText): - if case let .classicHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { - return true - } else { - return false - } - case let .none(lhsSection, lhsTheme, lhsText, lhsSelected): - if case let .none(rhsSection, rhsTheme, rhsText, rhsSelected) = rhs, lhsSection == rhsSection, lhsTheme === rhsTheme, lhsText == rhsText, lhsSelected == rhsSelected { - return true - } else { - return false - } - case let .default(lhsSection, lhsTheme, lhsText, lhsSelected): - if case let .default(rhsSection, rhsTheme, rhsText, rhsSelected) = rhs, lhsSection == rhsSection, lhsTheme === rhsTheme, lhsText == rhsText, lhsSelected == rhsSelected { - return true - } else { - return false - } - case let .sound(lhsSection, lhsIndex, lhsTheme, lhsText, lhsSound, lhsSelected): - if case let .sound(rhsSection, rhsIndex, rhsTheme, rhsText, rhsSound, rhsSelected) = rhs, lhsSection == rhsSection, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsText == rhsText, lhsSound == rhsSound, lhsSelected == rhsSelected { - return true - } else { - return false - } + case let .cloudHeader(text): + if case .cloudHeader(text) = rhs { + return true + } else { + return false + } + case let .cloudInfo(text): + if case .cloudInfo(text) = rhs { + return true + } else { + return false + } + case let .uploadSound(text): + if case .uploadSound(text) = rhs { + return true + } else { + return false + } + case let .modernHeader(lhsTheme, lhsText): + if case let .modernHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .classicHeader(lhsTheme, lhsText): + if case let .classicHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { + return true + } else { + return false + } + case let .none(lhsSection, lhsTheme, lhsText, lhsSelected): + if case let .none(rhsSection, rhsTheme, rhsText, rhsSelected) = rhs, lhsSection == rhsSection, lhsTheme === rhsTheme, lhsText == rhsText, lhsSelected == rhsSelected { + return true + } else { + return false + } + case let .default(lhsSection, lhsTheme, lhsText, lhsSelected): + if case let .default(rhsSection, rhsTheme, rhsText, rhsSelected) = rhs, lhsSection == rhsSection, lhsTheme === rhsTheme, lhsText == rhsText, lhsSelected == rhsSelected { + return true + } else { + return false + } + case let .sound(lhsSection, lhsIndex, lhsTheme, lhsText, lhsSound, lhsSelected): + if case let .sound(rhsSection, rhsIndex, rhsTheme, rhsText, rhsSound, rhsSelected) = rhs, lhsSection == rhsSection, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsText == rhsText, lhsSound == rhsSound, lhsSelected == rhsSelected { + return true + } else { + return false + } } } @@ -126,43 +167,63 @@ private enum NotificationSoundSelectionEntry: ItemListNodeEntry { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { let arguments = arguments as! NotificationSoundSelectionArguments switch self { - case let.modernHeader(_, text): - return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) - case let .classicHeader(_, text): - return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) - case let .none(_, _, text, selected): - return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: true, sectionId: self.section, action: { - arguments.selectSound(.none) - }) - case let .default(_, _, text, selected): - return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { - arguments.selectSound(.default) - }) - case let .sound(_, _, _, text, sound, selected): - return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { - arguments.selectSound(sound) - }) + case let .cloudHeader(text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .uploadSound(text): + let icon = PresentationResourcesItemList.uploadToneIcon(presentationData.theme) + return ItemListCheckboxItem(presentationData: presentationData, icon: icon, iconSize: nil, iconPlacement: .check, title: text, style: .left, checked: false, zeroSeparatorInsets: false, sectionId: self.section, action: { + arguments.upload() + }) + case let .cloudInfo(text): + return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) + case let .modernHeader(_, text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .classicHeader(_, text): + return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) + case let .none(_, _, text, selected): + return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: true, sectionId: self.section, action: { + arguments.selectSound(.none) + }) + case let .default(_, _, text, selected): + return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { + arguments.selectSound(.default) + }) + case let .sound(_, _, _, text, sound, selected): + return ItemListCheckboxItem(presentationData: presentationData, title: text, style: .left, checked: selected, zeroSeparatorInsets: false, sectionId: self.section, action: { + arguments.selectSound(sound) + }) } } } -private func notificationsAndSoundsEntries(presentationData: PresentationData, defaultSound: PeerMessageSound?, state: NotificationSoundSelectionState) -> [NotificationSoundSelectionEntry] { +private func notificationsAndSoundsEntries(presentationData: PresentationData, defaultSound: PeerMessageSound?, state: NotificationSoundSelectionState, notificationSoundList: NotificationSoundList?) -> [NotificationSoundSelectionEntry] { var entries: [NotificationSoundSelectionEntry] = [] + entries.append(.cloudHeader(presentationData.strings.Notifications_TelegramTones)) + //entries.append(.none(section: .cloud, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: .none), selected: state.selectedSound == .none)) + if let notificationSoundList = notificationSoundList { + for listSound in notificationSoundList.sounds { + let sound: PeerMessageSound = .cloud(fileId: listSound.file.fileId.id) + entries.append(.sound(section: .cloud, index: Int32(entries.count), theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: sound), sound: sound, selected: state.selectedSound.id == sound.id)) + } + } + entries.append(.uploadSound(presentationData.strings.Notifications_UploadSound)) + entries.append(.cloudInfo(presentationData.strings.Notifications_MessageSoundInfo)) + entries.append(.modernHeader(presentationData.theme, presentationData.strings.Notifications_AlertTones)) if let defaultSound = defaultSound { - entries.append(.default(section: .modern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .default, default: defaultSound), selected: state.selectedSound == .default)) + entries.append(.default(section: .modern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: .default, default: defaultSound), selected: state.selectedSound.id == .default)) } - entries.append(.none(section: .modern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .none), selected: state.selectedSound == .none)) + entries.append(.none(section: .modern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: .none), selected: state.selectedSound.id == .none)) for i in 0 ..< 12 { let sound: PeerMessageSound = .bundledModern(id: Int32(i)) - entries.append(.sound(section: .modern, index: Int32(i), theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound)) + entries.append(.sound(section: .modern, index: Int32(i), theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: sound), sound: sound, selected: sound.id == state.selectedSound.id)) } entries.append(.classicHeader(presentationData.theme, presentationData.strings.Notifications_ClassicTones)) for i in 0 ..< 8 { let sound: PeerMessageSound = .bundledClassic(id: Int32(i)) - entries.append(.sound(section: .classic, index: Int32(i), theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound)) + entries.append(.sound(section: .classic, index: Int32(i), theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: sound), sound: sound, selected: sound.id == state.selectedSound.id)) } return entries @@ -195,28 +256,40 @@ private final class AudioPlayerWrapper: NSObject, AVAudioPlayerDelegate { } } -public func fileNameForNotificationSound(_ sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> String { +public func fileNameForNotificationSound(account: Account, notificationSoundList: NotificationSoundList?, sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> String { switch sound { - case .none: - return "" - case .default: - if let defaultSound = defaultSound { - if case .default = defaultSound { - return "\(100)" - } else { - return fileNameForNotificationSound(defaultSound, defaultSound: nil) - } - } else { + case .none: + return "" + case .default: + if let defaultSound = defaultSound { + if case .default = defaultSound { return "\(100)" + } else { + return fileNameForNotificationSound(account: account, notificationSoundList: notificationSoundList, sound: defaultSound, defaultSound: nil) } - case let .bundledModern(id): - return "\(id + 100)" - case let .bundledClassic(id): - return "\(id + 2)" + } else { + return "\(100)" + } + case let .bundledModern(id): + return "\(id + 100)" + case let .bundledClassic(id): + return "\(id + 2)" + case let .cloud(fileId): + guard let notificationSoundList = notificationSoundList else { + return "" + } + for sound in notificationSoundList.sounds { + if sound.file.fileId.id == fileId { + if let path = account.postbox.mediaBox.completedResourcePath(sound.file.resource, pathExtension: "mp3") { + return path + } + } + } + return "" } } -public func playSound(context: AccountContext, sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> Signal { +public func playSound(context: AccountContext, notificationSoundList: NotificationSoundList?, sound: PeerMessageSound, defaultSound: PeerMessageSound?) -> Signal { if case .none = sound { return .complete() } else { @@ -225,11 +298,20 @@ public func playSound(context: AccountContext, sound: PeerMessageSound, defaultS var deactivateImpl: (() -> Void)? let session = context.sharedContext.mediaManager.audioSession.push(audioSessionType: .play, activate: { _ in Queue.mainQueue().async { - if let url = getAppBundle().url(forResource: fileNameForNotificationSound(sound, defaultSound: defaultSound), withExtension: "m4a") { - currentPlayer = AudioPlayerWrapper(url: url, completed: { + let filePath = fileNameForNotificationSound(account: context.account, notificationSoundList: notificationSoundList, sound: sound, defaultSound: defaultSound) + + if filePath.contains("/") { + currentPlayer = AudioPlayerWrapper(url: URL(fileURLWithPath: filePath), completed: { deactivateImpl?() }) currentPlayer?.play() + } else { + if let url = getAppBundle().url(forResource: filePath, withExtension: "m4a") { + currentPlayer = AudioPlayerWrapper(url: url, completed: { + deactivateImpl?() + }) + currentPlayer?.play() + } } } }, deactivate: { _ in @@ -266,25 +348,32 @@ public func notificationSoundSelectionController(context: AccountContext, update var completeImpl: (() -> Void)? var cancelImpl: (() -> Void)? + var presentFilePicker: (() -> Void)? let playSoundDisposable = MetaDisposable() + let soundActionDisposable = MetaDisposable() let arguments = NotificationSoundSelectionArguments(account: context.account, selectSound: { sound in updateState { state in return NotificationSoundSelectionState(selectedSound: sound) } - playSoundDisposable.set(playSound(context: context, sound: sound, defaultSound: defaultSound).start()) + let _ = (context.engine.peers.notificationSoundList() + |> take(1) + |> deliverOnMainQueue).start(next: { notificationSoundList in + playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: defaultSound).start()) + }) }, complete: { completeImpl?() }, cancel: { cancelImpl?() + }, upload: { + presentFilePicker?() }) let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData - let signal = combineLatest(presentationData, statePromise.get()) - |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in - + let signal = combineLatest(presentationData, statePromise.get(), context.engine.peers.notificationSoundList()) + |> map { presentationData, state, notificationSoundList -> (ItemListControllerState, (ItemListNodeState, Any)) in let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { arguments.cancel() }) @@ -294,13 +383,14 @@ public func notificationSoundSelectionController(context: AccountContext, update }) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.Notifications_TextTone), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: notificationsAndSoundsEntries(presentationData: presentationData, defaultSound: defaultSound, state: state), style: .blocks) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: notificationsAndSoundsEntries(presentationData: presentationData, defaultSound: defaultSound, state: state, notificationSoundList: notificationSoundList), style: .blocks) return (controllerState, (listState, arguments)) } let controller = ItemListController(context: context, state: signal |> afterDisposed { playSoundDisposable.dispose() + soundActionDisposable.dispose() }) controller.enableInteractiveDismiss = true if isModal { @@ -319,5 +409,57 @@ public func notificationSoundSelectionController(context: AccountContext, update controller?.dismiss() } + var presentUndo: ((UndoOverlayContent) -> Void)? + + + presentFilePicker = { [weak controller] in + guard let controller = controller else { + return + } + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + controller.present(legacyICloudFilePicker(theme: presentationData.theme, documentTypes: ["public.mp3"], completion: { urls in + guard !urls.isEmpty, let url = urls.first else { + return + } + + let coordinator = NSFileCoordinator(filePresenter: nil) + var error: NSError? + coordinator.coordinate(readingItemAt: url, options: .forUploading, error: &error, byAccessor: { url in + Queue.mainQueue().async { + let asset = AVAsset(url: url) + + guard let data = try? Data(contentsOf: url) else { + return + } + if data.count > 200 * 1024 { + presentUndo?(.info(title: "Audio is too large", text: "The file is larger than 200 KB.")) + return + } + + asset.loadValuesAsynchronously(forKeys: ["duration"], completionHandler: { + let duration = asset.duration.seconds + if duration > 5.0 { + //TODO:localize + presentUndo?(.info(title: "Audio is too long", text: "The duration is longer than 5 seconds.")) + } else { + soundActionDisposable.set((context.engine.peers.uploadNotificationSound(title: url.lastPathComponent, data: data) + |> deliverOnMainQueue).start(next: { _ in + }, error: { _ in + })) + } + }) + } + }) + }), in: .window(.root)) + } + + presentUndo = { [weak controller] content in + guard let controller = controller else { + return + } + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + controller.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + } + return controller } diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift index f141af50d7..207e371981 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionControllerNode.swift @@ -287,7 +287,7 @@ public enum NotificationExceptionMode : Equatable { } } -private func notificationsExceptionEntries(presentationData: PresentationData, state: NotificationExceptionState, query: String? = nil, foundPeers: [RenderedPeer] = []) -> [NotificationExceptionEntry] { +private func notificationsExceptionEntries(presentationData: PresentationData, notificationSoundList: NotificationSoundList?, state: NotificationExceptionState, query: String? = nil, foundPeers: [RenderedPeer] = []) -> [NotificationExceptionEntry] { var entries: [NotificationExceptionEntry] = [] if !state.isSearchMode { @@ -361,7 +361,7 @@ private func notificationsExceptionEntries(presentationData: PresentationData, s case .default: break default: - let soundName = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: value.settings.messageSound) + let soundName = localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: value.settings.messageSound) title += (title.isEmpty ? presentationData.strings.Notification_Exceptions_Sound(soundName).string : ", \(presentationData.strings.Notification_Exceptions_Sound(soundName).string)") } switch value.settings.displayPreviews { @@ -975,8 +975,8 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode { let previousEntriesHolder = Atomic<([NotificationExceptionEntry], PresentationTheme, PresentationStrings)?>(value: nil) - self.listDisposable = (combineLatest(context.sharedContext.presentationData, statePromise.get(), preferences) |> deliverOnMainQueue).start(next: { [weak self] (presentationData, state, prefs) in - let entries = notificationsExceptionEntries(presentationData: presentationData, state: state) + self.listDisposable = (combineLatest(context.sharedContext.presentationData, statePromise.get(), preferences, context.engine.peers.notificationSoundList()) |> deliverOnMainQueue).start(next: { [weak self] presentationData, state, prefs, notificationSoundList in + let entries = notificationsExceptionEntries(presentationData: presentationData, notificationSoundList: notificationSoundList, state: state) let previousEntriesAndPresentationData = previousEntriesHolder.swap((entries, presentationData.theme, presentationData.strings)) updateCanStartEditing(state.mode.peerIds.isEmpty ? nil : state.editing) @@ -1233,16 +1233,16 @@ private final class NotificationExceptionsSearchContainerNode: SearchDisplayCont |> distinctUntilChanged let searchSignal = stateQuery - |> mapToSignal { query -> Signal<(PresentationData, (NotificationExceptionState, String?), PreferencesView, [RenderedPeer]), NoError> in + |> mapToSignal { query -> Signal<(PresentationData, NotificationSoundList?, (NotificationExceptionState, String?), PreferencesView, [RenderedPeer]), NoError> in var contactsSignal: Signal<[RenderedPeer], NoError> = .single([]) if let query = query { contactsSignal = context.account.postbox.searchPeers(query: query) } - return combineLatest(context.sharedContext.presentationData, stateAndPeers, preferences, contactsSignal) + return combineLatest(context.sharedContext.presentationData, context.engine.peers.notificationSoundList(), stateAndPeers, preferences, contactsSignal) } self.searchDisposable.set((searchSignal - |> deliverOnMainQueue).start(next: { [weak self] (presentationData, state, prefs, foundPeers) in - let entries = notificationsExceptionEntries(presentationData: presentationData, state: state.0, query: state.1, foundPeers: foundPeers) + |> deliverOnMainQueue).start(next: { [weak self] presentationData, notificationSoundList, state, prefs, foundPeers in + let entries = notificationsExceptionEntries(presentationData: presentationData, notificationSoundList: notificationSoundList, state: state.0, query: state.1, foundPeers: foundPeers) let previousEntriesAndPresentationData = previousEntriesHolder.swap((entries, presentationData.theme, presentationData.strings)) let transition = preparedNotificationExceptionsSearchContainerTransition(presentationData: ItemListPresentationData(presentationData), from: previousEntriesAndPresentationData?.0 ?? [], to: entries, arguments: arguments, isSearching: state.1 != nil && !state.1!.isEmpty, forceUpdate: previousEntriesAndPresentationData?.1 !== presentationData.theme || previousEntriesAndPresentationData?.2 !== presentationData.strings) diff --git a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift index 1ae28d59c5..40b8161a6a 100644 --- a/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift +++ b/submodules/SettingsUI/Sources/Notifications/Exceptions/NotificationExceptionSettingsController.swift @@ -209,7 +209,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry { } -private func notificationPeerExceptionEntries(presentationData: PresentationData, state: NotificationExceptionPeerState) -> [NotificationPeerExceptionEntry] { +private func notificationPeerExceptionEntries(presentationData: PresentationData, notificationSoundList: NotificationSoundList?, state: NotificationExceptionPeerState) -> [NotificationPeerExceptionEntry] { var entries:[NotificationPeerExceptionEntry] = [] var index: Int32 = 0 @@ -239,15 +239,15 @@ private func notificationPeerExceptionEntries(presentationData: PresentationData entries.append(.soundModernHeader(index: index, theme: presentationData.theme, title: presentationData.strings.Notifications_AlertTones)) index += 1 - entries.append(.default(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .default, default: state.defaultSound), selected: state.selectedSound == .default)) + entries.append(.default(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: .default, default: state.defaultSound), selected: state.selectedSound == .default)) index += 1 - entries.append(.none(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: .none), selected: state.selectedSound == .none)) + entries.append(.none(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: .none), selected: state.selectedSound == .none)) index += 1 for i in 0 ..< 12 { let sound: PeerMessageSound = .bundledModern(id: Int32(i)) - entries.append(.sound(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound)) + entries.append(.sound(index: index, section: .soundModern, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: sound), sound: sound, selected: sound == state.selectedSound)) index += 1 } @@ -256,7 +256,7 @@ private func notificationPeerExceptionEntries(presentationData: PresentationData for i in 0 ..< 8 { let sound: PeerMessageSound = .bundledClassic(id: Int32(i)) - entries.append(.sound(index: index, section: .soundClassic, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, sound: sound), sound: sound, selected: sound == state.selectedSound)) + entries.append(.sound(index: index, section: .soundClassic, theme: presentationData.theme, text: localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: sound), sound: sound, selected: sound == state.selectedSound)) index += 1 } } @@ -330,7 +330,12 @@ public func notificationPeerExceptionController(context: AccountContext, updated let arguments = NotificationPeerExceptionArguments(account: context.account, selectSound: { sound in updateState { state in - playSoundDisposable.set(playSound(context: context, sound: sound, defaultSound: state.defaultSound).start()) + let _ = (context.engine.peers.notificationSoundList() + |> take(1) + |> deliverOnMainQueue).start(next: { notificationSoundList in + playSoundDisposable.set(playSound(context: context, notificationSoundList: notificationSoundList, sound: sound, defaultSound: state.defaultSound).start()) + }) + return state.withUpdatedSound(sound) } }, selectMode: { mode in @@ -365,8 +370,8 @@ public func notificationPeerExceptionController(context: AccountContext, updated }) - let signal = combineLatest(queue: .mainQueue(), (updatedPresentationData?.signal ?? context.sharedContext.presentationData), statePromise.get() |> distinctUntilChanged) - |> map { presentationData, state -> (ItemListControllerState, (ItemListNodeState, Any)) in + let signal = combineLatest(queue: .mainQueue(), (updatedPresentationData?.signal ?? context.sharedContext.presentationData), context.engine.peers.notificationSoundList(), statePromise.get() |> distinctUntilChanged) + |> map { presentationData, notificationSoundList, state -> (ItemListControllerState, (ItemListNodeState, Any)) in let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: { arguments.cancel() }) @@ -376,7 +381,7 @@ public func notificationPeerExceptionController(context: AccountContext, updated }) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: notificationPeerExceptionEntries(presentationData: presentationData, state: state), style: .blocks, animateChanges: false) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: notificationPeerExceptionEntries(presentationData: presentationData, notificationSoundList: notificationSoundList, state: state), style: .blocks, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift b/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift index f1f33910cb..d4ca96c152 100644 --- a/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift +++ b/submodules/SettingsUI/Sources/NotificationsPeerCategoryController.swift @@ -249,7 +249,7 @@ private func filteredGlobalSound(_ sound: PeerMessageSound) -> PeerMessageSound } } -private func notificationsPeerCategoryEntries(category: NotificationsPeerCategory, globalSettings: GlobalNotificationSettingsSet, state: NotificationExceptionState, presentationData: PresentationData) -> [NotificationsPeerCategoryEntry] { +private func notificationsPeerCategoryEntries(category: NotificationsPeerCategory, globalSettings: GlobalNotificationSettingsSet, state: NotificationExceptionState, presentationData: PresentationData, notificationSoundList: NotificationSoundList?) -> [NotificationsPeerCategoryEntry] { var entries: [NotificationsPeerCategoryEntry] = [] let notificationSettings: MessageNotificationSettings @@ -268,7 +268,7 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor if notificationSettings.enabled || !notificationExceptions.isEmpty { entries.append(.optionsHeader(presentationData.theme, presentationData.strings.Notifications_Options.uppercased())) entries.append(.previews(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsPreview, notificationSettings.displayPreviews)) - entries.append(.sound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, sound: filteredGlobalSound(notificationSettings.sound)), filteredGlobalSound(notificationSettings.sound))) + entries.append(.sound(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsSound, localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: filteredGlobalSound(notificationSettings.sound)), filteredGlobalSound(notificationSettings.sound))) } entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.Notifications_MessageNotificationsExceptions.uppercased())) @@ -338,7 +338,7 @@ private func notificationsPeerCategoryEntries(category: NotificationsPeerCategor case .default: break default: - let soundName = localizedPeerNotificationSoundString(strings: presentationData.strings, sound: value.settings.messageSound) + let soundName = localizedPeerNotificationSoundString(strings: presentationData.strings, notificationSoundList: notificationSoundList, sound: value.settings.messageSound) title += (title.isEmpty ? presentationData.strings.Notification_Exceptions_Sound(soundName).string : ", \(presentationData.strings.Notification_Exceptions_Sound(soundName).string)") } switch value.settings.displayPreviews { @@ -687,8 +687,8 @@ public func notificationsPeerCategoryController(context: AccountContext, categor let sharedData = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings]) let preferences = context.account.postbox.preferencesView(keys: [PreferencesKeys.globalNotifications]) - let signal = combineLatest(context.sharedContext.presentationData, sharedData, preferences, statePromise.get()) - |> map { presentationData, sharedData, view, state -> (ItemListControllerState, (ItemListNodeState, Any)) in + let signal = combineLatest(context.sharedContext.presentationData, context.engine.peers.notificationSoundList(), sharedData, preferences, statePromise.get()) + |> map { presentationData, notificationSoundList, sharedData, view, state -> (ItemListControllerState, (ItemListNodeState, Any)) in let viewSettings: GlobalNotificationSettingsSet if let settings = view.values[PreferencesKeys.globalNotifications]?.get(GlobalNotificationSettings.self) { viewSettings = settings.effective @@ -696,7 +696,7 @@ public func notificationsPeerCategoryController(context: AccountContext, categor viewSettings = GlobalNotificationSettingsSet.defaultSettings } - let entries = notificationsPeerCategoryEntries(category: category, globalSettings: viewSettings, state: state, presentationData: presentationData) + let entries = notificationsPeerCategoryEntries(category: category, globalSettings: viewSettings, state: state, presentationData: presentationData, notificationSoundList: notificationSoundList) var index = 0 var scrollToItem: ListViewScrollToItem? diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 40132d9495..9c39fd2c2b 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -303,7 +303,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[2107670217] = { return Api.InputPeer.parse_inputPeerSelf($0) } dict[-571955892] = { return Api.InputPeer.parse_inputPeerUser($0) } dict[-1468331492] = { return Api.InputPeer.parse_inputPeerUserFromMessage($0) } - dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) } + dict[-551616469] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) } dict[506920429] = { return Api.InputPhoneCall.parse_inputPhoneCall($0) } dict[1001634122] = { return Api.InputPhoto.parse_inputPhoto($0) } dict[483901197] = { return Api.InputPhoto.parse_inputPhotoEmpty($0) } @@ -477,6 +477,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1614803355] = { return Api.MessagesFilter.parse_inputMessagesFilterVideo($0) } dict[1358283666] = { return Api.MessagesFilter.parse_inputMessagesFilterVoice($0) } dict[-1910892683] = { return Api.NearestDc.parse_nearestDc($0) } + dict[-1746354498] = { return Api.NotificationSound.parse_notificationSoundDefault($0) } + dict[-2096391452] = { return Api.NotificationSound.parse_notificationSoundLocal($0) } + dict[1863070943] = { return Api.NotificationSound.parse_notificationSoundNone($0) } + dict[-9666487] = { return Api.NotificationSound.parse_notificationSoundRingtone($0) } dict[-703403793] = { return Api.NotifyPeer.parse_notifyBroadcasts($0) } dict[-1073230141] = { return Api.NotifyPeer.parse_notifyChats($0) } dict[-1613493288] = { return Api.NotifyPeer.parse_notifyPeer($0) } @@ -530,7 +534,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-386039788] = { return Api.PeerBlocked.parse_peerBlocked($0) } dict[-901375139] = { return Api.PeerLocated.parse_peerLocated($0) } dict[-118740917] = { return Api.PeerLocated.parse_peerSelfLocated($0) } - dict[-1353671392] = { return Api.PeerNotifySettings.parse_peerNotifySettings($0) } + dict[-1472527322] = { return Api.PeerNotifySettings.parse_peerNotifySettings($0) } dict[-1525149427] = { return Api.PeerSettings.parse_peerSettings($0) } dict[-1770029977] = { return Api.PhoneCall.parse_phoneCall($0) } dict[912311057] = { return Api.PhoneCall.parse_phoneCallAccepted($0) } @@ -787,6 +791,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1757493555] = { return Api.Update.parse_updateReadMessagesContents($0) } dict[-1706939360] = { return Api.Update.parse_updateRecentStickers($0) } dict[-1821035490] = { return Api.Update.parse_updateSavedGifs($0) } + dict[1960361625] = { return Api.Update.parse_updateSavedRingtones($0) } dict[-337352679] = { return Api.Update.parse_updateServiceNotification($0) } dict[1135492588] = { return Api.Update.parse_updateStickerSets($0) } dict[196268545] = { return Api.Update.parse_updateStickerSetsOrder($0) } @@ -845,6 +850,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-478701471] = { return Api.account.ResetPasswordResult.parse_resetPasswordFailedWait($0) } dict[-383330754] = { return Api.account.ResetPasswordResult.parse_resetPasswordOk($0) } dict[-370148227] = { return Api.account.ResetPasswordResult.parse_resetPasswordRequestedWait($0) } + dict[-1041683259] = { return Api.account.SavedRingtones.parse_savedRingtones($0) } + dict[-67704655] = { return Api.account.SavedRingtones.parse_savedRingtonesNotModified($0) } dict[-2128640689] = { return Api.account.SentEmailCode.parse_sentEmailCode($0) } dict[1304052993] = { return Api.account.Takeout.parse_takeout($0) } dict[-1707242387] = { return Api.account.Themes.parse_themes($0) } @@ -1354,6 +1361,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.NearestDc: _1.serialize(buffer, boxed) + case let _1 as Api.NotificationSound: + _1.serialize(buffer, boxed) case let _1 as Api.NotifyPeer: _1.serialize(buffer, boxed) case let _1 as Api.Page: @@ -1550,6 +1559,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.account.ResetPasswordResult: _1.serialize(buffer, boxed) + case let _1 as Api.account.SavedRingtones: + _1.serialize(buffer, boxed) case let _1 as Api.account.SentEmailCode: _1.serialize(buffer, boxed) case let _1 as Api.account.Takeout: diff --git a/submodules/TelegramApi/Sources/Api12.swift b/submodules/TelegramApi/Sources/Api12.swift index a44eb58e9b..af91a1bec8 100644 --- a/submodules/TelegramApi/Sources/Api12.swift +++ b/submodules/TelegramApi/Sources/Api12.swift @@ -680,6 +680,90 @@ public extension Api { } } +public extension Api { + enum NotificationSound: TypeConstructorDescription { + case notificationSoundDefault + case notificationSoundLocal(title: String, data: String) + case notificationSoundNone + case notificationSoundRingtone(id: Int64) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .notificationSoundDefault: + if boxed { + buffer.appendInt32(-1746354498) + } + + break + case .notificationSoundLocal(let title, let data): + if boxed { + buffer.appendInt32(-2096391452) + } + serializeString(title, buffer: buffer, boxed: false) + serializeString(data, buffer: buffer, boxed: false) + break + case .notificationSoundNone: + if boxed { + buffer.appendInt32(1863070943) + } + + break + case .notificationSoundRingtone(let id): + if boxed { + buffer.appendInt32(-9666487) + } + serializeInt64(id, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .notificationSoundDefault: + return ("notificationSoundDefault", []) + case .notificationSoundLocal(let title, let data): + return ("notificationSoundLocal", [("title", String(describing: title)), ("data", String(describing: data))]) + case .notificationSoundNone: + return ("notificationSoundNone", []) + case .notificationSoundRingtone(let id): + return ("notificationSoundRingtone", [("id", String(describing: id))]) + } + } + + public static func parse_notificationSoundDefault(_ reader: BufferReader) -> NotificationSound? { + return Api.NotificationSound.notificationSoundDefault + } + public static func parse_notificationSoundLocal(_ reader: BufferReader) -> NotificationSound? { + 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.NotificationSound.notificationSoundLocal(title: _1!, data: _2!) + } + else { + return nil + } + } + public static func parse_notificationSoundNone(_ reader: BufferReader) -> NotificationSound? { + return Api.NotificationSound.notificationSoundNone + } + public static func parse_notificationSoundRingtone(_ reader: BufferReader) -> NotificationSound? { + var _1: Int64? + _1 = reader.readInt64() + let _c1 = _1 != nil + if _c1 { + return Api.NotificationSound.notificationSoundRingtone(id: _1!) + } + else { + return nil + } + } + + } +} public extension Api { enum NotifyPeer: TypeConstructorDescription { case notifyBroadcasts @@ -754,77 +838,3 @@ public extension Api { } } -public extension Api { - enum Page: TypeConstructorDescription { - case page(flags: Int32, url: String, blocks: [Api.PageBlock], photos: [Api.Photo], documents: [Api.Document], views: Int32?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .page(let flags, let url, let blocks, let photos, let documents, let views): - if boxed { - buffer.appendInt32(-1738178803) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(url, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(blocks.count)) - for item in blocks { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(photos.count)) - for item in photos { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(documents.count)) - for item in documents { - item.serialize(buffer, true) - } - if Int(flags) & Int(1 << 3) != 0 {serializeInt32(views!, buffer: buffer, boxed: false)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .page(let flags, let url, let blocks, let photos, let documents, let views): - return ("page", [("flags", String(describing: flags)), ("url", String(describing: url)), ("blocks", String(describing: blocks)), ("photos", String(describing: photos)), ("documents", String(describing: documents)), ("views", String(describing: views))]) - } - } - - public static func parse_page(_ reader: BufferReader) -> Page? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: [Api.PageBlock]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) - } - var _4: [Api.Photo]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) - } - var _5: [Api.Document]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) - } - var _6: Int32? - if Int(_1!) & Int(1 << 3) != 0 {_6 = reader.readInt32() } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.Page.page(flags: _1!, url: _2!, blocks: _3!, photos: _4!, documents: _5!, views: _6) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api13.swift b/submodules/TelegramApi/Sources/Api13.swift index e3ffcd94a2..4a985aec2a 100644 --- a/submodules/TelegramApi/Sources/Api13.swift +++ b/submodules/TelegramApi/Sources/Api13.swift @@ -1,3 +1,77 @@ +public extension Api { + enum Page: TypeConstructorDescription { + case page(flags: Int32, url: String, blocks: [Api.PageBlock], photos: [Api.Photo], documents: [Api.Document], views: Int32?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .page(let flags, let url, let blocks, let photos, let documents, let views): + if boxed { + buffer.appendInt32(-1738178803) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(url, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(blocks.count)) + for item in blocks { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(photos.count)) + for item in photos { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(documents.count)) + for item in documents { + item.serialize(buffer, true) + } + if Int(flags) & Int(1 << 3) != 0 {serializeInt32(views!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .page(let flags, let url, let blocks, let photos, let documents, let views): + return ("page", [("flags", String(describing: flags)), ("url", String(describing: url)), ("blocks", String(describing: blocks)), ("photos", String(describing: photos)), ("documents", String(describing: documents)), ("views", String(describing: views))]) + } + } + + public static func parse_page(_ reader: BufferReader) -> Page? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.PageBlock]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PageBlock.self) + } + var _4: [Api.Photo]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Photo.self) + } + var _5: [Api.Document]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self) + } + var _6: Int32? + if Int(_1!) & Int(1 << 3) != 0 {_6 = reader.readInt32() } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + let _c6 = (Int(_1!) & Int(1 << 3) == 0) || _6 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { + return Api.Page.page(flags: _1!, url: _2!, blocks: _3!, photos: _4!, documents: _5!, views: _6) + } + else { + return nil + } + } + + } +} public extension Api { indirect enum PageBlock: TypeConstructorDescription { case pageBlockAnchor(name: String) diff --git a/submodules/TelegramApi/Sources/Api14.swift b/submodules/TelegramApi/Sources/Api14.swift index 3741f9aa2e..04b280b2d9 100644 --- a/submodules/TelegramApi/Sources/Api14.swift +++ b/submodules/TelegramApi/Sources/Api14.swift @@ -606,27 +606,29 @@ public extension Api { } public extension Api { enum PeerNotifySettings: TypeConstructorDescription { - case peerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: String?) + case peerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, iosSound: Api.NotificationSound?, androidSound: Api.NotificationSound?, otherSound: Api.NotificationSound?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): + case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let iosSound, let androidSound, let otherSound): if boxed { - buffer.appendInt32(-1353671392) + buffer.appendInt32(-1472527322) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 0) != 0 {showPreviews!.serialize(buffer, true)} if Int(flags) & Int(1 << 1) != 0 {silent!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {serializeInt32(muteUntil!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(sound!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {iosSound!.serialize(buffer, true)} + if Int(flags) & Int(1 << 4) != 0 {androidSound!.serialize(buffer, true)} + if Int(flags) & Int(1 << 5) != 0 {otherSound!.serialize(buffer, true)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): - return ("peerNotifySettings", [("flags", String(describing: flags)), ("showPreviews", String(describing: showPreviews)), ("silent", String(describing: silent)), ("muteUntil", String(describing: muteUntil)), ("sound", String(describing: sound))]) + case .peerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let iosSound, let androidSound, let otherSound): + return ("peerNotifySettings", [("flags", String(describing: flags)), ("showPreviews", String(describing: showPreviews)), ("silent", String(describing: silent)), ("muteUntil", String(describing: muteUntil)), ("iosSound", String(describing: iosSound)), ("androidSound", String(describing: androidSound)), ("otherSound", String(describing: otherSound))]) } } @@ -643,15 +645,27 @@ public extension Api { } } var _4: Int32? if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } - var _5: String? - if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _5: Api.NotificationSound? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.NotificationSound + } } + var _6: Api.NotificationSound? + if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.NotificationSound + } } + var _7: Api.NotificationSound? + if Int(_1!) & Int(1 << 5) != 0 {if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.NotificationSound + } } let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil let _c5 = (Int(_1!) & Int(1 << 3) == 0) || _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.PeerNotifySettings.peerNotifySettings(flags: _1!, showPreviews: _2, silent: _3, muteUntil: _4, sound: _5) + let _c6 = (Int(_1!) & Int(1 << 4) == 0) || _6 != nil + let _c7 = (Int(_1!) & Int(1 << 5) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.PeerNotifySettings.peerNotifySettings(flags: _1!, showPreviews: _2, silent: _3, muteUntil: _4, iosSound: _5, androidSound: _6, otherSound: _7) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api19.swift b/submodules/TelegramApi/Sources/Api19.swift index 3e9fb6e11f..28a01c2a8c 100644 --- a/submodules/TelegramApi/Sources/Api19.swift +++ b/submodules/TelegramApi/Sources/Api19.swift @@ -594,6 +594,7 @@ public extension Api { case updateReadMessagesContents(messages: [Int32], pts: Int32, ptsCount: Int32) case updateRecentStickers case updateSavedGifs + case updateSavedRingtones case updateServiceNotification(flags: Int32, inboxDate: Int32?, type: String, message: String, media: Api.MessageMedia, entities: [Api.MessageEntity]) case updateStickerSets case updateStickerSetsOrder(flags: Int32, order: [Int64]) @@ -1380,6 +1381,12 @@ public extension Api { buffer.appendInt32(-1821035490) } + break + case .updateSavedRingtones: + if boxed { + buffer.appendInt32(1960361625) + } + break case .updateServiceNotification(let flags, let inboxDate, let type, let message, let media, let entities): if boxed { @@ -1655,6 +1662,8 @@ public extension Api { return ("updateRecentStickers", []) case .updateSavedGifs: return ("updateSavedGifs", []) + case .updateSavedRingtones: + return ("updateSavedRingtones", []) case .updateServiceNotification(let flags, let inboxDate, let type, let message, let media, let entities): return ("updateServiceNotification", [("flags", String(describing: flags)), ("inboxDate", String(describing: inboxDate)), ("type", String(describing: type)), ("message", String(describing: message)), ("media", String(describing: media)), ("entities", String(describing: entities))]) case .updateStickerSets: @@ -3265,6 +3274,9 @@ public extension Api { public static func parse_updateSavedGifs(_ reader: BufferReader) -> Update? { return Api.Update.updateSavedGifs } + public static func parse_updateSavedRingtones(_ reader: BufferReader) -> Update? { + return Api.Update.updateSavedRingtones + } public static func parse_updateServiceNotification(_ reader: BufferReader) -> Update? { var _1: Int32? _1 = reader.readInt32() diff --git a/submodules/TelegramApi/Sources/Api21.swift b/submodules/TelegramApi/Sources/Api21.swift index bef7924733..f4dd7fe7d7 100644 --- a/submodules/TelegramApi/Sources/Api21.swift +++ b/submodules/TelegramApi/Sources/Api21.swift @@ -690,6 +690,64 @@ 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", String(describing: hash)), ("ringtones", String(describing: ringtones))]) + 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) @@ -1154,129 +1212,3 @@ public extension Api.auth { } } -public extension Api.auth { - enum LoggedOut: TypeConstructorDescription { - case loggedOut(flags: Int32, futureAuthToken: Buffer?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .loggedOut(let flags, let futureAuthToken): - if boxed { - buffer.appendInt32(-1012759713) - } - serializeInt32(flags, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .loggedOut(let flags, let futureAuthToken): - return ("loggedOut", [("flags", String(describing: flags)), ("futureAuthToken", String(describing: futureAuthToken))]) - } - } - - public static func parse_loggedOut(_ reader: BufferReader) -> LoggedOut? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Buffer? - if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) } - let _c1 = _1 != nil - let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil - if _c1 && _c2 { - return Api.auth.LoggedOut.loggedOut(flags: _1!, futureAuthToken: _2) - } - else { - return nil - } - } - - } -} -public extension Api.auth { - enum LoginToken: TypeConstructorDescription { - case loginToken(expires: Int32, token: Buffer) - case loginTokenMigrateTo(dcId: Int32, token: Buffer) - case loginTokenSuccess(authorization: Api.auth.Authorization) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .loginToken(let expires, let token): - if boxed { - buffer.appendInt32(1654593920) - } - serializeInt32(expires, buffer: buffer, boxed: false) - serializeBytes(token, buffer: buffer, boxed: false) - break - case .loginTokenMigrateTo(let dcId, let token): - if boxed { - buffer.appendInt32(110008598) - } - serializeInt32(dcId, buffer: buffer, boxed: false) - serializeBytes(token, buffer: buffer, boxed: false) - break - case .loginTokenSuccess(let authorization): - if boxed { - buffer.appendInt32(957176926) - } - authorization.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .loginToken(let expires, let token): - return ("loginToken", [("expires", String(describing: expires)), ("token", String(describing: token))]) - case .loginTokenMigrateTo(let dcId, let token): - return ("loginTokenMigrateTo", [("dcId", String(describing: dcId)), ("token", String(describing: token))]) - case .loginTokenSuccess(let authorization): - return ("loginTokenSuccess", [("authorization", String(describing: authorization))]) - } - } - - public static func parse_loginToken(_ reader: BufferReader) -> LoginToken? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Buffer? - _2 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.auth.LoginToken.loginToken(expires: _1!, token: _2!) - } - else { - return nil - } - } - public static func parse_loginTokenMigrateTo(_ reader: BufferReader) -> LoginToken? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Buffer? - _2 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.auth.LoginToken.loginTokenMigrateTo(dcId: _1!, token: _2!) - } - else { - return nil - } - } - public static func parse_loginTokenSuccess(_ reader: BufferReader) -> LoginToken? { - var _1: Api.auth.Authorization? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.auth.Authorization - } - let _c1 = _1 != nil - if _c1 { - return Api.auth.LoginToken.loginTokenSuccess(authorization: _1!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api22.swift b/submodules/TelegramApi/Sources/Api22.swift index d8a05e7801..1a0126bbac 100644 --- a/submodules/TelegramApi/Sources/Api22.swift +++ b/submodules/TelegramApi/Sources/Api22.swift @@ -1,3 +1,129 @@ +public extension Api.auth { + enum LoggedOut: TypeConstructorDescription { + case loggedOut(flags: Int32, futureAuthToken: Buffer?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .loggedOut(let flags, let futureAuthToken): + if boxed { + buffer.appendInt32(-1012759713) + } + serializeInt32(flags, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .loggedOut(let flags, let futureAuthToken): + return ("loggedOut", [("flags", String(describing: flags)), ("futureAuthToken", String(describing: futureAuthToken))]) + } + } + + public static func parse_loggedOut(_ reader: BufferReader) -> LoggedOut? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) } + let _c1 = _1 != nil + let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil + if _c1 && _c2 { + return Api.auth.LoggedOut.loggedOut(flags: _1!, futureAuthToken: _2) + } + else { + return nil + } + } + + } +} +public extension Api.auth { + enum LoginToken: TypeConstructorDescription { + case loginToken(expires: Int32, token: Buffer) + case loginTokenMigrateTo(dcId: Int32, token: Buffer) + case loginTokenSuccess(authorization: Api.auth.Authorization) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .loginToken(let expires, let token): + if boxed { + buffer.appendInt32(1654593920) + } + serializeInt32(expires, buffer: buffer, boxed: false) + serializeBytes(token, buffer: buffer, boxed: false) + break + case .loginTokenMigrateTo(let dcId, let token): + if boxed { + buffer.appendInt32(110008598) + } + serializeInt32(dcId, buffer: buffer, boxed: false) + serializeBytes(token, buffer: buffer, boxed: false) + break + case .loginTokenSuccess(let authorization): + if boxed { + buffer.appendInt32(957176926) + } + authorization.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .loginToken(let expires, let token): + return ("loginToken", [("expires", String(describing: expires)), ("token", String(describing: token))]) + case .loginTokenMigrateTo(let dcId, let token): + return ("loginTokenMigrateTo", [("dcId", String(describing: dcId)), ("token", String(describing: token))]) + case .loginTokenSuccess(let authorization): + return ("loginTokenSuccess", [("authorization", String(describing: authorization))]) + } + } + + public static func parse_loginToken(_ reader: BufferReader) -> LoginToken? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.auth.LoginToken.loginToken(expires: _1!, token: _2!) + } + else { + return nil + } + } + public static func parse_loginTokenMigrateTo(_ reader: BufferReader) -> LoginToken? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.auth.LoginToken.loginTokenMigrateTo(dcId: _1!, token: _2!) + } + else { + return nil + } + } + public static func parse_loginTokenSuccess(_ reader: BufferReader) -> LoginToken? { + var _1: Api.auth.Authorization? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.auth.Authorization + } + let _c1 = _1 != nil + if _c1 { + return Api.auth.LoginToken.loginTokenSuccess(authorization: _1!) + } + else { + return nil + } + } + + } +} public extension Api.auth { enum PasswordRecovery: TypeConstructorDescription { case passwordRecovery(emailPattern: String) @@ -1178,183 +1304,3 @@ public extension Api.help { } } -public extension Api.help { - enum Country: TypeConstructorDescription { - case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .country(let flags, let iso2, let defaultName, let name, let countryCodes): - if boxed { - buffer.appendInt32(-1014526429) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(iso2, buffer: buffer, boxed: false) - serializeString(defaultName, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)} - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(countryCodes.count)) - for item in countryCodes { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .country(let flags, let iso2, let defaultName, let name, let countryCodes): - return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))]) - } - } - - public static func parse_country(_ reader: BufferReader) -> Country? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: String? - _3 = parseString(reader) - var _4: String? - if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } - var _5: [Api.help.CountryCode]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!) - } - else { - return nil - } - } - - } -} -public extension Api.help { - enum CountryCode: TypeConstructorDescription { - case countryCode(flags: Int32, countryCode: String, prefixes: [String]?, patterns: [String]?) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .countryCode(let flags, let countryCode, let prefixes, let patterns): - if boxed { - buffer.appendInt32(1107543535) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(countryCode, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(prefixes!.count)) - for item in prefixes! { - serializeString(item, buffer: buffer, boxed: false) - }} - if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(patterns!.count)) - for item in patterns! { - serializeString(item, buffer: buffer, boxed: false) - }} - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .countryCode(let flags, let countryCode, let prefixes, let patterns): - return ("countryCode", [("flags", String(describing: flags)), ("countryCode", String(describing: countryCode)), ("prefixes", String(describing: prefixes)), ("patterns", String(describing: patterns))]) - } - } - - public static func parse_countryCode(_ reader: BufferReader) -> CountryCode? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: [String]? - if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) - } } - var _4: [String]? - if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil - let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.help.CountryCode.countryCode(flags: _1!, countryCode: _2!, prefixes: _3, patterns: _4) - } - else { - return nil - } - } - - } -} -public extension Api.help { - enum DeepLinkInfo: TypeConstructorDescription { - case deepLinkInfo(flags: Int32, message: String, entities: [Api.MessageEntity]?) - case deepLinkInfoEmpty - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .deepLinkInfo(let flags, let message, let entities): - if boxed { - buffer.appendInt32(1783556146) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeString(message, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(entities!.count)) - for item in entities! { - item.serialize(buffer, true) - }} - break - case .deepLinkInfoEmpty: - if boxed { - buffer.appendInt32(1722786150) - } - - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .deepLinkInfo(let flags, let message, let entities): - return ("deepLinkInfo", [("flags", String(describing: flags)), ("message", String(describing: message)), ("entities", String(describing: entities))]) - case .deepLinkInfoEmpty: - return ("deepLinkInfoEmpty", []) - } - } - - public static func parse_deepLinkInfo(_ reader: BufferReader) -> DeepLinkInfo? { - var _1: Int32? - _1 = reader.readInt32() - var _2: String? - _2 = parseString(reader) - var _3: [Api.MessageEntity]? - if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) - } } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil - if _c1 && _c2 && _c3 { - return Api.help.DeepLinkInfo.deepLinkInfo(flags: _1!, message: _2!, entities: _3) - } - else { - return nil - } - } - public static func parse_deepLinkInfoEmpty(_ reader: BufferReader) -> DeepLinkInfo? { - return Api.help.DeepLinkInfo.deepLinkInfoEmpty - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api23.swift b/submodules/TelegramApi/Sources/Api23.swift index 3bfadcddae..70e96ff045 100644 --- a/submodules/TelegramApi/Sources/Api23.swift +++ b/submodules/TelegramApi/Sources/Api23.swift @@ -1,3 +1,183 @@ +public extension Api.help { + enum Country: TypeConstructorDescription { + case country(flags: Int32, iso2: String, defaultName: String, name: String?, countryCodes: [Api.help.CountryCode]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .country(let flags, let iso2, let defaultName, let name, let countryCodes): + if boxed { + buffer.appendInt32(-1014526429) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(iso2, buffer: buffer, boxed: false) + serializeString(defaultName, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeString(name!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(countryCodes.count)) + for item in countryCodes { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .country(let flags, let iso2, let defaultName, let name, let countryCodes): + return ("country", [("flags", String(describing: flags)), ("iso2", String(describing: iso2)), ("defaultName", String(describing: defaultName)), ("name", String(describing: name)), ("countryCodes", String(describing: countryCodes))]) + } + } + + public static func parse_country(_ reader: BufferReader) -> Country? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: String? + _3 = parseString(reader) + var _4: String? + if Int(_1!) & Int(1 << 1) != 0 {_4 = parseString(reader) } + var _5: [Api.help.CountryCode]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.help.CountryCode.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.help.Country.country(flags: _1!, iso2: _2!, defaultName: _3!, name: _4, countryCodes: _5!) + } + else { + return nil + } + } + + } +} +public extension Api.help { + enum CountryCode: TypeConstructorDescription { + case countryCode(flags: Int32, countryCode: String, prefixes: [String]?, patterns: [String]?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .countryCode(let flags, let countryCode, let prefixes, let patterns): + if boxed { + buffer.appendInt32(1107543535) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(countryCode, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(prefixes!.count)) + for item in prefixes! { + serializeString(item, buffer: buffer, boxed: false) + }} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(patterns!.count)) + for item in patterns! { + serializeString(item, buffer: buffer, boxed: false) + }} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .countryCode(let flags, let countryCode, let prefixes, let patterns): + return ("countryCode", [("flags", String(describing: flags)), ("countryCode", String(describing: countryCode)), ("prefixes", String(describing: prefixes)), ("patterns", String(describing: patterns))]) + } + } + + public static func parse_countryCode(_ reader: BufferReader) -> CountryCode? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [String]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) + } } + var _4: [String]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil + let _c4 = (Int(_1!) & Int(1 << 1) == 0) || _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.help.CountryCode.countryCode(flags: _1!, countryCode: _2!, prefixes: _3, patterns: _4) + } + else { + return nil + } + } + + } +} +public extension Api.help { + enum DeepLinkInfo: TypeConstructorDescription { + case deepLinkInfo(flags: Int32, message: String, entities: [Api.MessageEntity]?) + case deepLinkInfoEmpty + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .deepLinkInfo(let flags, let message, let entities): + if boxed { + buffer.appendInt32(1783556146) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeString(message, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(entities!.count)) + for item in entities! { + item.serialize(buffer, true) + }} + break + case .deepLinkInfoEmpty: + if boxed { + buffer.appendInt32(1722786150) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .deepLinkInfo(let flags, let message, let entities): + return ("deepLinkInfo", [("flags", String(describing: flags)), ("message", String(describing: message)), ("entities", String(describing: entities))]) + case .deepLinkInfoEmpty: + return ("deepLinkInfoEmpty", []) + } + } + + public static func parse_deepLinkInfo(_ reader: BufferReader) -> DeepLinkInfo? { + var _1: Int32? + _1 = reader.readInt32() + var _2: String? + _2 = parseString(reader) + var _3: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil + if _c1 && _c2 && _c3 { + return Api.help.DeepLinkInfo.deepLinkInfo(flags: _1!, message: _2!, entities: _3) + } + else { + return nil + } + } + public static func parse_deepLinkInfoEmpty(_ reader: BufferReader) -> DeepLinkInfo? { + return Api.help.DeepLinkInfo.deepLinkInfoEmpty + } + + } +} public extension Api.help { enum InviteText: TypeConstructorDescription { case inviteText(message: String) @@ -1170,259 +1350,3 @@ public extension Api.messages { } } -public extension Api.messages { - enum CheckedHistoryImportPeer: TypeConstructorDescription { - case checkedHistoryImportPeer(confirmText: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .checkedHistoryImportPeer(let confirmText): - if boxed { - buffer.appendInt32(-1571952873) - } - serializeString(confirmText, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .checkedHistoryImportPeer(let confirmText): - return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))]) - } - } - - public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!) - } - else { - return nil - } - } - - } -} -public extension Api.messages { - enum DhConfig: TypeConstructorDescription { - case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer) - case dhConfigNotModified(random: Buffer) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .dhConfig(let g, let p, let version, let random): - if boxed { - buffer.appendInt32(740433629) - } - serializeInt32(g, buffer: buffer, boxed: false) - serializeBytes(p, buffer: buffer, boxed: false) - serializeInt32(version, buffer: buffer, boxed: false) - serializeBytes(random, buffer: buffer, boxed: false) - break - case .dhConfigNotModified(let random): - if boxed { - buffer.appendInt32(-1058912715) - } - serializeBytes(random, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .dhConfig(let g, let p, let version, let random): - return ("dhConfig", [("g", String(describing: g)), ("p", String(describing: p)), ("version", String(describing: version)), ("random", String(describing: random))]) - case .dhConfigNotModified(let random): - return ("dhConfigNotModified", [("random", String(describing: random))]) - } - } - - public static func parse_dhConfig(_ reader: BufferReader) -> DhConfig? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Buffer? - _2 = parseBytes(reader) - var _3: Int32? - _3 = reader.readInt32() - var _4: Buffer? - _4 = parseBytes(reader) - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.messages.DhConfig.dhConfig(g: _1!, p: _2!, version: _3!, random: _4!) - } - else { - return nil - } - } - public static func parse_dhConfigNotModified(_ reader: BufferReader) -> DhConfig? { - var _1: Buffer? - _1 = parseBytes(reader) - let _c1 = _1 != nil - if _c1 { - return Api.messages.DhConfig.dhConfigNotModified(random: _1!) - } - else { - return nil - } - } - - } -} -public extension Api.messages { - enum Dialogs: TypeConstructorDescription { - case dialogs(dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) - case dialogsNotModified(count: Int32) - case dialogsSlice(count: Int32, dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .dialogs(let dialogs, let messages, let chats, let users): - if boxed { - buffer.appendInt32(364538944) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(dialogs.count)) - for item in dialogs { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(messages.count)) - for item in messages { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(users.count)) - for item in users { - item.serialize(buffer, true) - } - break - case .dialogsNotModified(let count): - if boxed { - buffer.appendInt32(-253500010) - } - serializeInt32(count, buffer: buffer, boxed: false) - break - case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): - if boxed { - buffer.appendInt32(1910543603) - } - serializeInt32(count, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(dialogs.count)) - for item in dialogs { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(messages.count)) - for item in messages { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - 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 .dialogs(let dialogs, let messages, let chats, let users): - return ("dialogs", [("dialogs", String(describing: dialogs)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) - case .dialogsNotModified(let count): - return ("dialogsNotModified", [("count", String(describing: count))]) - case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): - return ("dialogsSlice", [("count", String(describing: count)), ("dialogs", String(describing: dialogs)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) - } - } - - public static func parse_dialogs(_ reader: BufferReader) -> Dialogs? { - var _1: [Api.Dialog]? - if let _ = reader.readInt32() { - _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) - } - var _2: [Api.Message]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) - } - var _3: [Api.Chat]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _4: [Api.User]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - if _c1 && _c2 && _c3 && _c4 { - return Api.messages.Dialogs.dialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!) - } - else { - return nil - } - } - public static func parse_dialogsNotModified(_ reader: BufferReader) -> Dialogs? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.messages.Dialogs.dialogsNotModified(count: _1!) - } - else { - return nil - } - } - public static func parse_dialogsSlice(_ reader: BufferReader) -> Dialogs? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.Dialog]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) - } - var _3: [Api.Message]? - if let _ = reader.readInt32() { - _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) - } - var _4: [Api.Chat]? - if let _ = reader.readInt32() { - _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _5: [Api.User]? - if let _ = reader.readInt32() { - _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - 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.messages.Dialogs.dialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api24.swift b/submodules/TelegramApi/Sources/Api24.swift index afa638d158..b12751463a 100644 --- a/submodules/TelegramApi/Sources/Api24.swift +++ b/submodules/TelegramApi/Sources/Api24.swift @@ -1,3 +1,259 @@ +public extension Api.messages { + enum CheckedHistoryImportPeer: TypeConstructorDescription { + case checkedHistoryImportPeer(confirmText: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .checkedHistoryImportPeer(let confirmText): + if boxed { + buffer.appendInt32(-1571952873) + } + serializeString(confirmText, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .checkedHistoryImportPeer(let confirmText): + return ("checkedHistoryImportPeer", [("confirmText", String(describing: confirmText))]) + } + } + + public static func parse_checkedHistoryImportPeer(_ reader: BufferReader) -> CheckedHistoryImportPeer? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.messages.CheckedHistoryImportPeer.checkedHistoryImportPeer(confirmText: _1!) + } + else { + return nil + } + } + + } +} +public extension Api.messages { + enum DhConfig: TypeConstructorDescription { + case dhConfig(g: Int32, p: Buffer, version: Int32, random: Buffer) + case dhConfigNotModified(random: Buffer) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dhConfig(let g, let p, let version, let random): + if boxed { + buffer.appendInt32(740433629) + } + serializeInt32(g, buffer: buffer, boxed: false) + serializeBytes(p, buffer: buffer, boxed: false) + serializeInt32(version, buffer: buffer, boxed: false) + serializeBytes(random, buffer: buffer, boxed: false) + break + case .dhConfigNotModified(let random): + if boxed { + buffer.appendInt32(-1058912715) + } + serializeBytes(random, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .dhConfig(let g, let p, let version, let random): + return ("dhConfig", [("g", String(describing: g)), ("p", String(describing: p)), ("version", String(describing: version)), ("random", String(describing: random))]) + case .dhConfigNotModified(let random): + return ("dhConfigNotModified", [("random", String(describing: random))]) + } + } + + public static func parse_dhConfig(_ reader: BufferReader) -> DhConfig? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Buffer? + _2 = parseBytes(reader) + var _3: Int32? + _3 = reader.readInt32() + var _4: Buffer? + _4 = parseBytes(reader) + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.DhConfig.dhConfig(g: _1!, p: _2!, version: _3!, random: _4!) + } + else { + return nil + } + } + public static func parse_dhConfigNotModified(_ reader: BufferReader) -> DhConfig? { + var _1: Buffer? + _1 = parseBytes(reader) + let _c1 = _1 != nil + if _c1 { + return Api.messages.DhConfig.dhConfigNotModified(random: _1!) + } + else { + return nil + } + } + + } +} +public extension Api.messages { + enum Dialogs: TypeConstructorDescription { + case dialogs(dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + case dialogsNotModified(count: Int32) + case dialogsSlice(count: Int32, dialogs: [Api.Dialog], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .dialogs(let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(364538944) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + case .dialogsNotModified(let count): + if boxed { + buffer.appendInt32(-253500010) + } + serializeInt32(count, buffer: buffer, boxed: false) + break + case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): + if boxed { + buffer.appendInt32(1910543603) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(dialogs.count)) + for item in dialogs { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + 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 .dialogs(let dialogs, let messages, let chats, let users): + return ("dialogs", [("dialogs", String(describing: dialogs)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) + case .dialogsNotModified(let count): + return ("dialogsNotModified", [("count", String(describing: count))]) + case .dialogsSlice(let count, let dialogs, let messages, let chats, let users): + return ("dialogsSlice", [("count", String(describing: count)), ("dialogs", String(describing: dialogs)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) + } + } + + public static func parse_dialogs(_ reader: BufferReader) -> Dialogs? { + var _1: [Api.Dialog]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) + } + var _2: [Api.Message]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _3: [Api.Chat]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _4: [Api.User]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.messages.Dialogs.dialogs(dialogs: _1!, messages: _2!, chats: _3!, users: _4!) + } + else { + return nil + } + } + public static func parse_dialogsNotModified(_ reader: BufferReader) -> Dialogs? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.Dialogs.dialogsNotModified(count: _1!) + } + else { + return nil + } + } + public static func parse_dialogsSlice(_ reader: BufferReader) -> Dialogs? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.Dialog]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Dialog.self) + } + var _3: [Api.Message]? + if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _4: [Api.Chat]? + if let _ = reader.readInt32() { + _4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _5: [Api.User]? + if let _ = reader.readInt32() { + _5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + 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.messages.Dialogs.dialogsSlice(count: _1!, dialogs: _2!, messages: _3!, chats: _4!, users: _5!) + } + else { + return nil + } + } + + } +} public extension Api.messages { enum DiscussionMessage: TypeConstructorDescription { case discussionMessage(flags: Int32, messages: [Api.Message], maxId: Int32?, readInboxMaxId: Int32?, readOutboxMaxId: Int32?, unreadCount: Int32, chats: [Api.Chat], users: [Api.User]) @@ -1268,249 +1524,3 @@ public extension Api.messages { } } -public extension Api.messages { - enum SearchCounter: TypeConstructorDescription { - case searchCounter(flags: Int32, filter: Api.MessagesFilter, count: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .searchCounter(let flags, let filter, let count): - if boxed { - buffer.appendInt32(-398136321) - } - serializeInt32(flags, buffer: buffer, boxed: false) - filter.serialize(buffer, true) - serializeInt32(count, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .searchCounter(let flags, let filter, let count): - return ("searchCounter", [("flags", String(describing: flags)), ("filter", String(describing: filter)), ("count", String(describing: count))]) - } - } - - public static func parse_searchCounter(_ reader: BufferReader) -> SearchCounter? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.MessagesFilter? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.MessagesFilter - } - var _3: Int32? - _3 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.messages.SearchCounter.searchCounter(flags: _1!, filter: _2!, count: _3!) - } - else { - return nil - } - } - - } -} -public extension Api.messages { - enum SearchResultsCalendar: TypeConstructorDescription { - case searchResultsCalendar(flags: Int32, count: Int32, minDate: Int32, minMsgId: Int32, offsetIdOffset: Int32?, periods: [Api.SearchResultsCalendarPeriod], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users): - if boxed { - buffer.appendInt32(343859772) - } - serializeInt32(flags, buffer: buffer, boxed: false) - serializeInt32(count, buffer: buffer, boxed: false) - serializeInt32(minDate, buffer: buffer, boxed: false) - serializeInt32(minMsgId, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 1) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)} - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(periods.count)) - for item in periods { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(messages.count)) - for item in messages { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(chats.count)) - for item in chats { - item.serialize(buffer, true) - } - 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 .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users): - return ("searchResultsCalendar", [("flags", String(describing: flags)), ("count", String(describing: count)), ("minDate", String(describing: minDate)), ("minMsgId", String(describing: minMsgId)), ("offsetIdOffset", String(describing: offsetIdOffset)), ("periods", String(describing: periods)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) - } - } - - public static func parse_searchResultsCalendar(_ reader: BufferReader) -> SearchResultsCalendar? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: Int32? - _3 = reader.readInt32() - var _4: Int32? - _4 = reader.readInt32() - var _5: Int32? - if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } - var _6: [Api.SearchResultsCalendarPeriod]? - if let _ = reader.readInt32() { - _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsCalendarPeriod.self) - } - var _7: [Api.Message]? - if let _ = reader.readInt32() { - _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) - } - var _8: [Api.Chat]? - if let _ = reader.readInt32() { - _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) - } - var _9: [Api.User]? - if let _ = reader.readInt32() { - _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil - let _c6 = _6 != nil - let _c7 = _7 != nil - let _c8 = _8 != nil - let _c9 = _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.messages.SearchResultsCalendar.searchResultsCalendar(flags: _1!, count: _2!, minDate: _3!, minMsgId: _4!, offsetIdOffset: _5, periods: _6!, messages: _7!, chats: _8!, users: _9!) - } - else { - return nil - } - } - - } -} -public extension Api.messages { - enum SearchResultsPositions: TypeConstructorDescription { - case searchResultsPositions(count: Int32, positions: [Api.SearchResultsPosition]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .searchResultsPositions(let count, let positions): - if boxed { - buffer.appendInt32(1404185519) - } - serializeInt32(count, buffer: buffer, boxed: false) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(positions.count)) - for item in positions { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .searchResultsPositions(let count, let positions): - return ("searchResultsPositions", [("count", String(describing: count)), ("positions", String(describing: positions))]) - } - } - - public static func parse_searchResultsPositions(_ reader: BufferReader) -> SearchResultsPositions? { - var _1: Int32? - _1 = reader.readInt32() - var _2: [Api.SearchResultsPosition]? - if let _ = reader.readInt32() { - _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsPosition.self) - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.messages.SearchResultsPositions.searchResultsPositions(count: _1!, positions: _2!) - } - else { - return nil - } - } - - } -} -public extension Api.messages { - enum SentEncryptedMessage: TypeConstructorDescription { - case sentEncryptedFile(date: Int32, file: Api.EncryptedFile) - case sentEncryptedMessage(date: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .sentEncryptedFile(let date, let file): - if boxed { - buffer.appendInt32(-1802240206) - } - serializeInt32(date, buffer: buffer, boxed: false) - file.serialize(buffer, true) - break - case .sentEncryptedMessage(let date): - if boxed { - buffer.appendInt32(1443858741) - } - serializeInt32(date, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .sentEncryptedFile(let date, let file): - return ("sentEncryptedFile", [("date", String(describing: date)), ("file", String(describing: file))]) - case .sentEncryptedMessage(let date): - return ("sentEncryptedMessage", [("date", String(describing: date))]) - } - } - - public static func parse_sentEncryptedFile(_ reader: BufferReader) -> SentEncryptedMessage? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Api.EncryptedFile? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.EncryptedFile - } - let _c1 = _1 != nil - let _c2 = _2 != nil - if _c1 && _c2 { - return Api.messages.SentEncryptedMessage.sentEncryptedFile(date: _1!, file: _2!) - } - else { - return nil - } - } - public static func parse_sentEncryptedMessage(_ reader: BufferReader) -> SentEncryptedMessage? { - var _1: Int32? - _1 = reader.readInt32() - let _c1 = _1 != nil - if _c1 { - return Api.messages.SentEncryptedMessage.sentEncryptedMessage(date: _1!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api25.swift b/submodules/TelegramApi/Sources/Api25.swift index c51ea43fac..c0500fe797 100644 --- a/submodules/TelegramApi/Sources/Api25.swift +++ b/submodules/TelegramApi/Sources/Api25.swift @@ -1,3 +1,249 @@ +public extension Api.messages { + enum SearchCounter: TypeConstructorDescription { + case searchCounter(flags: Int32, filter: Api.MessagesFilter, count: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .searchCounter(let flags, let filter, let count): + if boxed { + buffer.appendInt32(-398136321) + } + serializeInt32(flags, buffer: buffer, boxed: false) + filter.serialize(buffer, true) + serializeInt32(count, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .searchCounter(let flags, let filter, let count): + return ("searchCounter", [("flags", String(describing: flags)), ("filter", String(describing: filter)), ("count", String(describing: count))]) + } + } + + public static func parse_searchCounter(_ reader: BufferReader) -> SearchCounter? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.MessagesFilter? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.MessagesFilter + } + var _3: Int32? + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.messages.SearchCounter.searchCounter(flags: _1!, filter: _2!, count: _3!) + } + else { + return nil + } + } + + } +} +public extension Api.messages { + enum SearchResultsCalendar: TypeConstructorDescription { + case searchResultsCalendar(flags: Int32, count: Int32, minDate: Int32, minMsgId: Int32, offsetIdOffset: Int32?, periods: [Api.SearchResultsCalendarPeriod], messages: [Api.Message], chats: [Api.Chat], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users): + if boxed { + buffer.appendInt32(343859772) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(count, buffer: buffer, boxed: false) + serializeInt32(minDate, buffer: buffer, boxed: false) + serializeInt32(minMsgId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 1) != 0 {serializeInt32(offsetIdOffset!, buffer: buffer, boxed: false)} + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(periods.count)) + for item in periods { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(messages.count)) + for item in messages { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(chats.count)) + for item in chats { + item.serialize(buffer, true) + } + 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 .searchResultsCalendar(let flags, let count, let minDate, let minMsgId, let offsetIdOffset, let periods, let messages, let chats, let users): + return ("searchResultsCalendar", [("flags", String(describing: flags)), ("count", String(describing: count)), ("minDate", String(describing: minDate)), ("minMsgId", String(describing: minMsgId)), ("offsetIdOffset", String(describing: offsetIdOffset)), ("periods", String(describing: periods)), ("messages", String(describing: messages)), ("chats", String(describing: chats)), ("users", String(describing: users))]) + } + } + + public static func parse_searchResultsCalendar(_ reader: BufferReader) -> SearchResultsCalendar? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + if Int(_1!) & Int(1 << 1) != 0 {_5 = reader.readInt32() } + var _6: [Api.SearchResultsCalendarPeriod]? + if let _ = reader.readInt32() { + _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsCalendarPeriod.self) + } + var _7: [Api.Message]? + if let _ = reader.readInt32() { + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Message.self) + } + var _8: [Api.Chat]? + if let _ = reader.readInt32() { + _8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self) + } + var _9: [Api.User]? + if let _ = reader.readInt32() { + _9 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = _7 != nil + let _c8 = _8 != nil + let _c9 = _9 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { + return Api.messages.SearchResultsCalendar.searchResultsCalendar(flags: _1!, count: _2!, minDate: _3!, minMsgId: _4!, offsetIdOffset: _5, periods: _6!, messages: _7!, chats: _8!, users: _9!) + } + else { + return nil + } + } + + } +} +public extension Api.messages { + enum SearchResultsPositions: TypeConstructorDescription { + case searchResultsPositions(count: Int32, positions: [Api.SearchResultsPosition]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .searchResultsPositions(let count, let positions): + if boxed { + buffer.appendInt32(1404185519) + } + serializeInt32(count, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(positions.count)) + for item in positions { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .searchResultsPositions(let count, let positions): + return ("searchResultsPositions", [("count", String(describing: count)), ("positions", String(describing: positions))]) + } + } + + public static func parse_searchResultsPositions(_ reader: BufferReader) -> SearchResultsPositions? { + var _1: Int32? + _1 = reader.readInt32() + var _2: [Api.SearchResultsPosition]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SearchResultsPosition.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.SearchResultsPositions.searchResultsPositions(count: _1!, positions: _2!) + } + else { + return nil + } + } + + } +} +public extension Api.messages { + enum SentEncryptedMessage: TypeConstructorDescription { + case sentEncryptedFile(date: Int32, file: Api.EncryptedFile) + case sentEncryptedMessage(date: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .sentEncryptedFile(let date, let file): + if boxed { + buffer.appendInt32(-1802240206) + } + serializeInt32(date, buffer: buffer, boxed: false) + file.serialize(buffer, true) + break + case .sentEncryptedMessage(let date): + if boxed { + buffer.appendInt32(1443858741) + } + serializeInt32(date, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .sentEncryptedFile(let date, let file): + return ("sentEncryptedFile", [("date", String(describing: date)), ("file", String(describing: file))]) + case .sentEncryptedMessage(let date): + return ("sentEncryptedMessage", [("date", String(describing: date))]) + } + } + + public static func parse_sentEncryptedFile(_ reader: BufferReader) -> SentEncryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Api.EncryptedFile? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.EncryptedFile + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.messages.SentEncryptedMessage.sentEncryptedFile(date: _1!, file: _2!) + } + else { + return nil + } + } + public static func parse_sentEncryptedMessage(_ reader: BufferReader) -> SentEncryptedMessage? { + var _1: Int32? + _1 = reader.readInt32() + let _c1 = _1 != nil + if _c1 { + return Api.messages.SentEncryptedMessage.sentEncryptedMessage(date: _1!) + } + else { + return nil + } + } + + } +} public extension Api.messages { enum SponsoredMessages: TypeConstructorDescription { case sponsoredMessages(messages: [Api.SponsoredMessage], chats: [Api.Chat], users: [Api.User]) @@ -1260,489 +1506,3 @@ public extension Api.photos { } } -public extension Api.stats { - enum BroadcastStats: TypeConstructorDescription { - case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): - if boxed { - buffer.appendInt32(-1107852396) - } - period.serialize(buffer, true) - followers.serialize(buffer, true) - viewsPerPost.serialize(buffer, true) - sharesPerPost.serialize(buffer, true) - enabledNotifications.serialize(buffer, true) - growthGraph.serialize(buffer, true) - followersGraph.serialize(buffer, true) - muteGraph.serialize(buffer, true) - topHoursGraph.serialize(buffer, true) - interactionsGraph.serialize(buffer, true) - ivInteractionsGraph.serialize(buffer, true) - viewsBySourceGraph.serialize(buffer, true) - newFollowersBySourceGraph.serialize(buffer, true) - languagesGraph.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(recentMessageInteractions.count)) - for item in recentMessageInteractions { - item.serialize(buffer, true) - } - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): - return ("broadcastStats", [("period", String(describing: period)), ("followers", String(describing: followers)), ("viewsPerPost", String(describing: viewsPerPost)), ("sharesPerPost", String(describing: sharesPerPost)), ("enabledNotifications", String(describing: enabledNotifications)), ("growthGraph", String(describing: growthGraph)), ("followersGraph", String(describing: followersGraph)), ("muteGraph", String(describing: muteGraph)), ("topHoursGraph", String(describing: topHoursGraph)), ("interactionsGraph", String(describing: interactionsGraph)), ("ivInteractionsGraph", String(describing: ivInteractionsGraph)), ("viewsBySourceGraph", String(describing: viewsBySourceGraph)), ("newFollowersBySourceGraph", String(describing: newFollowersBySourceGraph)), ("languagesGraph", String(describing: languagesGraph)), ("recentMessageInteractions", String(describing: recentMessageInteractions))]) - } - } - - public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { - var _1: Api.StatsDateRangeDays? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays - } - var _2: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _3: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _5: Api.StatsPercentValue? - if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue - } - var _6: Api.StatsGraph? - if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _7: Api.StatsGraph? - if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _8: Api.StatsGraph? - if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _9: Api.StatsGraph? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _10: Api.StatsGraph? - if let signature = reader.readInt32() { - _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _11: Api.StatsGraph? - if let signature = reader.readInt32() { - _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _12: Api.StatsGraph? - if let signature = reader.readInt32() { - _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _13: Api.StatsGraph? - if let signature = reader.readInt32() { - _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _14: Api.StatsGraph? - if let signature = reader.readInt32() { - _14 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _15: [Api.MessageInteractionCounters]? - if let _ = reader.readInt32() { - _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageInteractionCounters.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 = _8 != nil - let _c9 = _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - let _c12 = _12 != nil - let _c13 = _13 != nil - let _c14 = _14 != nil - let _c15 = _15 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 { - return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, growthGraph: _6!, followersGraph: _7!, muteGraph: _8!, topHoursGraph: _9!, interactionsGraph: _10!, ivInteractionsGraph: _11!, viewsBySourceGraph: _12!, newFollowersBySourceGraph: _13!, languagesGraph: _14!, recentMessageInteractions: _15!) - } - else { - return nil - } - } - - } -} -public extension Api.stats { - enum MegagroupStats: TypeConstructorDescription { - case megagroupStats(period: Api.StatsDateRangeDays, members: Api.StatsAbsValueAndPrev, messages: Api.StatsAbsValueAndPrev, viewers: Api.StatsAbsValueAndPrev, posters: Api.StatsAbsValueAndPrev, growthGraph: Api.StatsGraph, membersGraph: Api.StatsGraph, newMembersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, messagesGraph: Api.StatsGraph, actionsGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, weekdaysGraph: Api.StatsGraph, topPosters: [Api.StatsGroupTopPoster], topAdmins: [Api.StatsGroupTopAdmin], topInviters: [Api.StatsGroupTopInviter], users: [Api.User]) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): - if boxed { - buffer.appendInt32(-276825834) - } - period.serialize(buffer, true) - members.serialize(buffer, true) - messages.serialize(buffer, true) - viewers.serialize(buffer, true) - posters.serialize(buffer, true) - growthGraph.serialize(buffer, true) - membersGraph.serialize(buffer, true) - newMembersBySourceGraph.serialize(buffer, true) - languagesGraph.serialize(buffer, true) - messagesGraph.serialize(buffer, true) - actionsGraph.serialize(buffer, true) - topHoursGraph.serialize(buffer, true) - weekdaysGraph.serialize(buffer, true) - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topPosters.count)) - for item in topPosters { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topAdmins.count)) - for item in topAdmins { - item.serialize(buffer, true) - } - buffer.appendInt32(481674261) - buffer.appendInt32(Int32(topInviters.count)) - for item in topInviters { - item.serialize(buffer, true) - } - 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 .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): - return ("megagroupStats", [("period", String(describing: period)), ("members", String(describing: members)), ("messages", String(describing: messages)), ("viewers", String(describing: viewers)), ("posters", String(describing: posters)), ("growthGraph", String(describing: growthGraph)), ("membersGraph", String(describing: membersGraph)), ("newMembersBySourceGraph", String(describing: newMembersBySourceGraph)), ("languagesGraph", String(describing: languagesGraph)), ("messagesGraph", String(describing: messagesGraph)), ("actionsGraph", String(describing: actionsGraph)), ("topHoursGraph", String(describing: topHoursGraph)), ("weekdaysGraph", String(describing: weekdaysGraph)), ("topPosters", String(describing: topPosters)), ("topAdmins", String(describing: topAdmins)), ("topInviters", String(describing: topInviters)), ("users", String(describing: users))]) - } - } - - public static func parse_megagroupStats(_ reader: BufferReader) -> MegagroupStats? { - var _1: Api.StatsDateRangeDays? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays - } - var _2: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _3: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _4: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _5: Api.StatsAbsValueAndPrev? - if let signature = reader.readInt32() { - _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev - } - var _6: Api.StatsGraph? - if let signature = reader.readInt32() { - _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _7: Api.StatsGraph? - if let signature = reader.readInt32() { - _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _8: Api.StatsGraph? - if let signature = reader.readInt32() { - _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _9: Api.StatsGraph? - if let signature = reader.readInt32() { - _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _10: Api.StatsGraph? - if let signature = reader.readInt32() { - _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _11: Api.StatsGraph? - if let signature = reader.readInt32() { - _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _12: Api.StatsGraph? - if let signature = reader.readInt32() { - _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _13: Api.StatsGraph? - if let signature = reader.readInt32() { - _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - var _14: [Api.StatsGroupTopPoster]? - if let _ = reader.readInt32() { - _14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopPoster.self) - } - var _15: [Api.StatsGroupTopAdmin]? - if let _ = reader.readInt32() { - _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopAdmin.self) - } - var _16: [Api.StatsGroupTopInviter]? - if let _ = reader.readInt32() { - _16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopInviter.self) - } - var _17: [Api.User]? - if let _ = reader.readInt32() { - _17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.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 = _8 != nil - let _c9 = _9 != nil - let _c10 = _10 != nil - let _c11 = _11 != nil - let _c12 = _12 != nil - let _c13 = _13 != nil - let _c14 = _14 != nil - let _c15 = _15 != nil - let _c16 = _16 != nil - let _c17 = _17 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 { - return Api.stats.MegagroupStats.megagroupStats(period: _1!, members: _2!, messages: _3!, viewers: _4!, posters: _5!, growthGraph: _6!, membersGraph: _7!, newMembersBySourceGraph: _8!, languagesGraph: _9!, messagesGraph: _10!, actionsGraph: _11!, topHoursGraph: _12!, weekdaysGraph: _13!, topPosters: _14!, topAdmins: _15!, topInviters: _16!, users: _17!) - } - else { - return nil - } - } - - } -} -public extension Api.stats { - enum MessageStats: TypeConstructorDescription { - case messageStats(viewsGraph: Api.StatsGraph) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .messageStats(let viewsGraph): - if boxed { - buffer.appendInt32(-1986399595) - } - viewsGraph.serialize(buffer, true) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .messageStats(let viewsGraph): - return ("messageStats", [("viewsGraph", String(describing: viewsGraph))]) - } - } - - public static func parse_messageStats(_ reader: BufferReader) -> MessageStats? { - var _1: Api.StatsGraph? - if let signature = reader.readInt32() { - _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph - } - let _c1 = _1 != nil - if _c1 { - return Api.stats.MessageStats.messageStats(viewsGraph: _1!) - } - else { - return nil - } - } - - } -} -public extension Api.stickers { - enum SuggestedShortName: TypeConstructorDescription { - case suggestedShortName(shortName: String) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .suggestedShortName(let shortName): - if boxed { - buffer.appendInt32(-2046910401) - } - serializeString(shortName, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .suggestedShortName(let shortName): - return ("suggestedShortName", [("shortName", String(describing: shortName))]) - } - } - - public static func parse_suggestedShortName(_ reader: BufferReader) -> SuggestedShortName? { - var _1: String? - _1 = parseString(reader) - let _c1 = _1 != nil - if _c1 { - return Api.stickers.SuggestedShortName.suggestedShortName(shortName: _1!) - } - else { - return nil - } - } - - } -} -public extension Api.storage { - enum FileType: TypeConstructorDescription { - case fileGif - case fileJpeg - case fileMov - case fileMp3 - case fileMp4 - case filePartial - case filePdf - case filePng - case fileUnknown - case fileWebp - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .fileGif: - if boxed { - buffer.appendInt32(-891180321) - } - - break - case .fileJpeg: - if boxed { - buffer.appendInt32(8322574) - } - - break - case .fileMov: - if boxed { - buffer.appendInt32(1258941372) - } - - break - case .fileMp3: - if boxed { - buffer.appendInt32(1384777335) - } - - break - case .fileMp4: - if boxed { - buffer.appendInt32(-1278304028) - } - - break - case .filePartial: - if boxed { - buffer.appendInt32(1086091090) - } - - break - case .filePdf: - if boxed { - buffer.appendInt32(-1373745011) - } - - break - case .filePng: - if boxed { - buffer.appendInt32(172975040) - } - - break - case .fileUnknown: - if boxed { - buffer.appendInt32(-1432995067) - } - - break - case .fileWebp: - if boxed { - buffer.appendInt32(276907596) - } - - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .fileGif: - return ("fileGif", []) - case .fileJpeg: - return ("fileJpeg", []) - case .fileMov: - return ("fileMov", []) - case .fileMp3: - return ("fileMp3", []) - case .fileMp4: - return ("fileMp4", []) - case .filePartial: - return ("filePartial", []) - case .filePdf: - return ("filePdf", []) - case .filePng: - return ("filePng", []) - case .fileUnknown: - return ("fileUnknown", []) - case .fileWebp: - return ("fileWebp", []) - } - } - - public static func parse_fileGif(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileGif - } - public static func parse_fileJpeg(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileJpeg - } - public static func parse_fileMov(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileMov - } - public static func parse_fileMp3(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileMp3 - } - public static func parse_fileMp4(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileMp4 - } - public static func parse_filePartial(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.filePartial - } - public static func parse_filePdf(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.filePdf - } - public static func parse_filePng(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.filePng - } - public static func parse_fileUnknown(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileUnknown - } - public static func parse_fileWebp(_ reader: BufferReader) -> FileType? { - return Api.storage.FileType.fileWebp - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api26.swift b/submodules/TelegramApi/Sources/Api26.swift index 05065fa598..ad5ef9bca8 100644 --- a/submodules/TelegramApi/Sources/Api26.swift +++ b/submodules/TelegramApi/Sources/Api26.swift @@ -1,3 +1,489 @@ +public extension Api.stats { + enum BroadcastStats: TypeConstructorDescription { + case broadcastStats(period: Api.StatsDateRangeDays, followers: Api.StatsAbsValueAndPrev, viewsPerPost: Api.StatsAbsValueAndPrev, sharesPerPost: Api.StatsAbsValueAndPrev, enabledNotifications: Api.StatsPercentValue, growthGraph: Api.StatsGraph, followersGraph: Api.StatsGraph, muteGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, interactionsGraph: Api.StatsGraph, ivInteractionsGraph: Api.StatsGraph, viewsBySourceGraph: Api.StatsGraph, newFollowersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, recentMessageInteractions: [Api.MessageInteractionCounters]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): + if boxed { + buffer.appendInt32(-1107852396) + } + period.serialize(buffer, true) + followers.serialize(buffer, true) + viewsPerPost.serialize(buffer, true) + sharesPerPost.serialize(buffer, true) + enabledNotifications.serialize(buffer, true) + growthGraph.serialize(buffer, true) + followersGraph.serialize(buffer, true) + muteGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + interactionsGraph.serialize(buffer, true) + ivInteractionsGraph.serialize(buffer, true) + viewsBySourceGraph.serialize(buffer, true) + newFollowersBySourceGraph.serialize(buffer, true) + languagesGraph.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(recentMessageInteractions.count)) + for item in recentMessageInteractions { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .broadcastStats(let period, let followers, let viewsPerPost, let sharesPerPost, let enabledNotifications, let growthGraph, let followersGraph, let muteGraph, let topHoursGraph, let interactionsGraph, let ivInteractionsGraph, let viewsBySourceGraph, let newFollowersBySourceGraph, let languagesGraph, let recentMessageInteractions): + return ("broadcastStats", [("period", String(describing: period)), ("followers", String(describing: followers)), ("viewsPerPost", String(describing: viewsPerPost)), ("sharesPerPost", String(describing: sharesPerPost)), ("enabledNotifications", String(describing: enabledNotifications)), ("growthGraph", String(describing: growthGraph)), ("followersGraph", String(describing: followersGraph)), ("muteGraph", String(describing: muteGraph)), ("topHoursGraph", String(describing: topHoursGraph)), ("interactionsGraph", String(describing: interactionsGraph)), ("ivInteractionsGraph", String(describing: ivInteractionsGraph)), ("viewsBySourceGraph", String(describing: viewsBySourceGraph)), ("newFollowersBySourceGraph", String(describing: newFollowersBySourceGraph)), ("languagesGraph", String(describing: languagesGraph)), ("recentMessageInteractions", String(describing: recentMessageInteractions))]) + } + } + + public static func parse_broadcastStats(_ reader: BufferReader) -> BroadcastStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsPercentValue? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsPercentValue + } + var _6: Api.StatsGraph? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _7: Api.StatsGraph? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _8: Api.StatsGraph? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _14: Api.StatsGraph? + if let signature = reader.readInt32() { + _14 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _15: [Api.MessageInteractionCounters]? + if let _ = reader.readInt32() { + _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageInteractionCounters.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 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 { + return Api.stats.BroadcastStats.broadcastStats(period: _1!, followers: _2!, viewsPerPost: _3!, sharesPerPost: _4!, enabledNotifications: _5!, growthGraph: _6!, followersGraph: _7!, muteGraph: _8!, topHoursGraph: _9!, interactionsGraph: _10!, ivInteractionsGraph: _11!, viewsBySourceGraph: _12!, newFollowersBySourceGraph: _13!, languagesGraph: _14!, recentMessageInteractions: _15!) + } + else { + return nil + } + } + + } +} +public extension Api.stats { + enum MegagroupStats: TypeConstructorDescription { + case megagroupStats(period: Api.StatsDateRangeDays, members: Api.StatsAbsValueAndPrev, messages: Api.StatsAbsValueAndPrev, viewers: Api.StatsAbsValueAndPrev, posters: Api.StatsAbsValueAndPrev, growthGraph: Api.StatsGraph, membersGraph: Api.StatsGraph, newMembersBySourceGraph: Api.StatsGraph, languagesGraph: Api.StatsGraph, messagesGraph: Api.StatsGraph, actionsGraph: Api.StatsGraph, topHoursGraph: Api.StatsGraph, weekdaysGraph: Api.StatsGraph, topPosters: [Api.StatsGroupTopPoster], topAdmins: [Api.StatsGroupTopAdmin], topInviters: [Api.StatsGroupTopInviter], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): + if boxed { + buffer.appendInt32(-276825834) + } + period.serialize(buffer, true) + members.serialize(buffer, true) + messages.serialize(buffer, true) + viewers.serialize(buffer, true) + posters.serialize(buffer, true) + growthGraph.serialize(buffer, true) + membersGraph.serialize(buffer, true) + newMembersBySourceGraph.serialize(buffer, true) + languagesGraph.serialize(buffer, true) + messagesGraph.serialize(buffer, true) + actionsGraph.serialize(buffer, true) + topHoursGraph.serialize(buffer, true) + weekdaysGraph.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topPosters.count)) + for item in topPosters { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topAdmins.count)) + for item in topAdmins { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(topInviters.count)) + for item in topInviters { + item.serialize(buffer, true) + } + 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 .megagroupStats(let period, let members, let messages, let viewers, let posters, let growthGraph, let membersGraph, let newMembersBySourceGraph, let languagesGraph, let messagesGraph, let actionsGraph, let topHoursGraph, let weekdaysGraph, let topPosters, let topAdmins, let topInviters, let users): + return ("megagroupStats", [("period", String(describing: period)), ("members", String(describing: members)), ("messages", String(describing: messages)), ("viewers", String(describing: viewers)), ("posters", String(describing: posters)), ("growthGraph", String(describing: growthGraph)), ("membersGraph", String(describing: membersGraph)), ("newMembersBySourceGraph", String(describing: newMembersBySourceGraph)), ("languagesGraph", String(describing: languagesGraph)), ("messagesGraph", String(describing: messagesGraph)), ("actionsGraph", String(describing: actionsGraph)), ("topHoursGraph", String(describing: topHoursGraph)), ("weekdaysGraph", String(describing: weekdaysGraph)), ("topPosters", String(describing: topPosters)), ("topAdmins", String(describing: topAdmins)), ("topInviters", String(describing: topInviters)), ("users", String(describing: users))]) + } + } + + public static func parse_megagroupStats(_ reader: BufferReader) -> MegagroupStats? { + var _1: Api.StatsDateRangeDays? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsDateRangeDays + } + var _2: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _2 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _3: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _3 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _4: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _5: Api.StatsAbsValueAndPrev? + if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.StatsAbsValueAndPrev + } + var _6: Api.StatsGraph? + if let signature = reader.readInt32() { + _6 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _7: Api.StatsGraph? + if let signature = reader.readInt32() { + _7 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _8: Api.StatsGraph? + if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _9: Api.StatsGraph? + if let signature = reader.readInt32() { + _9 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _10: Api.StatsGraph? + if let signature = reader.readInt32() { + _10 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _11: Api.StatsGraph? + if let signature = reader.readInt32() { + _11 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _12: Api.StatsGraph? + if let signature = reader.readInt32() { + _12 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _13: Api.StatsGraph? + if let signature = reader.readInt32() { + _13 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + var _14: [Api.StatsGroupTopPoster]? + if let _ = reader.readInt32() { + _14 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopPoster.self) + } + var _15: [Api.StatsGroupTopAdmin]? + if let _ = reader.readInt32() { + _15 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopAdmin.self) + } + var _16: [Api.StatsGroupTopInviter]? + if let _ = reader.readInt32() { + _16 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StatsGroupTopInviter.self) + } + var _17: [Api.User]? + if let _ = reader.readInt32() { + _17 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.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 = _8 != nil + let _c9 = _9 != nil + let _c10 = _10 != nil + let _c11 = _11 != nil + let _c12 = _12 != nil + let _c13 = _13 != nil + let _c14 = _14 != nil + let _c15 = _15 != nil + let _c16 = _16 != nil + let _c17 = _17 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 && _c15 && _c16 && _c17 { + return Api.stats.MegagroupStats.megagroupStats(period: _1!, members: _2!, messages: _3!, viewers: _4!, posters: _5!, growthGraph: _6!, membersGraph: _7!, newMembersBySourceGraph: _8!, languagesGraph: _9!, messagesGraph: _10!, actionsGraph: _11!, topHoursGraph: _12!, weekdaysGraph: _13!, topPosters: _14!, topAdmins: _15!, topInviters: _16!, users: _17!) + } + else { + return nil + } + } + + } +} +public extension Api.stats { + enum MessageStats: TypeConstructorDescription { + case messageStats(viewsGraph: Api.StatsGraph) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .messageStats(let viewsGraph): + if boxed { + buffer.appendInt32(-1986399595) + } + viewsGraph.serialize(buffer, true) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .messageStats(let viewsGraph): + return ("messageStats", [("viewsGraph", String(describing: viewsGraph))]) + } + } + + public static func parse_messageStats(_ reader: BufferReader) -> MessageStats? { + var _1: Api.StatsGraph? + if let signature = reader.readInt32() { + _1 = Api.parse(reader, signature: signature) as? Api.StatsGraph + } + let _c1 = _1 != nil + if _c1 { + return Api.stats.MessageStats.messageStats(viewsGraph: _1!) + } + else { + return nil + } + } + + } +} +public extension Api.stickers { + enum SuggestedShortName: TypeConstructorDescription { + case suggestedShortName(shortName: String) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .suggestedShortName(let shortName): + if boxed { + buffer.appendInt32(-2046910401) + } + serializeString(shortName, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .suggestedShortName(let shortName): + return ("suggestedShortName", [("shortName", String(describing: shortName))]) + } + } + + public static func parse_suggestedShortName(_ reader: BufferReader) -> SuggestedShortName? { + var _1: String? + _1 = parseString(reader) + let _c1 = _1 != nil + if _c1 { + return Api.stickers.SuggestedShortName.suggestedShortName(shortName: _1!) + } + else { + return nil + } + } + + } +} +public extension Api.storage { + enum FileType: TypeConstructorDescription { + case fileGif + case fileJpeg + case fileMov + case fileMp3 + case fileMp4 + case filePartial + case filePdf + case filePng + case fileUnknown + case fileWebp + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .fileGif: + if boxed { + buffer.appendInt32(-891180321) + } + + break + case .fileJpeg: + if boxed { + buffer.appendInt32(8322574) + } + + break + case .fileMov: + if boxed { + buffer.appendInt32(1258941372) + } + + break + case .fileMp3: + if boxed { + buffer.appendInt32(1384777335) + } + + break + case .fileMp4: + if boxed { + buffer.appendInt32(-1278304028) + } + + break + case .filePartial: + if boxed { + buffer.appendInt32(1086091090) + } + + break + case .filePdf: + if boxed { + buffer.appendInt32(-1373745011) + } + + break + case .filePng: + if boxed { + buffer.appendInt32(172975040) + } + + break + case .fileUnknown: + if boxed { + buffer.appendInt32(-1432995067) + } + + break + case .fileWebp: + if boxed { + buffer.appendInt32(276907596) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .fileGif: + return ("fileGif", []) + case .fileJpeg: + return ("fileJpeg", []) + case .fileMov: + return ("fileMov", []) + case .fileMp3: + return ("fileMp3", []) + case .fileMp4: + return ("fileMp4", []) + case .filePartial: + return ("filePartial", []) + case .filePdf: + return ("filePdf", []) + case .filePng: + return ("filePng", []) + case .fileUnknown: + return ("fileUnknown", []) + case .fileWebp: + return ("fileWebp", []) + } + } + + public static func parse_fileGif(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileGif + } + public static func parse_fileJpeg(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileJpeg + } + public static func parse_fileMov(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMov + } + public static func parse_fileMp3(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMp3 + } + public static func parse_fileMp4(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileMp4 + } + public static func parse_filePartial(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePartial + } + public static func parse_filePdf(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePdf + } + public static func parse_filePng(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.filePng + } + public static func parse_fileUnknown(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileUnknown + } + public static func parse_fileWebp(_ reader: BufferReader) -> FileType? { + return Api.storage.FileType.fileWebp + } + + } +} public extension Api.updates { enum ChannelDifference: TypeConstructorDescription { case channelDifference(flags: Int32, pts: Int32, timeout: Int32?, newMessages: [Api.Message], otherUpdates: [Api.Update], chats: [Api.Chat], users: [Api.User]) diff --git a/submodules/TelegramApi/Sources/Api27.swift b/submodules/TelegramApi/Sources/Api27.swift index 2179dfc8d1..d467ba00b0 100644 --- a/submodules/TelegramApi/Sources/Api27.swift +++ b/submodules/TelegramApi/Sources/Api27.swift @@ -436,6 +436,21 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func getSavedRingtones(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-510647672) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getSavedRingtones", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.SavedRingtones? in + let reader = BufferReader(buffer) + var result: Api.account.SavedRingtones? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.SavedRingtones + } + return result + }) + } +} public extension Api.functions.account { static func getSecureValue(types: [Api.SecureValueType]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Api.SecureValue]>) { let buffer = Buffer() @@ -779,6 +794,22 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func saveRingtone(id: Api.InputDocument, unsave: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-369618141) + id.serialize(buffer, true) + unsave.serialize(buffer, true) + return (FunctionDescription(name: "account.saveRingtone", parameters: [("id", String(describing: id)), ("unsave", String(describing: unsave))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.account { static func saveSecureValue(value: Api.InputSecureValue, secureSecretId: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -1127,6 +1158,23 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func uploadRingtone(file: Api.InputFile, fileName: String, mimeType: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2095414366) + file.serialize(buffer, true) + serializeString(fileName, buffer: buffer, boxed: false) + serializeString(mimeType, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.uploadRingtone", parameters: [("file", String(describing: file)), ("fileName", String(describing: fileName)), ("mimeType", String(describing: mimeType))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Document? in + let reader = BufferReader(buffer) + var result: Api.Document? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Document + } + return result + }) + } +} public extension Api.functions.account { static func uploadTheme(flags: Int32, file: Api.InputFile, thumb: Api.InputFile?, fileName: String, mimeType: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramApi/Sources/Api8.swift b/submodules/TelegramApi/Sources/Api8.swift index 6610fc2009..6fd500f79e 100644 --- a/submodules/TelegramApi/Sources/Api8.swift +++ b/submodules/TelegramApi/Sources/Api8.swift @@ -444,19 +444,19 @@ public extension Api { } public extension Api { enum InputPeerNotifySettings: TypeConstructorDescription { - case inputPeerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: String?) + case inputPeerNotifySettings(flags: Int32, showPreviews: Api.Bool?, silent: Api.Bool?, muteUntil: Int32?, sound: Api.NotificationSound?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { case .inputPeerNotifySettings(let flags, let showPreviews, let silent, let muteUntil, let sound): if boxed { - buffer.appendInt32(-1673717362) + buffer.appendInt32(-551616469) } serializeInt32(flags, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 0) != 0 {showPreviews!.serialize(buffer, true)} if Int(flags) & Int(1 << 1) != 0 {silent!.serialize(buffer, true)} if Int(flags) & Int(1 << 2) != 0 {serializeInt32(muteUntil!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 3) != 0 {serializeString(sound!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {sound!.serialize(buffer, true)} break } } @@ -481,8 +481,10 @@ public extension Api { } } var _4: Int32? if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } - var _5: String? - if Int(_1!) & Int(1 << 3) != 0 {_5 = parseString(reader) } + var _5: Api.NotificationSound? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.NotificationSound + } } let _c1 = _1 != nil let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil diff --git a/submodules/TelegramAudio/Sources/ManagedAudioSession.swift b/submodules/TelegramAudio/Sources/ManagedAudioSession.swift index b6dfdf05f6..2b3a8c16a3 100644 --- a/submodules/TelegramAudio/Sources/ManagedAudioSession.swift +++ b/submodules/TelegramAudio/Sources/ManagedAudioSession.swift @@ -207,6 +207,8 @@ public final class ManagedAudioSession { private let isActiveSubscribers = Bag<(Bool) -> Void>() private let isPlaybackActiveSubscribers = Bag<(Bool) -> Void>() + private var callKitAudioSessionIsActive: Bool = false + public init() { self.queue = Queue() @@ -899,18 +901,18 @@ public final class ManagedAudioSession { } public func callKitActivatedAudioSession() { - /*self.queue.async { - managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession") + self.queue.async { + managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession") self.callKitAudioSessionIsActive = true self.updateHolders() - }*/ + } } public func callKitDeactivatedAudioSession() { - /*self.queue.async { - managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession") + self.queue.async { + managedAudioSessionLog("ManagedAudioSession callKitDeactivatedAudioSession") self.callKitAudioSessionIsActive = false self.updateHolders() - }*/ + } } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 8c6be115ee..46d2a1f351 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1572,7 +1572,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController }).start() } - strongSelf.presentUndoOverlay(content: .info(text: strongSelf.presentationData.strings.VoiceChat_EditBioSuccess), action: { _ in return false }) + strongSelf.presentUndoOverlay(content: .info(title: nil, text: strongSelf.presentationData.strings.VoiceChat_EditBioSuccess), action: { _ in return false }) } }) self?.controller?.present(controller, in: .window(.root)) @@ -1593,7 +1593,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController if let strongSelf = self, let (firstName, lastName) = firstAndLastName { let _ = context.engine.accountData.updateAccountPeerName(firstName: firstName, lastName: lastName).start() - strongSelf.presentUndoOverlay(content: .info(text: strongSelf.presentationData.strings.VoiceChat_EditNameSuccess), action: { _ in return false }) + strongSelf.presentUndoOverlay(content: .info(title: nil, text: strongSelf.presentationData.strings.VoiceChat_EditNameSuccess), action: { _ in return false }) } }) self?.controller?.present(controller, in: .window(.root)) diff --git a/submodules/TelegramCore/Sources/Account/Account.swift b/submodules/TelegramCore/Sources/Account/Account.swift index 98c0c1f47b..2ad71c35b0 100644 --- a/submodules/TelegramCore/Sources/Account/Account.swift +++ b/submodules/TelegramCore/Sources/Account/Account.swift @@ -1092,6 +1092,7 @@ public class Account { self.managedOperationsDisposable.add(managedApplyPendingScheduledMessagesActions(postbox: self.postbox, network: self.network, stateManager: self.stateManager).start()) self.managedOperationsDisposable.add(managedSynchronizeAvailableReactions(postbox: self.postbox, network: self.network).start()) self.managedOperationsDisposable.add(managedSynchronizeAttachMenuBots(postbox: self.postbox, network: self.network).start()) + self.managedOperationsDisposable.add(managedSynchronizeNotificationSoundList(postbox: self.postbox, network: self.network).start()) if !supplementary { self.managedOperationsDisposable.add(managedChatListFilters(postbox: self.postbox, network: self.network, accountPeerId: self.peerId).start()) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift index c4f35eb3ed..d4f31dea62 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramPeerNotificationSettings.swift @@ -6,76 +6,91 @@ import TelegramApi extension TelegramPeerNotificationSettings { convenience init(apiSettings: Api.PeerNotifySettings) { switch apiSettings { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): - let muteState: PeerMuteState - if let muteUntil = muteUntil { - if muteUntil == 0 { - muteState = .unmuted - } else { - muteState = .muted(until: muteUntil) - } + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound): + let sound: Api.NotificationSound? + #if os(iOS) + sound = iosSound + #elseif os(macOS) + sound = desktopSound + #endif + + let muteState: PeerMuteState + if let muteUntil = muteUntil { + if muteUntil == 0 { + muteState = .unmuted } else { - muteState = .default + muteState = .muted(until: muteUntil) } - let displayPreviews: PeerNotificationDisplayPreviews - if let showPreviews = showPreviews { - if case .boolTrue = showPreviews { - displayPreviews = .show - } else { - displayPreviews = .hide - } + } else { + muteState = .default + } + let displayPreviews: PeerNotificationDisplayPreviews + if let showPreviews = showPreviews { + if case .boolTrue = showPreviews { + displayPreviews = .show } else { - displayPreviews = .default + displayPreviews = .hide } - self.init(muteState: muteState, messageSound: PeerMessageSound(apiSound: sound), displayPreviews: displayPreviews) + } else { + displayPreviews = .default + } + self.init(muteState: muteState, messageSound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault), displayPreviews: displayPreviews) } } } extension PeerMessageSound { - init(apiSound: String?) { - guard let apiSound = apiSound else { + init(apiSound: Api.NotificationSound) { + switch apiSound { + case .notificationSoundDefault: self = .default - return - } - var rawApiSound = apiSound - if let index = rawApiSound.firstIndex(of: ".") { - rawApiSound = String(rawApiSound[..= 100 && soundId <= 111 { - parsedSound = .bundledModern(id: soundId - 100) - } else if soundId >= 2 && soundId <= 9 { - parsedSound = .bundledClassic(id: soundId - 2) + let parsedSound: PeerMessageSound + if rawApiSound == "default" { + parsedSound = .default + } else if rawApiSound == "" || rawApiSound == "0" { + parsedSound = .none } else { - parsedSound = .bundledModern(id: 0) + let soundId: Int32 + if let id = Int32(rawApiSound) { + soundId = id + } else { + soundId = 100 + } + if soundId >= 100 && soundId <= 111 { + parsedSound = .bundledModern(id: soundId - 100) + } else if soundId >= 2 && soundId <= 9 { + parsedSound = .bundledClassic(id: soundId - 2) + } else { + parsedSound = .bundledModern(id: 0) + } } + self = parsedSound + case let .notificationSoundRingtone(id): + self = .cloud(fileId: id) } - self = parsedSound } - var apiSound: String? { + var apiSound: Api.NotificationSound { switch self { - case .none: - return "" - case .default: - return nil - case let .bundledModern(id): - return "\(id + 100)" - case let .bundledClassic(id): - return "\(id + 2)" + case .none: + return .notificationSoundNone + case .default: + return .notificationSoundDefault + case let .bundledModern(id): + let string = "\(id + 100)" + return .notificationSoundLocal(title: string, data: string) + case let .bundledClassic(id): + let string = "\(id + 2)" + return .notificationSoundLocal(title: string, data: string) + case let .cloud(fileId): + return .notificationSoundRingtone(id: fileId) } } } diff --git a/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift index 538815b37b..20c835757d 100644 --- a/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/Settings/GlobalNotificationSettings.swift @@ -6,14 +6,20 @@ import TelegramApi extension MessageNotificationSettings { init(apiSettings: Api.PeerNotifySettings) { switch apiSettings { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): - let displayPreviews: Bool - if let showPreviews = showPreviews, case .boolFalse = showPreviews { - displayPreviews = false - } else { - displayPreviews = true - } - self = MessageNotificationSettings(enabled: muteUntil == 0, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? "2")) + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound): + let sound: Api.NotificationSound? + #if os(iOS) + sound = iosSound + #elseif os(macOS) + sound = desktopSound + #endif + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + self = MessageNotificationSettings(enabled: muteUntil == 0, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault)) } } } diff --git a/submodules/TelegramCore/Sources/State/ManagedCloudChatRemoveMessagesOperations.swift b/submodules/TelegramCore/Sources/State/ManagedCloudChatRemoveMessagesOperations.swift index b4af28309a..cb12d5ffe1 100644 --- a/submodules/TelegramCore/Sources/State/ManagedCloudChatRemoveMessagesOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedCloudChatRemoveMessagesOperations.swift @@ -395,7 +395,10 @@ private func _internal_clearHistory(transaction: Transaction, postbox: Postbox, if operation.minTimestamp != nil { return .complete() } else { - let flags: Int32 = 0 + var flags: Int32 = 0 + if operation.type == .forEveryone { + flags |= 1 << 0 + } return network.request(Api.functions.channels.deleteHistory(flags: flags, channel: inputChannel, maxId: operation.topMessageId.id)) |> map(Optional.init) |> `catch` { _ -> Signal in diff --git a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift index 04f174b2a0..01f6814dad 100644 --- a/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedGlobalNotificationSettings.swift @@ -116,56 +116,77 @@ private func fetchedNotificationSettings(network: Network) -> Signal map { chats, users, channels, contactsJoinedMuted in let chatsSettings: MessageNotificationSettings switch chats { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): - let enabled: Bool - if muteUntil != nil && muteUntil != 0 { - enabled = false - } else { - enabled = true - } - let displayPreviews: Bool - if let showPreviews = showPreviews, case .boolFalse = showPreviews { - displayPreviews = false - } else { - displayPreviews = true - } - chatsSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound): + let sound: Api.NotificationSound? + #if os(iOS) + sound = iosSound + #elseif os(macOS) + sound = desktopSound + #endif + + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + chatsSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault)) } let userSettings: MessageNotificationSettings switch users { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): - let enabled: Bool - if muteUntil != nil && muteUntil != 0 { - enabled = false - } else { - enabled = true - } - let displayPreviews: Bool - if let showPreviews = showPreviews, case .boolFalse = showPreviews { - displayPreviews = false - } else { - displayPreviews = true - } - userSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound): + let sound: Api.NotificationSound? + #if os(iOS) + sound = iosSound + #elseif os(macOS) + sound = desktopSound + #endif + + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + userSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault)) } let channelSettings: MessageNotificationSettings switch channels { - case let .peerNotifySettings(_, showPreviews, _, muteUntil, sound): - let enabled: Bool - if muteUntil != nil && muteUntil != 0 { - enabled = false - } else { - enabled = true - } - let displayPreviews: Bool - if let showPreviews = showPreviews, case .boolFalse = showPreviews { - displayPreviews = false - } else { - displayPreviews = true - } - channelSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound)) + case let .peerNotifySettings(_, showPreviews, _, muteUntil, iosSound, _, desktopSound): + let sound: Api.NotificationSound? + #if os(iOS) + sound = iosSound + #elseif os(macOS) + sound = desktopSound + #endif + + let enabled: Bool + if muteUntil != nil && muteUntil != 0 { + enabled = false + } else { + enabled = true + } + let displayPreviews: Bool + if let showPreviews = showPreviews, case .boolFalse = showPreviews { + displayPreviews = false + } else { + displayPreviews = true + } + channelSettings = MessageNotificationSettings(enabled: enabled, displayPreviews: displayPreviews, sound: PeerMessageSound(apiSound: sound ?? .notificationSoundDefault)) } return GlobalNotificationSettingsSet(privateChats: userSettings, groupChats: chatsSettings, channels: channelSettings, contactsJoined: contactsJoinedMuted == .boolFalse) @@ -179,7 +200,7 @@ private func apiInputPeerNotifySettings(_ settings: MessageNotificationSettings) } else { muteUntil = Int32.max } - let sound: String? = settings.sound.apiSound + let sound: Api.NotificationSound? = settings.sound.apiSound var flags: Int32 = 0 flags |= (1 << 0) if muteUntil != nil { diff --git a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift index c3f1bedbb4..33c196d7a9 100644 --- a/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/State/ManagedPendingPeerNotificationSettings.swift @@ -116,7 +116,7 @@ private func pushPeerNotificationSettings(postbox: Postbox, network: Network, pe case .default: muteUntil = nil } - let sound: String? = settings.messageSound.apiSound + let sound: Api.NotificationSound? = settings.messageSound.apiSound var flags: Int32 = 0 if showPreviews != nil { flags |= (1 << 0) diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift index 2cc45c0cd7..06ba62576d 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_Namespaces.swift @@ -84,6 +84,7 @@ public struct Namespaces { public static let availableReactions: Int8 = 19 public static let resolvedByPhonePeers: Int8 = 20 public static let attachMenuBots: Int8 = 21 + public static let notificationSoundList: Int8 = 22 } public struct UnorderedItemList { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift index afac21e3ea..bc1ee16a62 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramPeerNotificationSettings.swift @@ -1,3 +1,4 @@ +import Foundation import Postbox public enum PeerMuteState: Equatable { @@ -36,102 +37,147 @@ private enum PeerMessageSoundValue: Int32 { case bundledModern case bundledClassic case `default` + case cloud } public enum PeerMessageSound: Equatable { + public enum Id: Hashable { + case none + case `default` + case bundledModern(id: Int32) + case bundledClassic(id: Int32) + case cloud(fileId: Int64) + } + case none case `default` case bundledModern(id: Int32) case bundledClassic(id: Int32) + case cloud(fileId: Int64) + + public var id: Id { + switch self { + case .none: + return .none + case .default: + return .default + case let .bundledModern(id): + return .bundledModern(id: id) + case let .bundledClassic(id): + return .bundledClassic(id: id) + case let .cloud(fileId): + return .cloud(fileId: fileId) + } + } static func decodeInline(_ container: KeyedDecodingContainer) throws -> PeerMessageSound { switch try container.decode(Int32.self, forKey: "s.v") { - case PeerMessageSoundValue.none.rawValue: - return .none - case PeerMessageSoundValue.bundledModern.rawValue: - return .bundledModern(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) - case PeerMessageSoundValue.bundledClassic.rawValue: - return .bundledClassic(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) - case PeerMessageSoundValue.default.rawValue: + case PeerMessageSoundValue.none.rawValue: + return .none + case PeerMessageSoundValue.bundledModern.rawValue: + return .bundledModern(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) + case PeerMessageSoundValue.bundledClassic.rawValue: + return .bundledClassic(id: (try? container.decode(Int32.self, forKey: "s.i")) ?? 0) + case PeerMessageSoundValue.default.rawValue: + return .default + case PeerMessageSoundValue.cloud.rawValue: + do { + return .cloud(fileId: try container.decode(Int64.self, forKey: "s.cloud.fileId")) + } catch { return .default - default: - assertionFailure() - return .bundledModern(id: 0) + } + default: + assertionFailure() + return .bundledModern(id: 0) } } static func decodeInline(_ container: PostboxDecoder) -> PeerMessageSound { switch container.decodeInt32ForKey("s.v", orElse: 0) { - case PeerMessageSoundValue.none.rawValue: - return .none - case PeerMessageSoundValue.bundledModern.rawValue: - return .bundledModern(id: container.decodeInt32ForKey("s.i", orElse: 0)) - case PeerMessageSoundValue.bundledClassic.rawValue: - return .bundledClassic(id: container.decodeInt32ForKey("s.i", orElse: 0)) - case PeerMessageSoundValue.default.rawValue: - return .default - default: - assertionFailure() - return .bundledModern(id: 0) + case PeerMessageSoundValue.none.rawValue: + return .none + case PeerMessageSoundValue.bundledModern.rawValue: + return .bundledModern(id: container.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.bundledClassic.rawValue: + return .bundledClassic(id: container.decodeInt32ForKey("s.i", orElse: 0)) + case PeerMessageSoundValue.default.rawValue: + return .default + case PeerMessageSoundValue.cloud.rawValue: + return .cloud(fileId: container.decodeInt64ForKey("s.cloud.fileId", orElse: 0)) + default: + assertionFailure() + return .bundledModern(id: 0) } } func encodeInline(_ container: inout KeyedEncodingContainer) throws { switch self { - case .none: - try container.encode(PeerMessageSoundValue.none.rawValue, forKey: "s.v") - case let .bundledModern(id): - try container.encode(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") - try container.encode(id, forKey: "s.i") - case let .bundledClassic(id): - try container.encode(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") - try container.encode(id, forKey: "s.i") - case .default: - try container.encode(PeerMessageSoundValue.default.rawValue, forKey: "s.v") + case .none: + try container.encode(PeerMessageSoundValue.none.rawValue, forKey: "s.v") + case let .bundledModern(id): + try container.encode(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") + try container.encode(id, forKey: "s.i") + case let .bundledClassic(id): + try container.encode(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") + try container.encode(id, forKey: "s.i") + case let .cloud(fileId): + try container.encode(PeerMessageSoundValue.cloud.rawValue, forKey: "s.v") + try container.encode(fileId, forKey: "s.cloud.fileId") + case .default: + try container.encode(PeerMessageSoundValue.default.rawValue, forKey: "s.v") } } func encodeInline(_ encoder: PostboxEncoder) { switch self { - case .none: - encoder.encodeInt32(PeerMessageSoundValue.none.rawValue, forKey: "s.v") - case let .bundledModern(id): - encoder.encodeInt32(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") - encoder.encodeInt32(id, forKey: "s.i") - case let .bundledClassic(id): - encoder.encodeInt32(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") - encoder.encodeInt32(id, forKey: "s.i") - case .default: - encoder.encodeInt32(PeerMessageSoundValue.default.rawValue, forKey: "s.v") + case .none: + encoder.encodeInt32(PeerMessageSoundValue.none.rawValue, forKey: "s.v") + case let .bundledModern(id): + encoder.encodeInt32(PeerMessageSoundValue.bundledModern.rawValue, forKey: "s.v") + encoder.encodeInt32(id, forKey: "s.i") + case let .bundledClassic(id): + encoder.encodeInt32(PeerMessageSoundValue.bundledClassic.rawValue, forKey: "s.v") + encoder.encodeInt32(id, forKey: "s.i") + case let .cloud(fileId): + encoder.encodeInt32(PeerMessageSoundValue.cloud.rawValue, forKey: "s.v") + encoder.encodeInt64(fileId, forKey: "s.cloud.fileId") + case .default: + encoder.encodeInt32(PeerMessageSoundValue.default.rawValue, forKey: "s.v") } } public static func ==(lhs: PeerMessageSound, rhs: PeerMessageSound) -> Bool { switch lhs { - case .none: - if case .none = rhs { - return true - } else { - return false - } - case let .bundledModern(id): - if case .bundledModern(id) = rhs { - return true - } else { - return false - } - case let .bundledClassic(id): - if case .bundledClassic(id) = rhs { - return true - } else { - return false - } - case .default: - if case .default = rhs { - return true - } else { - return false - } + case .none: + if case .none = rhs { + return true + } else { + return false + } + case let .bundledModern(id): + if case .bundledModern(id) = rhs { + return true + } else { + return false + } + case let .bundledClassic(id): + if case .bundledClassic(id) = rhs { + return true + } else { + return false + } + case .default: + if case .default = rhs { + return true + } else { + return false + } + case let .cloud(fileId): + if case .cloud(fileId) = rhs { + return true + } else { + return false + } } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift new file mode 100644 index 0000000000..8f15d29543 --- /dev/null +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift @@ -0,0 +1,241 @@ +import Foundation +import SwiftSignalKit +import Postbox +import TelegramApi + +public final class NotificationSoundList: Equatable, Codable { + public final class NotificationSound: Equatable, Codable { + private enum CodingKeys: String, CodingKey { + case file + } + + public let file: TelegramMediaFile + + public init( + file: TelegramMediaFile + ) { + self.file = file + } + + public static func ==(lhs: NotificationSound, rhs: NotificationSound) -> Bool { + if lhs.file != rhs.file { + return false + } + return true + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let fileData = try container.decode(AdaptedPostboxDecoder.RawObjectData.self, forKey: .file) + self.file = TelegramMediaFile(decoder: PostboxDecoder(buffer: MemoryBuffer(data: fileData.data))) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(PostboxEncoder().encodeObjectToRawData(self.file), forKey: .file) + } + } + + private enum CodingKeys: String, CodingKey { + case hash + case sounds + } + + public let hash: Int64 + public let sounds: [NotificationSound] + + public init( + hash: Int64, + sounds: [NotificationSound] + ) { + self.hash = hash + self.sounds = sounds + } + + public static func ==(lhs: NotificationSoundList, rhs: NotificationSoundList) -> Bool { + if lhs.hash != rhs.hash { + return false + } + if lhs.sounds != rhs.sounds { + return false + } + return true + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.hash = try container.decode(Int64.self, forKey: .hash) + self.sounds = try container.decode([NotificationSound].self, forKey: .sounds) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.hash, forKey: .hash) + try container.encode(self.sounds, forKey: .sounds) + } +} + +private extension NotificationSoundList.NotificationSound { + convenience init?(apiDocument: Api.Document) { + guard let file = telegramMediaFileFromApiDocument(apiDocument) else { + return nil + } + self.init(file: file) + } +} + +func _internal_cachedNotificationSoundList(postbox: Postbox) -> Signal { + return postbox.transaction { transaction -> NotificationSoundList? in + return _internal_cachedNotificationSoundList(transaction: transaction) + } +} + +func _internal_cachedNotificationSoundListCacheKey() -> ItemCacheEntryId { + let key = ValueBoxKey(length: 8) + key.setInt64(0, value: 0) + + return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.notificationSoundList, key: key) +} + +func _internal_cachedNotificationSoundList(transaction: Transaction) -> NotificationSoundList? { + let cached = transaction.retrieveItemCacheEntry(id: _internal_cachedNotificationSoundListCacheKey())?.get(NotificationSoundList.self) + if let cached = cached { + return cached + } else { + return nil + } +} + +func _internal_setCachedNotificationSoundList(transaction: Transaction, notificationSoundList: NotificationSoundList) { + if let entry = CodableEntry(notificationSoundList) { + transaction.putItemCacheEntry(id: _internal_cachedNotificationSoundListCacheKey(), entry: entry, collectionSpec: ItemCacheCollectionSpec(lowWaterItemCount: 10, highWaterItemCount: 10)) + } +} + +private func pollNotificationSoundList(postbox: Postbox, network: Network) -> Signal { + return Signal { subscriber in + let signal: Signal = _internal_cachedNotificationSoundList(postbox: postbox) + |> mapToSignal { current in + return (network.request(Api.functions.account.getSavedRingtones(hash: current?.hash ?? 0)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction -> Signal in + guard let result = result else { + return .complete() + } + switch result { + case let .savedRingtones(hash, ringtones): + let notificationSoundList = NotificationSoundList( + hash: hash, + sounds: ringtones.compactMap(NotificationSoundList.NotificationSound.init(apiDocument:)) + ) + _internal_setCachedNotificationSoundList(transaction: transaction, notificationSoundList: notificationSoundList) + case .savedRingtonesNotModified: + break + } + + var signals: [Signal] = [] + + if let notificationSoundList = _internal_cachedNotificationSoundList(transaction: transaction) { + var resources: [MediaResource] = [] + + for sound in notificationSoundList.sounds { + resources.append(sound.file.resource) + } + + for resource in resources { + signals.append( + fetchedMediaResource(mediaBox: postbox.mediaBox, reference: .standalone(resource: resource)) + |> ignoreValues + |> `catch` { _ -> Signal in + return .complete() + } + ) + } + } + + return combineLatest(signals) + |> ignoreValues + } + |> switchToLatest + }) + } + + return signal.start(completed: { + subscriber.putCompletion() + }) + } +} + +func managedSynchronizeNotificationSoundList(postbox: Postbox, network: Network) -> Signal { + let poll = pollNotificationSoundList(postbox: postbox, network: network) + + return ( + poll + |> then( + .complete() + |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()) + ) + ) + |> restart +} + +func _internal_saveNotificationSound(account: Account, file: TelegramMediaFile) -> Signal { + guard let resource = file.resource as? CloudDocumentMediaResource else { + return .fail(.generic) + } + return account.network.request(Api.functions.account.saveRingtone(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), unsave: .boolFalse)) + |> mapError { _ -> UploadNotificationSoundError in + return .generic + } + |> mapToSignal { _ -> Signal in + return pollNotificationSoundList(postbox: account.postbox, network: account.network) + |> castError(UploadNotificationSoundError.self) + } +} + +public enum UploadNotificationSoundError { + case generic +} + +func _internal_uploadNotificationSound(account: Account, title: String, data: Data) -> Signal { + return multipartUpload(network: account.network, postbox: account.postbox, source: .data(data), encrypt: false, tag: nil, hintFileSize: data.count, hintFileIsLarge: false, forceNoBigParts: true, useLargerParts: false, increaseParallelParts: false, useMultiplexedRequests: false, useCompression: false) + |> mapError { _ -> UploadNotificationSoundError in + return .generic + } + |> mapToSignal { value -> Signal in + switch value { + case let .inputFile(file): + return account.network.request(Api.functions.account.uploadRingtone(file: file, fileName: title, mimeType: "audio/mpeg")) + |> mapError { _ -> UploadNotificationSoundError in + return .generic + } + |> mapToSignal { result -> Signal in + guard let file = telegramMediaFileFromApiDocument(result) else { + return .fail(.generic) + } + return account.postbox.transaction { transaction -> NotificationSoundList.NotificationSound in + let item = NotificationSoundList.NotificationSound(file: file) + + account.postbox.mediaBox.storeResourceData(file.resource.id, data: data, synchronous: true) + + let notificationSoundList = _internal_cachedNotificationSoundList(transaction: transaction) ?? NotificationSoundList(hash: 0, sounds: []) + let updatedNotificationSoundList = NotificationSoundList(hash: notificationSoundList.hash, sounds: [item] + notificationSoundList.sounds) + _internal_setCachedNotificationSoundList(transaction: transaction, notificationSoundList: updatedNotificationSoundList) + + return item + } + |> castError(UploadNotificationSoundError.self) + } + default: + return .never() + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift index 15da45cd4b..c8e13058f8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/Peer.swift @@ -1,3 +1,4 @@ +import Foundation import Postbox public enum EnginePeer: Equatable { @@ -75,6 +76,7 @@ public enum EnginePeer: Equatable { case `default` case bundledModern(id: Int32) case bundledClassic(id: Int32) + case cloud(fileId: Int64) } public enum DisplayPreviews { @@ -200,6 +202,8 @@ public extension EnginePeer.NotificationSettings.MessageSound { self = .bundledClassic(id: id) case let .bundledModern(id): self = .bundledModern(id: id) + case let .cloud(fileId): + self = .cloud(fileId: fileId) } } @@ -213,6 +217,8 @@ public extension EnginePeer.NotificationSettings.MessageSound { return .bundledClassic(id: id) case let .bundledModern(id): return .bundledModern(id: id) + case let .cloud(fileId): + return .cloud(fileId: fileId) } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index ffc1e598d6..68882bbb26 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -684,6 +684,25 @@ public extension TelegramEngine { public func updatePeerAllowedReactions(peerId: PeerId, allowedReactions: [String]) -> Signal { return _internal_updatePeerAllowedReactions(account: account, peerId: peerId, allowedReactions: allowedReactions) } + + public func notificationSoundList() -> Signal { + let key = PostboxViewKey.cachedItem(_internal_cachedNotificationSoundListCacheKey()) + return self.account.postbox.combinedView(keys: [key]) + |> map { views -> NotificationSoundList? in + guard let view = views.views[key] as? CachedItemView else { + return nil + } + return view.value?.get(NotificationSoundList.self) + } + } + + public func saveNotificationSound(file: TelegramMediaFile) -> Signal { + return _internal_saveNotificationSound(account: self.account, file: file) + } + + public func uploadNotificationSound(title: String, data: Data) -> Signal { + return _internal_uploadNotificationSound(account: self.account, title: title, data: data) + } } } diff --git a/submodules/TelegramPresentationData/Sources/NumericFormat.swift b/submodules/TelegramPresentationData/Sources/NumericFormat.swift index accea9d382..ec999b6a9e 100644 --- a/submodules/TelegramPresentationData/Sources/NumericFormat.swift +++ b/submodules/TelegramPresentationData/Sources/NumericFormat.swift @@ -38,6 +38,18 @@ public func presentationStringsFormattedNumber(_ count: Int32, _ groupingSeparat } } +public func dayIntervalString(strings: PresentationStrings, days: Int32) -> String { + return strings.MessageTimer_Days(max(0, days)) +} + +public func hoursIntervalString(strings: PresentationStrings, hours: Int32) -> String { + return strings.MessageTimer_Hours(max(0, hours)) +} + +public func minutesIntervalString(strings: PresentationStrings, minutes: Int32) -> String { + return strings.MessageTimer_Minutes(max(0, minutes)) +} + public func timeIntervalString(strings: PresentationStrings, value: Int32, preferLowerValue: Bool = false) -> String { if preferLowerValue { if value <= 60 { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift index 793aa8053c..1f3d80386c 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourceKey.swift @@ -273,6 +273,8 @@ public enum PresentationResourceKey: Int32 { case chatKeyboardActionButtonProfileIcon case chatKeyboardActionButtonAddToChatIcon case chatKeyboardActionButtonWebAppIcon + + case uploadToneIcon } public enum PresentationResourceParameterKey: Hashable { diff --git a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift index 361f10141e..eb199046f8 100644 --- a/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift +++ b/submodules/TelegramPresentationData/Sources/Resources/PresentationResourcesItemList.swift @@ -269,4 +269,10 @@ public struct PresentationResourcesItemList { })?.stretchableImage(withLeftCapWidth: 25, topCapHeight: 25) }) } + + public static func uploadToneIcon(_ theme: PresentationTheme) -> UIImage? { + return theme.image(PresentationResourceKey.uploadToneIcon.rawValue, { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Settings/UploadTone"), color: theme.list.itemAccentColor) + }) + } } diff --git a/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift b/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift index ecb3db3f12..dbf3cfcd02 100644 --- a/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/PeerNotificationSoundStrings.swift @@ -28,41 +28,52 @@ private let classicSoundNamePaths: [KeyPath] = [ \.NotificationsSound_Telegraph ] -private func soundName(strings: PresentationStrings, sound: PeerMessageSound) -> String { +private func soundName(strings: PresentationStrings, sound: PeerMessageSound, notificationSoundList: NotificationSoundList?) -> String { switch sound { - case .none: - return strings.NotificationsSound_None - case .default: - return "" - case let .bundledModern(id): - if id >= 0 && Int(id) < modernSoundsNamePaths.count { - return strings[keyPath: modernSoundsNamePaths[Int(id)]] + case .none: + return strings.NotificationsSound_None + case .default: + return "" + case let .bundledModern(id): + if id >= 0 && Int(id) < modernSoundsNamePaths.count { + return strings[keyPath: modernSoundsNamePaths[Int(id)]] + } + return "Sound \(id)" + case let .bundledClassic(id): + if id >= 0 && Int(id) < classicSoundNamePaths.count { + return strings[keyPath: classicSoundNamePaths[Int(id)]] + } + return "Sound \(id)" + case let .cloud(fileId): + guard let notificationSoundList = notificationSoundList else { + //TODO:localize + return "Loading..." + } + for sound in notificationSoundList.sounds { + if sound.file.fileId.id == fileId { + return sound.file.fileName ?? "Cloud Tone" } - return "Sound \(id)" - case let .bundledClassic(id): - if id >= 0 && Int(id) < classicSoundNamePaths.count { - return strings[keyPath: classicSoundNamePaths[Int(id)]] - } - return "Sound \(id)" + } + return "" } } -public func localizedPeerNotificationSoundString(strings: PresentationStrings, sound: PeerMessageSound, default: PeerMessageSound? = nil) -> String { +public func localizedPeerNotificationSoundString(strings: PresentationStrings, notificationSoundList: NotificationSoundList?, sound: PeerMessageSound, default: PeerMessageSound? = nil) -> String { switch sound { - case .default: - if let defaultSound = `default` { - let name = soundName(strings: strings, sound: defaultSound) - let actualName: String - if name.isEmpty { - actualName = soundName(strings: strings, sound: .bundledModern(id: 0)) - } else { - actualName = name - } - return strings.UserInfo_NotificationsDefaultSound(actualName).string + case .default: + if let defaultSound = `default` { + let name = soundName(strings: strings, sound: defaultSound, notificationSoundList: notificationSoundList) + let actualName: String + if name.isEmpty { + actualName = soundName(strings: strings, sound: .bundledModern(id: 0), notificationSoundList: notificationSoundList) } else { - return strings.UserInfo_NotificationsDefault + actualName = name } - default: - return soundName(strings: strings, sound: sound) + return strings.UserInfo_NotificationsDefaultSound(actualName).string + } else { + return strings.UserInfo_NotificationsDefault + } + default: + return soundName(strings: strings, sound: sound, notificationSoundList: notificationSoundList) } } diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/Contents.json new file mode 100644 index 0000000000..9b661ffb8b --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "clearmessages_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/clearmessages_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/clearmessages_24.pdf new file mode 100644 index 0000000000..7e880e11cb --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/ClearMessages.imageset/clearmessages_24.pdf @@ -0,0 +1,285 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 3.000000 3.630371 cm +0.000000 0.000000 0.000000 scn +6.036711 3.044792 m +5.888044 2.396624 l +6.036711 3.044792 l +h +4.213051 1.739638 m +3.887771 2.319654 l +3.887771 2.319654 l +4.213051 1.739638 l +h +1.977577 1.386564 m +1.720352 0.773327 l +1.977577 1.386564 l +h +2.890895 4.595274 m +2.498061 4.058705 l +2.890895 4.595274 l +h +8.000000 16.704628 m +12.112072 16.704628 15.335000 13.688025 15.335000 10.096902 c +16.665001 10.096902 l +16.665001 14.539012 12.724484 18.034630 8.000000 18.034630 c +8.000000 16.704628 l +h +15.335000 10.096902 m +15.335000 6.505779 12.112072 3.489175 8.000000 3.489175 c +8.000000 2.159175 l +12.724484 2.159175 16.665001 5.654792 16.665001 10.096902 c +15.335000 10.096902 l +h +8.000000 3.489175 m +7.372782 3.489175 6.764923 3.560034 6.185379 3.692961 c +5.888044 2.396624 l +6.564841 2.241389 7.272436 2.159175 8.000000 2.159175 c +8.000000 3.489175 l +h +6.185379 3.692961 m +5.804111 3.780411 5.513260 3.569372 5.413143 3.494156 c +5.290826 3.402263 5.147437 3.265127 5.034352 3.161364 c +4.781663 2.929504 4.434368 2.626192 3.887771 2.319654 c +4.538331 1.159622 l +5.211778 1.537300 5.645048 1.916672 5.933547 2.181390 c +6.091055 2.325915 6.158414 2.390541 6.212014 2.430810 c +6.287813 2.487756 6.138047 2.339281 5.888044 2.396624 c +6.185379 3.692961 l +h +3.887771 2.319654 m +3.572365 2.142771 3.165311 2.048659 2.790003 2.014445 c +2.607043 1.997766 2.446026 1.996657 2.327112 2.003073 c +2.267397 2.006294 2.224190 2.011101 2.197881 2.015177 c +2.158949 2.021208 2.183327 2.021393 2.234801 1.999803 c +1.720352 0.773327 l +1.821844 0.730755 1.926930 0.711287 1.994275 0.700853 c +2.074244 0.688465 2.162884 0.679998 2.255463 0.675005 c +2.441139 0.664988 2.666504 0.667671 2.910749 0.689938 c +3.389851 0.733614 4.000499 0.858000 4.538331 1.159622 c +3.887771 2.319654 l +h +2.234801 1.999803 m +2.265677 1.986851 2.404851 1.923249 2.493219 1.747771 c +2.589725 1.556132 2.551083 1.383581 2.526376 1.313473 c +2.504906 1.252550 2.480861 1.226551 2.497980 1.249567 c +2.510608 1.266544 2.534224 1.295128 2.576988 1.342783 c +2.735965 1.519941 3.080277 1.865030 3.376156 2.318596 c +2.262219 3.045261 l +2.039068 2.703184 1.800315 2.468651 1.587115 2.231068 c +1.536834 2.175037 1.480586 2.110241 1.430826 2.043344 c +1.385558 1.982486 1.316601 1.882117 1.271991 1.755535 c +1.224144 1.619764 1.184133 1.390259 1.305339 1.149572 c +1.418406 0.925049 1.608346 0.820307 1.720352 0.773327 c +2.234801 1.999803 l +h +3.376156 2.318596 m +3.725287 2.853793 3.824730 3.434122 3.801171 3.906185 c +3.789388 4.142282 3.746260 4.366606 3.677134 4.560054 c +3.618218 4.724927 3.504569 4.970161 3.283730 5.131843 c +2.498061 4.058705 l +2.393648 4.135148 2.394127 4.198050 2.424695 4.112509 c +2.445051 4.055541 2.466761 3.961368 2.472824 3.839892 c +2.484955 3.596812 2.432118 3.305708 2.262219 3.045261 c +3.376156 2.318596 l +h +3.283730 5.131843 m +1.614924 6.353613 0.665000 8.040656 0.665000 10.096902 c +-0.665000 10.096902 l +-0.665000 7.571545 0.525193 5.503087 2.498061 4.058705 c +3.283730 5.131843 l +h +0.665000 10.096902 m +0.665000 13.688025 3.887928 16.704628 8.000000 16.704628 c +8.000000 18.034630 l +3.275515 18.034630 -0.665000 14.539012 -0.665000 10.096902 c +0.665000 10.096902 l +h +f +n +Q +q +-1.000000 -0.000000 -0.000000 1.000000 21.700012 1.535767 cm +0.000000 0.000000 0.000000 scn +6.036711 3.139397 m +5.888044 2.491228 l +6.036711 3.139397 l +h +4.213051 1.834243 m +3.887771 2.414258 l +3.887771 2.414258 l +4.213051 1.834243 l +h +1.977577 1.481169 m +1.720352 0.867930 l +1.977577 1.481169 l +h +2.890895 4.689878 m +2.498061 4.153310 l +2.890895 4.689878 l +h +1.435227 13.141423 m +1.613510 13.462519 1.497738 13.867344 1.176643 14.045628 c +0.855548 14.223910 0.450722 14.108138 0.272439 13.787044 c +1.435227 13.141423 l +h +9.828376 2.430831 m +10.188738 2.501724 10.423399 2.851326 10.352506 3.211688 c +10.281612 3.572050 9.932011 3.806711 9.571649 3.735818 c +9.828376 2.430831 l +h +8.000000 3.583779 m +7.372782 3.583779 6.764923 3.654638 6.185379 3.787565 c +5.888044 2.491228 l +6.564841 2.335994 7.272436 2.253779 8.000000 2.253779 c +8.000000 3.583779 l +h +6.185379 3.787565 m +5.804111 3.875015 5.513260 3.663977 5.413143 3.588760 c +5.290826 3.496867 5.147437 3.359732 5.034352 3.255968 c +4.781663 3.024109 4.434368 2.720797 3.887771 2.414258 c +4.538331 1.254228 l +5.211778 1.631905 5.645048 2.011276 5.933547 2.275994 c +6.091055 2.420520 6.158414 2.485146 6.212014 2.525414 c +6.287813 2.582360 6.138047 2.433886 5.888044 2.491228 c +6.185379 3.787565 l +h +3.887771 2.414258 m +3.572365 2.237375 3.165311 2.143264 2.790003 2.109050 c +2.607043 2.092371 2.446026 2.091262 2.327112 2.097677 c +2.267397 2.100899 2.224190 2.105705 2.197881 2.109781 c +2.158949 2.115812 2.183327 2.115997 2.234801 2.094407 c +1.720352 0.867930 l +1.821844 0.825360 1.926930 0.805891 1.994275 0.795458 c +2.074244 0.783070 2.162884 0.774603 2.255463 0.769608 c +2.441139 0.759591 2.666504 0.762276 2.910749 0.784542 c +3.389851 0.828218 4.000499 0.952604 4.538331 1.254228 c +3.887771 2.414258 l +h +2.234801 2.094407 m +2.265677 2.081455 2.404851 2.017854 2.493219 1.842376 c +2.589725 1.650737 2.551083 1.478186 2.526376 1.408076 c +2.504906 1.347156 2.480861 1.321156 2.497980 1.344172 c +2.510608 1.361148 2.534224 1.389732 2.576988 1.437387 c +2.735965 1.614546 3.080277 1.959635 3.376156 2.413200 c +2.262219 3.139866 l +2.039068 2.797789 1.800315 2.563255 1.587115 2.325672 c +1.536834 2.269642 1.480586 2.204845 1.430826 2.137948 c +1.385558 2.077090 1.316601 1.976722 1.271991 1.850140 c +1.224144 1.714369 1.184133 1.484863 1.305339 1.244177 c +1.418406 1.019652 1.608346 0.914912 1.720352 0.867930 c +2.234801 2.094407 l +h +3.376156 2.413200 m +3.725287 2.948398 3.824730 3.528727 3.801171 4.000790 c +3.789388 4.236886 3.746260 4.461210 3.677134 4.654658 c +3.618218 4.819531 3.504569 5.064766 3.283730 5.226447 c +2.498061 4.153310 l +2.393648 4.229753 2.394127 4.292655 2.424695 4.207113 c +2.445051 4.150146 2.466761 4.055972 2.472824 3.934497 c +2.484955 3.691417 2.432118 3.400312 2.262219 3.139866 c +3.376156 2.413200 l +h +3.283730 5.226447 m +1.614924 6.448217 0.665000 8.135260 0.665000 10.191506 c +-0.665000 10.191506 l +-0.665000 7.666149 0.525193 5.597691 2.498061 4.153310 c +3.283730 5.226447 l +h +0.665000 10.191506 m +0.665000 11.250713 0.941389 12.252002 1.435227 13.141423 c +0.272439 13.787044 l +-0.326097 12.709055 -0.665000 11.486644 -0.665000 10.191506 c +0.665000 10.191506 l +h +9.571649 3.735818 m +9.065956 3.636334 8.540168 3.583779 8.000000 3.583779 c +8.000000 2.253779 l +8.626554 2.253779 9.238318 2.314750 9.828376 2.430831 c +9.571649 3.735818 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 7.335022 9.700195 cm +0.000000 0.000000 0.000000 scn +1.135226 7.265065 m +0.875527 7.524764 0.454473 7.524764 0.194774 7.265065 c +-0.064925 7.005366 -0.064925 6.584311 0.194774 6.324613 c +2.724548 3.794839 l +0.194774 1.265065 l +-0.064925 1.005366 -0.064925 0.584311 0.194774 0.324613 c +0.454473 0.064914 0.875527 0.064914 1.135226 0.324613 c +3.665000 2.854387 l +6.194774 0.324613 l +6.454473 0.064914 6.875527 0.064914 7.135226 0.324613 c +7.394925 0.584311 7.394925 1.005366 7.135226 1.265065 c +4.605452 3.794839 l +7.135226 6.324613 l +7.394925 6.584311 7.394925 7.005366 7.135226 7.265065 c +6.875527 7.524764 6.454473 7.524764 6.194774 7.265065 c +3.665000 4.735291 l +1.135226 7.265065 l +h +f* +n +Q + +endstream +endobj + +3 0 obj + 7291 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000007381 00000 n +0000007404 00000 n +0000007577 00000 n +0000007651 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +7710 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/Contents.json new file mode 100644 index 0000000000..669efc0d5d --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "custom_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/custom_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/custom_24.pdf new file mode 100644 index 0000000000..7992899240 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/Customize.imageset/custom_24.pdf @@ -0,0 +1,163 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 10.500000 15.669922 cm +0.000000 0.000000 0.000000 scn +0.000000 1.995078 m +-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c +-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c +0.000000 1.995078 l +h +9.000000 0.665078 m +9.367270 0.665078 9.665000 0.962809 9.665000 1.330078 c +9.665000 1.697348 9.367270 1.995078 9.000000 1.995078 c +9.000000 0.665078 l +h +0.000000 0.665078 m +9.000000 0.665078 l +9.000000 1.995078 l +0.000000 1.995078 l +0.000000 0.665078 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 4.500000 5.669922 cm +0.000000 0.000000 0.000000 scn +0.000000 1.995078 m +-0.367269 1.995078 -0.665000 1.697348 -0.665000 1.330078 c +-0.665000 0.962809 -0.367269 0.665078 0.000000 0.665078 c +0.000000 1.995078 l +h +9.000000 0.665078 m +9.367270 0.665078 9.665000 0.962809 9.665000 1.330078 c +9.665000 1.697348 9.367270 1.995078 9.000000 1.995078 c +9.000000 0.665078 l +h +0.000000 0.665078 m +9.000000 0.665078 l +9.000000 1.995078 l +0.000000 1.995078 l +0.000000 0.665078 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 4.000000 12.669922 cm +0.000000 0.000000 0.000000 scn +5.335000 4.330078 m +5.335000 3.040493 4.289585 1.995078 3.000000 1.995078 c +3.000000 0.665078 l +5.024124 0.665078 6.665000 2.305954 6.665000 4.330078 c +5.335000 4.330078 l +h +3.000000 1.995078 m +1.710415 1.995078 0.665000 3.040493 0.665000 4.330078 c +-0.665000 4.330078 l +-0.665000 2.305954 0.975876 0.665078 3.000000 0.665078 c +3.000000 1.995078 l +h +0.665000 4.330078 m +0.665000 5.619663 1.710415 6.665078 3.000000 6.665078 c +3.000000 7.995078 l +0.975876 7.995078 -0.665000 6.354202 -0.665000 4.330078 c +0.665000 4.330078 l +h +3.000000 6.665078 m +4.289585 6.665078 5.335000 5.619663 5.335000 4.330078 c +6.665000 4.330078 l +6.665000 6.354202 5.024124 7.995078 3.000000 7.995078 c +3.000000 6.665078 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 14.000000 2.669922 cm +0.000000 0.000000 0.000000 scn +5.335000 4.330078 m +5.335000 3.040493 4.289585 1.995078 3.000000 1.995078 c +3.000000 0.665078 l +5.024124 0.665078 6.665000 2.305954 6.665000 4.330078 c +5.335000 4.330078 l +h +3.000000 1.995078 m +1.710415 1.995078 0.665000 3.040493 0.665000 4.330078 c +-0.665000 4.330078 l +-0.665000 2.305954 0.975876 0.665078 3.000000 0.665078 c +3.000000 1.995078 l +h +0.665000 4.330078 m +0.665000 5.619663 1.710415 6.665078 3.000000 6.665078 c +3.000000 7.995078 l +0.975876 7.995078 -0.665000 6.354202 -0.665000 4.330078 c +0.665000 4.330078 l +h +3.000000 6.665078 m +4.289585 6.665078 5.335000 5.619663 5.335000 4.330078 c +6.665000 4.330078 l +6.665000 6.354202 5.024124 7.995078 3.000000 7.995078 c +3.000000 6.665078 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 2650 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002740 00000 n +0000002763 00000 n +0000002936 00000 n +0000003010 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +3069 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/Contents.json new file mode 100644 index 0000000000..dbdc1d9a97 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "downloadtone_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/downloadtone_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/downloadtone_24.pdf new file mode 100644 index 0000000000..75999b1619 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DownloadTone.imageset/downloadtone_24.pdf @@ -0,0 +1,116 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.334961 1.926270 cm +0.000000 0.000000 0.000000 scn +18.499836 17.264488 m +18.499828 17.485374 18.289789 17.645796 18.076683 17.587671 c +14.576791 16.633081 l +14.431045 16.593330 14.329936 16.460947 14.329941 16.309877 c +14.330013 13.944344 l +18.253044 15.014344 l +18.398790 15.054096 18.499899 15.186479 18.499895 15.337549 c +18.499836 17.264488 l +h +13.000040 13.073683 m +12.999941 16.309837 l +12.999918 17.060677 13.502439 17.718637 14.226819 17.916210 c +17.726713 18.870800 l +18.785870 19.159685 19.829802 18.362379 19.829836 17.264528 c +19.829895 15.337589 l +19.829918 14.586750 19.327396 13.928788 18.603016 13.731215 c +14.330040 12.565768 l +14.330040 5.073744 l +14.330001 5.073744 l +14.330006 4.174320 l +14.330013 2.634279 13.299263 1.284771 11.813485 0.879566 c +11.386369 0.763084 l +9.429031 0.229277 7.499888 1.702747 7.499878 3.731570 c +7.499871 5.119122 8.428559 6.335007 9.767220 6.700088 c +13.000040 7.581746 l +13.000040 13.073662 l +13.000040 13.073683 l +h +12.999995 6.203160 m +10.117160 5.416950 l +9.357137 5.209676 8.829874 4.519358 8.829878 3.731577 c +8.829884 2.579716 9.925153 1.743153 11.036430 2.046223 c +11.463547 2.162704 l +12.370687 2.410101 13.000010 3.234043 13.000006 4.174314 c +12.999995 6.203160 l +h +3.665000 17.738770 m +4.032269 17.738770 4.330000 17.441038 4.330000 17.073769 c +4.330000 10.679222 l +6.194774 12.543995 l +6.454473 12.803694 6.875527 12.803694 7.135226 12.543995 c +7.394925 12.284297 7.394925 11.863242 7.135226 11.603544 c +4.135226 8.603543 l +3.875527 8.343845 3.454473 8.343845 3.194774 8.603543 c +0.194774 11.603544 l +-0.064925 11.863242 -0.064925 12.284297 0.194774 12.543995 c +0.454473 12.803694 0.875527 12.803694 1.135226 12.543995 c +3.000000 10.679222 l +3.000000 17.073769 l +3.000000 17.441038 3.297731 17.738770 3.665000 17.738770 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1860 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000001950 00000 n +0000001973 00000 n +0000002146 00000 n +0000002220 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2279 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/Contents.json new file mode 100644 index 0000000000..53f08cbb91 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "addtone_30.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/addtone_30.pdf b/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/addtone_30.pdf new file mode 100644 index 0000000000..a7c14bd9fa --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/UploadTone.imageset/addtone_30.pdf @@ -0,0 +1,118 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.335022 2.524536 cm +0.000000 0.000000 0.000000 scn +24.000023 22.149782 m +24.000023 22.372349 23.786995 22.533037 23.572990 22.471893 c +18.572990 21.043322 l +18.429174 21.002232 18.330023 20.870783 18.330023 20.721212 c +18.330023 17.357124 l +23.757053 18.907703 l +23.900869 18.948795 24.000023 19.080244 24.000023 19.229815 c +24.000023 22.149782 l +h +18.330023 15.973903 m +24.122433 17.628878 l +24.837221 17.833101 25.330023 18.486425 25.330023 19.229815 c +25.330023 22.149782 l +25.330023 23.255974 24.271240 24.054613 23.207611 23.750721 c +18.207611 22.322149 l +17.492825 22.117924 17.000023 21.464602 17.000023 20.721212 c +17.000023 16.475513 l +17.000023 8.977081 l +12.574430 7.712626 l +11.050592 7.277245 10.000000 5.884441 10.000000 4.299627 c +10.000000 1.941366 12.257193 0.238766 14.524715 0.886629 c +15.671853 1.214382 l +17.245243 1.663923 18.330000 3.102016 18.330000 4.738369 c +18.330000 5.475513 l +18.330023 5.475513 l +18.330023 15.973903 l +h +17.000000 7.593853 m +12.939809 6.433800 l +11.986943 6.161552 11.330000 5.290623 11.330000 4.299627 c +11.330000 2.824991 12.741438 1.760342 14.159337 2.165457 c +15.306474 2.493210 l +16.308893 2.779615 17.000000 3.695837 17.000000 4.738369 c +17.000000 7.593853 l +h +5.665000 21.140503 m +6.032269 21.140503 6.330000 20.842772 6.330000 20.475502 c +6.330000 16.140503 l +10.665000 16.140503 l +11.032269 16.140503 11.330000 15.842772 11.330000 15.475503 c +11.330000 15.108233 11.032269 14.810503 10.665000 14.810503 c +6.330000 14.810503 l +6.330000 10.475503 l +6.330000 10.108233 6.032269 9.810503 5.665000 9.810503 c +5.297730 9.810503 5.000000 10.108233 5.000000 10.475503 c +5.000000 14.810503 l +0.665000 14.810503 l +0.297731 14.810503 0.000000 15.108233 0.000000 15.475503 c +0.000000 15.842772 0.297731 16.140503 0.665000 16.140503 c +5.000000 16.140503 l +5.000000 20.475502 l +5.000000 20.842772 5.297730 21.140503 5.665000 21.140503 c +h +f* +n +Q + +endstream +endobj + +3 0 obj + 1956 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000002046 00000 n +0000002069 00000 n +0000002242 00000 n +0000002316 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2375 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Resources/Animations/anim_notificationsound.json b/submodules/TelegramUI/Resources/Animations/anim_notificationsound.json new file mode 100644 index 0000000000..d323a10f4f --- /dev/null +++ b/submodules/TelegramUI/Resources/Animations/anim_notificationsound.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":66,"w":512,"h":512,"nm":"Sound Download 2","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.764],"y":[1]},"o":{"x":[0.683],"y":[0]},"t":4,"s":[-5]},{"i":{"x":[0.44],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":15,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.576],"y":[0]},"t":23,"s":[-1]},{"i":{"x":[0.517],"y":[1]},"o":{"x":[0.4],"y":[0]},"t":32,"s":[2]},{"i":{"x":[0.6],"y":[1]},"o":{"x":[0.545],"y":[0]},"t":39,"s":[-1]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":47,"s":[2]},{"i":{"x":[0.7],"y":[1]},"o":{"x":[0.3],"y":[0]},"t":56,"s":[-1]},{"t":65,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.59,"y":1},"o":{"x":0.236,"y":0},"t":0,"s":[256,416,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":11,"s":[262,232,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":19,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.4,"y":0},"t":28,"s":[256,256,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[256,284,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":43,"s":[256,236,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.3,"y":0},"t":52,"s":[256,300,0],"to":[0,0,0],"ti":[0,0,0]},{"t":63,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.5,0.5,0.5],"y":[1,1,1]},"o":{"x":[0.2,0.2,0.2],"y":[0,0,0]},"t":0,"s":[60,10,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":11,"s":[90,110,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":19,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.4,0.4,0.4],"y":[0,0,0]},"t":28,"s":[95,105,100]},{"i":{"x":[0.6,0.6,0.6],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":34,"s":[105,95,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":43,"s":[95,105,100]},{"i":{"x":[0.7,0.7,0.7],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":52,"s":[105,95,100]},{"t":63,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":179,"st":-1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.8,"y":1},"o":{"x":0.7,"y":0},"t":36,"s":[395,27.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.6,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[395,219.333,0],"to":[0,0,0],"ti":[0,0,0]},{"t":62,"s":[395,141.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[117,-105.5],[139.054,-69],[161,-105.5]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[62,-80],[139.188,-36.333],[216,-80]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.038,-110],[139.02,-69.849]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-172],[139.071,-37.349]],"c":false}]},{"t":62,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.063,-193],[139.063,-37.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":36,"op":213,"st":33,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.744,"y":0.482},"o":{"x":0.477,"y":0},"t":16,"s":[395,41.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.615,"y":0.728},"o":{"x":0.312,"y":0.353},"t":28,"s":[391,145.474,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.581,"y":1},"o":{"x":0.265,"y":0.596},"t":34,"s":[401.815,238.274,0],"to":[0,0,0],"ti":[0,0,0]},{"t":42,"s":[399,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[103,-112.817],[139.088,-93],[175,-112.817]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139,-86.5],[139,-51.833],[139,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":16,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.066,-130],[139.033,-93.461]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":38,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-102],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":16,"op":38,"st":-1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arrow 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.746,"y":0.458},"o":{"x":0.463,"y":0},"t":4,"s":[395,105.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.489,"y":1},"o":{"x":0.267,"y":0.449},"t":12,"s":[395,167.999,0],"to":[0,0,0],"ti":[0,0,0]},{"t":23,"s":[401,277.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[93.085,-94.664],[139.112,-63],[184.915,-94.664]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[139.25,-103],[139,-51.833],[139.25,-103]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":4,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.084,-137],[139.042,-63.736]],"c":false}]},{"i":{"x":0.39,"y":1},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.125,-167],[139.063,-37.5]],"c":false}]},{"t":20,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.5,-103.5],[139,-53]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":3,"op":20,"st":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"R","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.174,82.369,0],"ix":2},"a":{"a":0,"k":[88.174,82.369,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.566,"y":1},"o":{"x":0.61,"y":0},"t":0,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.904,-49.445],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.406,-46.501],[136.514,-43.354]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[162.959,25.276],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[122.462,28.22],[139.57,31.366]],"c":true}]},{"i":{"x":0.287,"y":1},"o":{"x":0.451,"y":0},"t":22,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.305,-51.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.808,-48.801],[135.916,-45.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.027,13.718],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.529,16.663],[135.637,19.809]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.599,"y":0},"t":42,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.611,-74.745],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.114,-71.801],[136.222,-68.654]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[-4.316,1.274],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-3.48,-4.272],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.226],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[160.128,43.818],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[111.637,55.698],[111.65,43.878],[135.309,47.714]],"c":true}]},{"t":62,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.452,6.555],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.955,9.499],[136.063,12.646]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":181,"st":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-58.912,2.378,0],"ix":2},"a":{"a":0,"k":[-58.912,2.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.82,"y":1},"o":{"x":0.279,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[48.175,-182.632],[48.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.458,"y":1},"o":{"x":0.3,"y":0},"t":14,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[94.175,-189.632],[94.165,-147.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.837,"y":1},"o":{"x":0.66,"y":0},"t":22,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[62.175,-183.632],[62.165,-141.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.82,"y":1},"o":{"x":0.3,"y":0},"t":34,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[90.175,-190.632],[90.165,-148.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.8,"y":1},"o":{"x":0.66,"y":0},"t":42,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[63.175,-182.632],[63.165,-140.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.4,"y":1},"o":{"x":0.2,"y":0},"t":51,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"t":62,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":179,"st":-1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/submodules/TelegramUI/Resources/Animations/anim_notificationsoundprogress.json b/submodules/TelegramUI/Resources/Animations/anim_notificationsoundprogress.json new file mode 100644 index 0000000000..7c93f3b7b7 --- /dev/null +++ b/submodules/TelegramUI/Resources/Animations/anim_notificationsoundprogress.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":60,"w":512,"h":512,"nm":"Sound Download","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL ALL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.1,"y":0},"t":-1,"s":[256,56,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":11,"s":[256,322,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":25,"s":[256,228,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.41,"y":1},"o":{"x":0.3,"y":0},"t":39,"s":[256,288,0],"to":[0,0,0],"ti":[0,0,0]},{"t":59,"s":[256,256,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.359,0.359,0.115],"y":[0,0,0]},"t":0,"s":[20,60,100]},{"i":{"x":[0.54,0.54,0.738],"y":[1,1,1]},"o":{"x":[0.1,0.1,0.1],"y":[0,0,0]},"t":11,"s":[102,70,100]},{"i":{"x":[0.4,0.4,0.4],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":25,"s":[90,110,100]},{"i":{"x":[0.41,0.41,0.41],"y":[1,1,1]},"o":{"x":[0.3,0.3,0.3],"y":[0,0,0]},"t":39,"s":[105,95,100]},{"t":59,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":1,"op":179,"st":-1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.7,"y":1},"o":{"x":0.7,"y":0},"t":8,"s":[387,21.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.4,"y":1},"o":{"x":0.3,"y":0},"t":22,"s":[389,181.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.41,"y":1},"o":{"x":0.3,"y":0},"t":36,"s":[399,111.333,0],"to":[0,0,0],"ti":[0,0,0]},{"t":59,"s":[395,141.333,0]}],"ix":2},"a":{"a":0,"k":[139,-114.667,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[112.991,-95.024],[139.219,-96.402],[166.009,-94.955]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[112.991,-101.972],[139.219,-36.333],[166.009,-105.232]],"c":false}]},{"i":{"x":0.71,"y":1},"o":{"x":0.167,"y":0.167},"t":22,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[68,-84],[139.173,-36.333],[210,-84]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.29,"y":0},"t":36,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[86.5,-84],[139.137,-36.333],[193,-84.5]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[70.667,-86.5],[139.167,-36.333],[207.333,-86.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[138.582,-93.931],[139.036,-96.361]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[138.582,-154],[139.036,-38.319]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":19,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[138.145,-207.143],[139.051,-37.851]],"c":false}]},{"i":{"x":0.71,"y":1},"o":{"x":0.167,"y":0.167},"t":22,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[138.063,-170],[139.063,-37.5]],"c":false}]},{"i":{"x":0.4,"y":1},"o":{"x":0.29,"y":0},"t":36,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.063,-193],[139.051,-37.5]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[139.063,-193],[139.063,-37.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":40,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":12,"op":179,"st":-1,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"R","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[88.174,82.369,0],"ix":2},"a":{"a":0,"k":[88.174,82.369,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.6,"y":1},"o":{"x":0.2,"y":0},"t":14,"s":[{"i":[[-0.626,-19.83],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-5.043,-3.301]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[3.48,-0.35],[11.788,7.716]],"v":[[159.476,-150.419],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.979,-191.031],[139.841,-186.806]],"c":true}]},{"i":{"x":0.517,"y":1},"o":{"x":0.589,"y":0},"t":22,"s":[{"i":[[-4.753,-0.752],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-5.911,-1.178]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[9.821,1.957]],"v":[[159.61,61.441],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[119.173,53.964],[136.554,58.5]],"c":true}]},{"i":{"x":0.41,"y":1},"o":{"x":0.433,"y":0},"t":36,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.348,-48.29],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.851,-45.346],[135.959,-42.2]],"c":true}]},{"t":59,"s":[{"i":[[-6.917,3.879],[0,-0.716],[39.672,0],[0,30.227],[-39.672,0],[-10.43,-4.012],[0,0],[-6.028,0]],"o":[[0,0],[0,30.227],[-39.672,0],[0,-30.227],[12.077,0],[0,0],[5.313,2.033],[8.494,0]],"v":[[159.452,6.555],[160.007,103.453],[84.753,158.183],[16.341,103.453],[84.753,48.723],[118.958,55.005],[118.955,9.499],[136.063,12.646]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":181,"st":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"L","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-58.912,2.378,0],"ix":2},"a":{"a":0,"k":[-58.912,2.378,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0,"y":0.751},"o":{"x":0.05,"y":0},"t":13,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.321],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[118.79,-191.298],[119.935,-149.636],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.627,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"i":{"x":0.564,"y":1},"o":{"x":0.514,"y":0.128},"t":32,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.192,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[54.288,-183.407],[54.277,-141.529],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.627,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]},{"t":59,"s":[{"i":[[0,0],[0,0],[0,0],[0.171,-0.721],[0,-0.687],[39.672,0],[0,30.227],[-39.672,0],[-9.268,-3.322],[0,0],[-19.193,4.657]],"o":[[0,0],[0,0],[-0.752,0.152],[0,0],[0,30.227],[-39.672,0],[0,-30.227],[10.92,0],[0,0],[0,-19.896],[0,0]],"v":[[88.175,-187.632],[88.165,-145.754],[-61.03,-115.682],[-62.53,-114.233],[-62.334,137.659],[-134.167,192.389],[-206,137.659],[-134.167,82.929],[-103.628,88.107],[-103.629,-113.786],[-70.799,-155.552]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":1,"op":179,"st":-1,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 276e60d26f..3c52b0940a 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -260,7 +260,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private let temporaryHiddenGalleryMediaDisposable = MetaDisposable() private let chatBackgroundNode: WallpaperBackgroundNode - private var controllerInteraction: ChatControllerInteraction? + private(set) var controllerInteraction: ChatControllerInteraction? private var interfaceInteraction: ChatPanelInterfaceInteraction? private let messageContextDisposable = MetaDisposable() @@ -5679,7 +5679,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self, case let .message(index) = toIndex { if case let .message(messageSubject, _, _) = strongSelf.subject, initial, case let .id(messageId) = messageSubject, messageId != index.id { if messageId.peerId == index.id.peerId { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(text: strongSelf.presentationData.strings.Conversation_MessageDoesntExist), elevatedLayout: false, action: { _ in return true }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(title: nil, text: strongSelf.presentationData.strings.Conversation_MessageDoesntExist), elevatedLayout: false, action: { _ in return true }), in: .current) } } else if let controllerInteraction = strongSelf.controllerInteraction { if let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(index.id) { @@ -8168,7 +8168,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G presentAddMembers(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, parentController: strongSelf, groupPeer: peer, selectAddMemberDisposable: strongSelf.selectAddMemberDisposable, addMemberDisposable: strongSelf.addMemberDisposable) }, presentGigagroupHelp: { [weak self] in if let strongSelf = self { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(text: strongSelf.presentationData.strings.Conversation_GigagroupDescription), elevatedLayout: false, action: { _ in return true }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(title: nil, text: strongSelf.presentationData.strings.Conversation_GigagroupDescription), elevatedLayout: false, action: { _ in return true }), in: .current) } }, editMessageMedia: { [weak self] messageId, draw in if let strongSelf = self { @@ -8295,6 +8295,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G })) }) } + }, chatController: { [weak self] in + return self }, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get())) do { @@ -9074,7 +9076,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center) let controller = richTextAlertController(context: strongSelf.context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: { - strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(text: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_SettingsTip), elevatedLayout: false, action: { _ in return false }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .info(title: nil, text: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_SettingsTip), elevatedLayout: false, action: { _ in return false }), in: .current) }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.BroadcastGroups_LimitAlert_LearnMore, action: { let context = strongSelf.context @@ -15387,18 +15389,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } - let controller = peerAutoremoveSetupScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peerId: peer.id, completion: { [weak self] updatedValue in - if case let .updated(value) = updatedValue { + let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peerId: peer.id, style: .default, mode: .autoremove, currentTime: self.presentationInterfaceState.autoremoveTimeout, dismissByTapOutside: true, completion: { [weak self] value in + guard let strongSelf = self else { + return + } + + let _ = (strongSelf.context.engine.peers.setChatMessageAutoremoveTimeoutInteractively(peerId: peer.id, timeout: value == 0 ? nil : value) + |> deliverOnMainQueue).start(completed: { guard let strongSelf = self else { return } - strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) }) - var isOn: Bool = true var text: String? - if let myValue = value.value { - text = strongSelf.presentationData.strings.Conversation_AutoremoveChanged("\(timeIntervalString(strings: strongSelf.presentationData.strings, value: myValue))").string + if value != 0 { + text = strongSelf.presentationData.strings.Conversation_AutoremoveChanged("\(timeIntervalString(strings: strongSelf.presentationData.strings, value: value))").string } else { isOn = false text = strongSelf.presentationData.strings.Conversation_AutoremoveOff @@ -15406,10 +15411,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let text = text { strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), in: .current) } - } + }) }) self.chatDisplayNode.dismissInput() - self.push(controller) + self.present(controller, in: .window(.root)) } private func presentChatRequestAdminInfo() { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 8e9edf862f..b34e44e06b 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -29,6 +29,7 @@ import TranslateUI import DebugSettingsUI import ChatPresentationInterfaceState import Pasteboard +import SettingsUI private struct MessageContextMenuData { let starStatus: Bool? @@ -819,51 +820,6 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } f(.default) }))) - - if resourceAvailable { - for media in message.media { - if let file = media as? TelegramMediaFile, (["audio/mp3", "audio/mpeg3"] as [String]).contains(file.mimeType.lowercased()) { - actions.append(.action(ContextMenuActionItem(text: "Set as Message Tone", icon: { _ in - return nil - }, action: { _, f in - for media in message.media { - if let file = media as? TelegramMediaFile { - let _ = (context.account.postbox.mediaBox.resourceData(file.resource, option: .incremental(waitUntilFetchStatus: false)) - |> take(1) - |> deliverOnMainQueue).start(next: { data in - if data.complete { - let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0] - let soundsDirectoryPath = documentsDirectoryPath + "/Sounds" - - let _ = try? FileManager.default.createDirectory(atPath: soundsDirectoryPath, withIntermediateDirectories: true, attributes: nil) - - let containerSoundsPath = context.sharedContext.applicationBindings.containerPath + "/Library/Sounds" - - let _ = try? FileManager.default.createDirectory(atPath: containerSoundsPath, withIntermediateDirectories: true, attributes: nil) - - let soundFileName = "\(UInt32.random(in: 0 ..< UInt32.max)).mp3" - let soundPath = soundsDirectoryPath + "/\(soundFileName)" - - let _ = try? FileManager.default.copyItem(atPath: data.path, toPath: soundPath) - let _ = try? FileManager.default.copyItem(atPath: data.path, toPath: "\(containerSoundsPath)/\(soundFileName)") - - let _ = updateInAppNotificationSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in - var settings = settings - - settings.customSound = soundFileName - - return settings - }).start() - } - }) - } - } - - f(.default) - }))) - } - } - } } let (canTranslate, _) = canTranslateText(context: context, text: messageText, showTranslate: translationSettings.showTranslate, ignoredLanguages: translationSettings.ignoredLanguages) @@ -914,6 +870,54 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } } + for media in message.media { + if let file = media as? TelegramMediaFile, let size = file.size, size < 200 * 1024, (["audio/mpeg", "audio/mp3", "audio/mpeg3"] as [String]).contains(file.mimeType.lowercased()) { + actions.append(.action(ContextMenuActionItem(text: "Save for Notifications", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/DownloadTone"), color: theme.actionSheet.primaryTextColor) + }, action: { _, f in + let _ = context.engine.peers.saveNotificationSound(file: file).start(completed: { + //TODO:localize + controllerInteraction.displayUndo(.notificationSoundAdded(title: "Sound added", text: "You can now use this sound as a notification tone in your [custom notification settings]().", action: { + controllerInteraction.navigationController()?.pushViewController(notificationsAndSoundsController(context: context, exceptionsList: nil)) + })) + }) + + f(.default) + }))) + + /* + + let _ = (context.account.postbox.mediaBox.resourceData(file.resource, option: .incremental(waitUntilFetchStatus: false)) + |> take(1) + |> deliverOnMainQueue).start(next: { data in + if data.complete { + let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.libraryDirectory, .userDomainMask, true)[0] + let soundsDirectoryPath = documentsDirectoryPath + "/Sounds" + + let _ = try? FileManager.default.createDirectory(atPath: soundsDirectoryPath, withIntermediateDirectories: true, attributes: nil) + + let containerSoundsPath = context.sharedContext.applicationBindings.containerPath + "/Library/Sounds" + + let _ = try? FileManager.default.createDirectory(atPath: containerSoundsPath, withIntermediateDirectories: true, attributes: nil) + + let soundFileName = "\(UInt32.random(in: 0 ..< UInt32.max)).mp3" + let soundPath = soundsDirectoryPath + "/\(soundFileName)" + + let _ = try? FileManager.default.copyItem(atPath: data.path, toPath: soundPath) + let _ = try? FileManager.default.copyItem(atPath: data.path, toPath: "\(containerSoundsPath)/\(soundFileName)") + + let _ = updateInAppNotificationSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in + var settings = settings + + settings.customSound = soundFileName + + return settings + }).start() + } + })*/ + } + } + var downloadableMediaResourceInfos: [String] = [] for media in message.media { if let file = media as? TelegramMediaFile { diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index 6232a0844f..be1ebaf1c4 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -55,6 +55,9 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { private let textNode: TextNode private var spoilerTextNode: TextNode? private var dustNode: InvisibleInkDustNode? + private let actionButton: HighlightableButtonNode + private let actionButtonTitleNode: ImmediateTextNode + private let actionButtonBackgroundNode: ASImageNode private let imageNode: TransformImageNode private let imageNodeContainer: ASDisplayNode @@ -93,6 +96,14 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0) self.closeButton.displaysAsynchronously = false + self.actionButton = HighlightableButtonNode() + self.actionButton.isHidden = true + self.actionButtonTitleNode = ImmediateTextNode() + self.actionButtonTitleNode.isHidden = true + self.actionButtonBackgroundNode = ASImageNode() + self.actionButtonBackgroundNode.isHidden = true + self.actionButtonBackgroundNode.displaysAsynchronously = false + self.listButton = HighlightableButtonNode() self.listButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0) self.listButton.displaysAsynchronously = false @@ -153,8 +164,21 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { } } + self.actionButton.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.actionButton.layer.removeAnimation(forKey: "opacity") + strongSelf.actionButton.alpha = 0.4 + } else { + strongSelf.actionButton.alpha = 1.0 + strongSelf.actionButton.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside]) self.listButton.addTarget(self, action: #selector(self.listPressed), forControlEvents: [.touchUpInside]) + self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: [.touchUpInside]) self.addSubnode(self.contextContainer) @@ -168,6 +192,9 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.imageNodeContainer.addSubnode(self.imageNode) self.contentContainer.addSubnode(self.imageNodeContainer) + self.actionButton.addSubnode(self.actionButtonBackgroundNode) + self.actionButton.addSubnode(self.actionButtonTitleNode) + self.buttonsContainer.addSubnode(self.actionButton) self.buttonsContainer.addSubnode(self.closeButton) self.buttonsContainer.addSubnode(self.listButton) self.contextContainer.addSubnode(self.buttonsContainer) @@ -207,6 +234,8 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(interfaceState.theme), for: []) self.listButton.setImage(PresentationResourcesChat.chatInputPanelPinnedListIconImage(interfaceState.theme), for: []) self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor + + self.actionButtonBackgroundNode.image = generateStretchableFilledCircleImage(diameter: 14.0 * 2.0, color: interfaceState.theme.list.itemCheckColors.fillColor, strokeColor: nil, strokeWidth: nil, backgroundColor: nil) } if self.statusDisposable == nil, let interfaceInteraction = self.interfaceInteraction, let statuses = interfaceInteraction.statuses { @@ -259,6 +288,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.contextContainer.isGestureEnabled = !isReplyThread + var actionTitle: String? var messageUpdated = false var messageUpdatedAnimation: PinnedMessageAnimation? if let currentMessage = self.currentMessage, let pinnedMessage = interfaceState.pinnedMessage { @@ -286,6 +316,16 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { } } + if let currentMessage = self.currentMessage { + for attribute in currentMessage.message.attributes { + if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), attribute.rows.count == 1, attribute.rows[0].buttons.count == 1 { + actionTitle = attribute.rows[0].buttons[0].title + } + } + } else { + actionTitle = nil + } + if isReplyThread { self.closeButton.isHidden = true self.listButton.isHidden = true @@ -302,12 +342,34 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.closeButton.isHidden = true } - let rightInset: CGFloat = 18.0 + rightInset + var rightInset: CGFloat = 18.0 + rightInset let buttonsContainerSize = CGSize(width: 16.0, height: panelHeight) self.buttonsContainer.frame = CGRect(origin: CGPoint(x: width - buttonsContainerSize.width - rightInset, y: 0.0), size: buttonsContainerSize) let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0)) + + if let actionTitle = actionTitle { + self.actionButton.isHidden = false + self.actionButtonBackgroundNode.isHidden = false + self.actionButtonTitleNode.isHidden = false + + self.actionButtonTitleNode.attributedText = NSAttributedString(string: actionTitle, font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: interfaceState.theme.list.itemCheckColors.foregroundColor) + + let actionButtonTitleSize = self.actionButtonTitleNode.updateLayout(CGSize(width: 150.0, height: .greatestFiniteMagnitude)) + let actionButtonSize = CGSize(width: actionButtonTitleSize.width + 20.0, height: 28.0) + let actionButtonFrame = CGRect(origin: CGPoint(x: (buttonsContainerSize.width - closeButtonSize.width + 1.0) - 8.0 - actionButtonSize.width, y: floor((panelHeight - actionButtonSize.height) / 2.0)), size: actionButtonSize) + transition.updateFrame(node: self.actionButton, frame: actionButtonFrame) + transition.updateFrame(node: self.actionButtonBackgroundNode, frame: CGRect(origin: CGPoint(), size: actionButtonFrame.size)) + transition.updateFrame(node: self.actionButtonTitleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((actionButtonFrame.width - actionButtonTitleSize.width) / 2.0), y: floorToScreenPixels((actionButtonFrame.height - actionButtonTitleSize.height) / 2.0)), size: actionButtonTitleSize)) + + rightInset += actionButtonSize.width + 8.0 + } else { + self.actionButton.isHidden = true + self.actionButtonBackgroundNode.isHidden = true + self.actionButtonTitleNode.isHidden = true + } + transition.updateFrame(node: self.closeButton, frame: CGRect(origin: CGPoint(x: buttonsContainerSize.width - closeButtonSize.width + 1.0, y: 19.0), size: closeButtonSize)) let listButtonSize = self.listButton.measure(CGSize(width: 100.0, height: 100.0)) @@ -323,7 +385,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { self.clippingContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) self.contentContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)) - if self.currentLayout?.0 != width || self.currentLayout?.1 != leftInset || self.currentLayout?.2 != rightInset { + if self.currentLayout?.0 != width || self.currentLayout?.1 != leftInset || self.currentLayout?.2 != rightInset || messageUpdated { self.currentLayout = (width, leftInset, rightInset) if let currentMessage = self.currentMessage { @@ -377,12 +439,17 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { targetQueue = self.queue } + let contentLeftInset: CGFloat = leftInset + 10.0 + var textLineInset: CGFloat = 10.0 + var rightInset: CGFloat = 18.0 + rightInset + + let textRightInset: CGFloat = 0.0 + + if !self.actionButton.isHidden { + rightInset += self.actionButton.bounds.width + 8.0 + } + targetQueue.async { [weak self] in - let contentLeftInset: CGFloat = leftInset + 10.0 - var textLineInset: CGFloat = 10.0 - let rightInset: CGFloat = 18.0 + rightInset - let textRightInset: CGFloat = 0.0 - var updatedMediaReference: AnyMediaReference? var imageDimensions: CGSize? @@ -610,4 +677,63 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { interfaceInteraction.openPinnedList(message.message.id) } } + + @objc private func actionButtonPressed() { + if let interfaceInteraction = self.interfaceInteraction, let controller = interfaceInteraction.chatController() as? ChatControllerImpl, let controllerInteraction = controller.controllerInteraction, let message = self.currentMessage?.message { + for attribute in message.attributes { + if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), attribute.rows.count == 1, attribute.rows[0].buttons.count == 1 { + let button = attribute.rows[0].buttons[0] + switch button.action { + case .text: + controllerInteraction.sendMessage(button.title) + case let .url(url): + controllerInteraction.openUrl(url, true, nil, nil) + case .requestMap: + controllerInteraction.shareCurrentLocation() + case .requestPhone: + controllerInteraction.shareAccountContact() + case .openWebApp: + controllerInteraction.requestMessageActionCallback(message.id, nil, true, false) + case let .callback(requiresPassword, data): + controllerInteraction.requestMessageActionCallback(message.id, data, false, requiresPassword) + case let .switchInline(samePeer, query): + var botPeer: Peer? + + var found = false + for attribute in message.attributes { + if let attribute = attribute as? InlineBotMessageAttribute { + if let peerId = attribute.peerId { + botPeer = message.peers[peerId] + found = true + } + } + } + if !found { + botPeer = message.author + } + + var peerId: PeerId? + if samePeer { + peerId = message.id.peerId + } + if let botPeer = botPeer, let addressName = botPeer.addressName { + controllerInteraction.activateSwitchInline(peerId, "@\(addressName) \(query)") + } + case .payment: + controllerInteraction.openCheckoutOrReceipt(message.id) + case let .urlAuth(url, buttonId): + controllerInteraction.requestMessageActionUrlAuth(url, .message(id: message.id, buttonId: buttonId)) + case .setupPoll: + break + case let .openUserProfile(peerId): + controllerInteraction.openPeer(peerId, .info, nil, nil) + case let .openWebView(url, simple): + controllerInteraction.openWebView(button.title, url, simple) + } + + break + } + } + } + } } diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsController.swift b/submodules/TelegramUI/Sources/ChatRecentActionsController.swift index 309fc63e88..72ffda7e53 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsController.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsController.swift @@ -151,6 +151,8 @@ final class ChatRecentActionsController: TelegramBaseController { }, openSendAsPeer: { _, _ in }, presentChatRequestAdminInfo: { }, displayCopyProtectionTip: { _, _ in + }, chatController: { + return nil }, statuses: nil) self.navigationItem.titleView = self.titleView diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift index 570e22b647..098863dbb5 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsControllerNode.swift @@ -946,27 +946,31 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { } private func presentAutoremoveSetup() { - let peer = self.peer - - let controller = peerAutoremoveSetupScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: peer.id, completion: { [weak self] updatedValue in - if case let .updated(value) = updatedValue { + /*let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peer.id, style: .default, mode: .autoremove, currentTime: currentValue, dismissByTapOutside: true, completion: { [weak self] value in + guard let strongSelf = self else { + return + } + + let _ = (strongSelf.context.engine.peers.setChatMessageAutoremoveTimeoutInteractively(peerId: strongSelf.peer.id, timeout: value == 0 ? nil : value) + |> deliverOnMainQueue).start(completed: { guard let strongSelf = self else { return } var isOn: Bool = true var text: String? - if let myValue = value.value { - text = strongSelf.presentationData.strings.Conversation_AutoremoveChanged("\(timeIntervalString(strings: strongSelf.presentationData.strings, value: myValue))").string + if value != 0 { + text = strongSelf.presentationData.strings.Conversation_AutoremoveChanged("\(timeIntervalString(strings: strongSelf.presentationData.strings, value: value))").string } else { isOn = false text = strongSelf.presentationData.strings.Conversation_AutoremoveOff } if let text = text { - strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), .current, nil) + strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), in: .current) } - } + }) }) - self.pushController(controller) + self.view.endEditing(true) + self.present(controller, in: .window(.root))*/ } } diff --git a/submodules/TelegramUI/Sources/ChatTimerScreen.swift b/submodules/TelegramUI/Sources/ChatTimerScreen.swift index 673a50af85..034888d56f 100644 --- a/submodules/TelegramUI/Sources/ChatTimerScreen.swift +++ b/submodules/TelegramUI/Sources/ChatTimerScreen.swift @@ -273,6 +273,10 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi private let cancelButton: HighlightableButtonNode private let doneButton: SolidRoundedButtonNode + private let disableButton: HighlightableButtonNode + private let disableButtonTitle: ImmediateTextNode + + private var initialTime: Int32? private var pickerView: TimerPickerView? private var containerLayout: (ContainerViewLayout, CGFloat)? @@ -287,6 +291,7 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi self.presentationData = presentationData self.dismissByTapOutside = dismissByTapOutside self.mode = mode + self.initialTime = currentTime self.wrappingScrollNode = ASScrollNode() self.wrappingScrollNode.view.alwaysBounceVertical = true @@ -349,6 +354,22 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false) self.doneButton.title = self.presentationData.strings.Conversation_Timer_Send + self.disableButton = HighlightableButtonNode() + self.disableButtonTitle = ImmediateTextNode() + self.disableButton.addSubnode(self.disableButtonTitle) + //TODO:localize + self.disableButtonTitle.attributedText = NSAttributedString(string: "Disable Auto-Delete", font: Font.regular(17.0), textColor: self.presentationData.theme.list.itemAccentColor) + self.disableButton.isHidden = true + + switch self.mode { + case .autoremove: + if self.initialTime != nil { + self.disableButton.isHidden = false + } + default: + break + } + super.init() self.backgroundColor = nil @@ -369,17 +390,24 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi self.contentContainerNode.addSubnode(self.textNode) self.contentContainerNode.addSubnode(self.cancelButton) self.contentContainerNode.addSubnode(self.doneButton) + self.contentContainerNode.addSubnode(self.disableButton) self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside) self.doneButton.pressed = { [weak self] in if let strongSelf = self, let pickerView = strongSelf.pickerView { strongSelf.doneButton.isUserInteractionEnabled = false if let pickerView = pickerView as? TimerCustomPickerView { - strongSelf.completion?(timerValues[pickerView.selectedRow(inComponent: 0)]) + switch strongSelf.mode { + case .sendTimer: + strongSelf.completion?(timerValues[pickerView.selectedRow(inComponent: 0)]) + case .autoremove: + let timeInterval = pickerView.selectedRow(inComponent: 0) * 24 * 60 * 60 + pickerView.selectedRow(inComponent: 1) * 60 * 60 + pickerView.selectedRow(inComponent: 2) * 60 + strongSelf.completion?(Int32(timeInterval)) + case .mute: + break + } } else if let pickerView = pickerView as? TimerDatePickerView { switch strongSelf.mode { - case .autoremove: - strongSelf.completion?(Int32(pickerView.countDownDuration)) case .mute: let timeInterval = max(0, Int32(pickerView.date.timeIntervalSince1970) - Int32(Date().timeIntervalSince1970)) strongSelf.completion?(timeInterval) @@ -390,9 +418,15 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi } } + self.disableButton.addTarget(self, action: #selector(self.disableButtonPressed), forControlEvents: .touchUpInside) + self.setupPickerView(currentTime: currentTime) } + @objc private func disableButtonPressed() { + self.completion?(0) + } + func setupPickerView(currentTime: Int32? = nil) { if let pickerView = self.pickerView { pickerView.removeFromSuperview() @@ -408,17 +442,24 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi self.contentContainerNode.view.addSubview(pickerView) self.pickerView = pickerView case .autoremove: - let pickerView = TimerDatePickerView() - pickerView.locale = localeWithStrings(self.presentationData.strings) - pickerView.datePickerMode = .countDownTimer - if #available(iOS 13.4, *) { - pickerView.preferredDatePickerStyle = .wheels - } - pickerView.selectorColor = UIColor(rgb: 0xffffff, alpha: 0.18) - pickerView.addTarget(self, action: #selector(self.dataPickerChanged), for: .valueChanged) + let pickerView = TimerCustomPickerView() + pickerView.dataSource = self + pickerView.delegate = self + + pickerView.selectorColor = self.presentationData.theme.list.itemPrimaryTextColor.withMultipliedAlpha(0.18) self.contentContainerNode.view.addSubview(pickerView) self.pickerView = pickerView + + if let value = self.initialTime { + let days = value / (24 * 60 * 60) + let hours = (value % (24 * 60 * 60)) / (60 * 60) + let minutes = (value % (60 * 60)) / 60 + + pickerView.selectRow(Int(days), inComponent: 0, animated: false) + pickerView.selectRow(Int(hours), inComponent: 1, animated: false) + pickerView.selectRow(Int(minutes), inComponent: 2, animated: false) + } case .mute: let pickerView = TimerDatePickerView() pickerView.locale = localeWithStrings(self.presentationData.strings) @@ -436,35 +477,87 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi } @objc private func dataPickerChanged() { - guard let _ = self.pickerView as? TimerDatePickerView else { - return - } - if let (layout, navigationBarHeight) = self.containerLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) } } func numberOfComponents(in pickerView: UIPickerView) -> Int { - return 1 + switch self.mode { + case .sendTimer: + return 1 + case .autoremove: + return 3 + case .mute: + return 0 + } } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - return timerValues.count + switch self.mode { + case .sendTimer: + return timerValues.count + case .autoremove: + switch component { + case 0: + return 365 + case 1: + return 24 + case 2: + return 60 + default: + return 0 + } + case .mute: + return 0 + } } func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView { - let value = timerValues[row] - let string = timeIntervalString(strings: self.presentationData.strings, value: value) - if let view = view as? TimerPickerItemView { + switch self.mode { + case .sendTimer: + let value = timerValues[row] + let string = timeIntervalString(strings: self.presentationData.strings, value: value) + if let view = view as? TimerPickerItemView { + view.value = (value, string) + return view + } + + let view = TimerPickerItemView() view.value = (value, string) + view.textColor = .white return view + case .autoremove: + let itemView: TimerPickerItemView + if let current = view as? TimerPickerItemView { + itemView = current + } else { + itemView = TimerPickerItemView() + itemView.textColor = self.presentationData.theme.list.itemPrimaryTextColor + } + + let string: String + switch component { + case 0: + string = dayIntervalString(strings: self.presentationData.strings, days: Int32(row)) + case 1: + string = hoursIntervalString(strings: self.presentationData.strings, hours: Int32(row)) + case 2: + string = minutesIntervalString(strings: self.presentationData.strings, minutes: Int32(row)) + default: + preconditionFailure() + } + + itemView.value = (Int32(row), string) + + return itemView + case .mute: + preconditionFailure() } - - let view = TimerPickerItemView() - view.value = (value, string) - view.textColor = .white - return view + } + + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + self.dataPickerChanged() } func updatePresentationData(_ presentationData: PresentationData) { @@ -575,11 +668,16 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi let cleanInsets = layout.insets(options: [.statusBar]) insets.top = max(10.0, insets.top) - let buttonOffset: CGFloat = 0.0 + var buttonOffset: CGFloat = 0.0 let bottomInset: CGFloat = 10.0 + cleanInsets.bottom let titleHeight: CGFloat = 54.0 var contentHeight = titleHeight + bottomInset + 52.0 + 17.0 let pickerHeight: CGFloat = min(216.0, layout.size.height - contentHeight) + + if !self.disableButton.isHidden { + buttonOffset += 52.0 + } + contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + pickerHeight + buttonOffset let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 0.0) @@ -612,11 +710,8 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi case .sendTimer: break case .autoremove: - if let pickerView = self.pickerView as? TimerDatePickerView, pickerView.countDownDuration > 0.0 { - self.doneButton.title = "Auto-Delete after \(timeIntervalString(strings: self.presentationData.strings, value: Int32(pickerView.countDownDuration)))" - } else { - self.doneButton.title = self.presentationData.strings.Common_Close - } + //TODO:localize + self.doneButton.title = "Set Auto-Delete" case .mute: if let pickerView = self.pickerView as? TimerDatePickerView { let timeInterval = max(0, Int32(pickerView.date.timeIntervalSince1970) - Int32(Date().timeIntervalSince1970)) @@ -635,7 +730,13 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi } let doneButtonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition) - transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 16.0 - buttonOffset, width: contentFrame.width, height: doneButtonHeight)) + let doneButtonFrame = CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 16.0 - buttonOffset, width: contentFrame.width, height: doneButtonHeight) + transition.updateFrame(node: self.doneButton, frame: doneButtonFrame) + + let disableButtonTitleSize = self.disableButtonTitle.updateLayout(CGSize(width: contentFrame.width, height: doneButtonHeight)) + let disableButtonFrame = CGRect(origin: CGPoint(x: doneButtonFrame.minX, y: doneButtonFrame.maxY), size: CGSize(width: contentFrame.width - buttonInset * 2.0, height: doneButtonHeight)) + transition.updateFrame(node: self.disableButton, frame: disableButtonFrame) + transition.updateFrame(node: self.disableButtonTitle, frame: CGRect(origin: CGPoint(x: floor((disableButtonFrame.width - disableButtonTitleSize.width) / 2.0), y: floor((disableButtonFrame.height - disableButtonTitleSize.height) / 2.0)), size: disableButtonTitleSize)) self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight)) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 7b0e385b7b..08b236937c 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -346,6 +346,8 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode { }, presentChatRequestAdminInfo: { }, displayCopyProtectionTip: { node, save in displayCopyProtectionTip(node, save) + }, chatController: { + return nil }, statuses: nil) self.selectionPanel.interfaceInteraction = interfaceInteraction @@ -3540,6 +3542,42 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate var items: [ContextMenuItem] = [] + var isSoundEnabled = true + if let notificationSettings = self.data?.notificationSettings { + switch notificationSettings.messageSound { + case .none: + isSoundEnabled = false + default: + break + } + } + + if !isSoundEnabled { + //TODO:localize + items.append(.action(ContextMenuActionItem(text: "Enable Sound", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + + guard let strongSelf = self else { + return + } + let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .default).start() + }))) + } else { + //TODO:localize + items.append(.action(ContextMenuActionItem(text: "Disable Sound", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + + guard let strongSelf = self else { + return + } + let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .none).start() + }))) + } + items.append(.action(ContextMenuActionItem(text: "Mute for...", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Mute2d"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, _ in @@ -3586,59 +3624,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate c.pushItems(items: .single(ContextController.Items(content: .list(subItems)))) }))) - - items.append(.separator) - - var isSoundEnabled = true - if let notificationSettings = self.data?.notificationSettings { - switch notificationSettings.messageSound { - case .none: - isSoundEnabled = false - default: - break - } - } //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Sound On", icon: { theme in - if !isSoundEnabled { - return nil - } - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let strongSelf = self else { - return - } - if isSoundEnabled { - return - } - let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .default).start() - }))) - - //TODO:localize - items.append(.action(ContextMenuActionItem(text: "Sound Off", icon: { theme in - if isSoundEnabled { - return nil - } - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let strongSelf = self else { - return - } - if !isSoundEnabled { - return - } - let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: strongSelf.peerId, sound: .none).start() - }))) - - items.append(.separator) - items.append(.action(ContextMenuActionItem(text: "Customize", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Settings"), color: theme.contextMenu.primaryColor) + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Customize"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) @@ -3738,16 +3727,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate canChangeColors = true } - if canChangeColors { - items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_ChangeColors, icon: { theme in - generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor) - }, action: { _, f in - f(.dismissWithoutContent) - - self?.openChatForThemeChange() - }))) - } - var currentAutoremoveTimeout: Int32? if let cachedData = data.cachedData as? CachedUserData { switch cachedData.autoremoveTimeout { @@ -3979,26 +3958,38 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } }))) } + + if canChangeColors { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_ChangeColors, icon: { theme in + generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor) + }, action: { _, f in + f(.dismissWithoutContent) + + self?.openChatForThemeChange() + }))) + } if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser && user.botInfo == nil && !user.flags.contains(.isSupport) { items.append(.action(ContextMenuActionItem(text: presentationData.strings.UserInfo_StartSecretChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Timer"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in + }, action: { _, f in f(.dismissWithoutContent) self?.openStartSecretChat() }))) } - /*if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser { - items.append(.action(ContextMenuActionItem(text: "", icon: { theme in - generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.dismissWithoutContent) - - self?.openStartSecretChat() - }))) - }*/ + let clearPeerHistory = ClearPeerHistory(context: strongSelf.context, peer: user, chatPeer: user, cachedData: strongSelf.data?.cachedData) + if clearPeerHistory.canClearForMyself != nil || clearPeerHistory.canClearForEveryone != nil { + if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser { + //TODO:localize + items.append(.action(ContextMenuActionItem(text: "Clear Messages", icon: { theme in + generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: user, chatPeer: user) + }))) + } + } if strongSelf.peerId.namespace == Namespaces.Peer.CloudUser && user.botInfo == nil && !user.flags.contains(.isSupport) { if data.isContact { @@ -4006,7 +3997,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } else { items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_BlockUser, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.contextMenu.destructiveColor) - }, action: { [weak self] _, f in + }, action: { _, f in f(.dismissWithoutContent) self?.updateBlocked(block: true) @@ -4058,6 +4049,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }))) } + let clearPeerHistory = ClearPeerHistory(context: strongSelf.context, peer: channel, chatPeer: channel, cachedData: strongSelf.data?.cachedData) + if clearPeerHistory.canClearForMyself != nil || clearPeerHistory.canClearForEveryone != nil { + //TODO:localize + items.append(.action(ContextMenuActionItem(text: "Clear Messages", icon: { theme in + generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: channel, chatPeer: channel) + }))) + } + switch channel.info { case .broadcast: if case .member = channel.participationStatus, !headerButtons.contains(.leave) { @@ -4087,6 +4088,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } } else if let group = peer as? TelegramGroup { + let clearPeerHistory = ClearPeerHistory(context: strongSelf.context, peer: group, chatPeer: group, cachedData: strongSelf.data?.cachedData) + if clearPeerHistory.canClearForMyself != nil || clearPeerHistory.canClearForEveryone != nil { + //TODO:localize + items.append(.action(ContextMenuActionItem(text: "Clear Messages", icon: { theme in + generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ClearMessages"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + self?.openClearHistory(contextController: c, clearPeerHistory: clearPeerHistory, peer: group, chatPeer: group) + }))) + } + if case .Member = group.membership, !headerButtons.contains(.leave) { if !items.isEmpty { items.append(.separator) @@ -4162,28 +4173,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } private func openAutoremove(currentValue: Int32?) { - /*let controller = peerAutoremoveSetupScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, completion: { [weak self] updatedValue in - if case let .updated(value) = updatedValue { - guard let strongSelf = self else { - return - } - - var isOn: Bool = true - var text: String? - if let myValue = value.value { - text = strongSelf.presentationData.strings.Conversation_AutoremoveChanged("\(timeIntervalString(strings: strongSelf.presentationData.strings, value: myValue))").string - } else { - isOn = false - text = strongSelf.presentationData.strings.Conversation_AutoremoveOff - } - if let text = text { - strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .autoDelete(isOn: isOn, title: nil, text: text), elevatedLayout: false, action: { _ in return false }), in: .current) - } - } - }) - self.controller?.view.endEditing(true) - self.controller?.push(controller)*/ - let controller = ChatTimerScreen(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, peerId: self.peerId, style: .default, mode: .autoremove, currentTime: currentValue, dismissByTapOutside: true, completion: { [weak self] value in guard let strongSelf = self else { return @@ -4340,6 +4329,94 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }) } + private func openClearHistory(contextController: ContextControllerProtocol, clearPeerHistory: ClearPeerHistory, peer: Peer, chatPeer: Peer) { + var subItems: [ContextMenuItem] = [] + + subItems.append(.action(ContextMenuActionItem(text: self.presentationData.strings.Common_Back, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor) + }, action: { c, _ in + c.popItems() + }))) + subItems.append(.separator) + + //TODO:localize + + guard let anyType = clearPeerHistory.canClearForEveryone ?? clearPeerHistory.canClearForMyself else { + return + } + + let title: String + switch anyType { + case .user, .secretChat, .savedMessages: + title = "Are you sure you want to delete all messages with \(EnginePeer(chatPeer).compactDisplayTitle)?" + case .group, .channel: + title = "Are you sure you want to delete all messages in \(EnginePeer(chatPeer).compactDisplayTitle)?" + } + + subItems.append(.action(ContextMenuActionItem(text: title, textLayout: .multiline, textFont: .small, icon: { _ in + return nil + }, action: nil as ((ContextControllerProtocol, @escaping (ContextMenuActionResult) -> Void) -> Void)?))) + + let beginClear: (InteractiveHistoryClearingType) -> Void = { [weak self] type in + guard let strongSelf = self else { + return + } + let statusText: String + if case .forEveryone = type { + statusText = strongSelf.presentationData.strings.Undo_ChatClearedForBothSides + } else { + statusText = strongSelf.presentationData.strings.Undo_ChatCleared + } + + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(text: statusText), elevatedLayout: false, action: { value in + if value == .commit { + guard let strongSelf = self else { + return false + } + + let _ = strongSelf.context.engine.messages.clearHistoryInteractively(peerId: peer.id, type: type).start(completed: { + }) + return true + } else if value == .undo { + return true + } + return false + }), in: .current) + } + + if let canClearForEveryone = clearPeerHistory.canClearForEveryone { + let text: String + switch canClearForEveryone { + case .user, .secretChat, .savedMessages: + text = self.presentationData.strings.Conversation_DeleteMessagesFor(EnginePeer(chatPeer).compactDisplayTitle).string + case .channel, .group: + text = self.presentationData.strings.Conversation_DeleteMessagesForEveryone + } + + subItems.append(.action(ContextMenuActionItem(text: text, textColor: .destructive, icon: { _ in + return nil + }, action: { _, f in + f(.default) + + beginClear(.forEveryone) + }))) + } + + if let _ = clearPeerHistory.canClearForMyself { + let text: String = self.presentationData.strings.Conversation_DeleteMessagesForMe + + subItems.append(.action(ContextMenuActionItem(text: text, textColor: .destructive, icon: { _ in + return nil + }, action: { _, f in + f(.default) + + beginClear(.forLocalPeer) + }))) + } + + contextController.pushItems(items: .single(ContextController.Items(content: .list(subItems)))) + } + private func openUsername(value: String) { let shareController = ShareController(context: self.context, subject: .url("https://t.me/\(value)"), updatedPresentationData: self.controller?.updatedPresentationData) shareController.completed = { [weak self] peerIds in @@ -4541,16 +4618,19 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate private func editingOpenNotificationSettings() { let peerId = self.peerId - let _ = (self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in + let _ = (combineLatest(self.context.account.postbox.transaction { transaction -> (TelegramPeerNotificationSettings, GlobalNotificationSettings) in let peerSettings: TelegramPeerNotificationSettings = (transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings) ?? TelegramPeerNotificationSettings.defaultSettings let globalSettings: GlobalNotificationSettings = transaction.getPreferencesEntry(key: PreferencesKeys.globalNotifications)?.get(GlobalNotificationSettings.self) ?? GlobalNotificationSettings.defaultSettings return (peerSettings, globalSettings) - } - |> deliverOnMainQueue).start(next: { [weak self] peerSettings, globalSettings in + }, self.context.engine.peers.notificationSoundList()) + |> deliverOnMainQueue).start(next: { [weak self] settings, notificationSoundList in guard let strongSelf = self else { return } - let muteSettingsController = notificationMuteSettingsController(presentationData: strongSelf.presentationData, notificationSettings: globalSettings.effective.groupChats, soundSettings: nil, openSoundSettings: { + + let (peerSettings, globalSettings) = settings + + let muteSettingsController = notificationMuteSettingsController(presentationData: strongSelf.presentationData, notificationSoundList: notificationSoundList, notificationSettings: globalSettings.effective.groupChats, soundSettings: nil, openSoundSettings: { guard let strongSelf = self else { return } @@ -4660,7 +4740,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate |> deliverOnMainQueue).start(completed: { [weak self] in if let strongSelf = self, let peer = strongSelf.data?.peer { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } - let controller = UndoOverlayController(presentationData: presentationData, content: .info(text: presentationData.strings.Conversation_DeletedFromContacts(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }) + let controller = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.Conversation_DeletedFromContacts(EnginePeer(peer).displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).string), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }) controller.keepOnParentDismissal = true strongSelf.controller?.present(controller, in: .window(.root)) @@ -8480,3 +8560,73 @@ func presentAddMembers(context: AccountContext, updatedPresentationData: (initia } }) } + +struct ClearPeerHistory { + enum ClearType { + case savedMessages + case secretChat + case group + case channel + case user + } + + var canClearCache: Bool = false + var canClearForMyself: ClearType? = nil + var canClearForEveryone: ClearType? = nil + + init(context: AccountContext, peer: Peer, chatPeer: Peer, cachedData: CachedPeerData?) { + if peer.id == context.account.peerId { + canClearCache = false + canClearForMyself = .savedMessages + canClearForEveryone = nil + } else if chatPeer is TelegramSecretChat { + canClearCache = false + canClearForMyself = .secretChat + canClearForEveryone = nil + } else if let group = chatPeer as? TelegramGroup { + canClearCache = false + + switch group.role { + case .creator: + canClearForMyself = .group + canClearForEveryone = .group + case .admin, .member: + canClearForMyself = .group + canClearForEveryone = nil + } + } else if let channel = chatPeer as? TelegramChannel { + var canDeleteHistory = false + if let cachedData = cachedData as? CachedChannelData { + canDeleteHistory = cachedData.flags.contains(.canDeleteHistory) + } + + var canDeleteLocally = true + if case .broadcast = channel.info { + canDeleteLocally = false + } else if channel.username != nil { + canDeleteLocally = false + } + + if !canDeleteHistory { + canClearCache = true + + canClearForMyself = canDeleteLocally ? .channel : nil + canClearForEveryone = nil + } else { + canClearCache = true + canClearForMyself = canDeleteLocally ? .channel : nil + + canClearForEveryone = .channel + } + } else { + canClearCache = false + canClearForMyself = .user + + if let user = chatPeer as? TelegramUser, user.botInfo != nil { + canClearForEveryone = nil + } else { + canClearForEveryone = .user + } + } + } +} diff --git a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift index 3c399abdfb..87ee0cd833 100644 --- a/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/PeerSelectionControllerNode.swift @@ -347,6 +347,8 @@ final class PeerSelectionControllerNode: ASDisplayNode { }, openSendAsPeer: { _, _ in }, presentChatRequestAdminInfo: { }, displayCopyProtectionTip: { _, _ in + }, chatController: { + return nil }, statuses: nil) self.readyValue.set(self.chatListNode.ready) diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index a553b4bf25..07bc2a1cf2 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -23,6 +23,9 @@ #import "platform/darwin/VideoSampleBufferView.h" #import "platform/darwin/VideoCaptureView.h" #import "platform/darwin/CustomExternalCapturer.h" + +#include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" + #endif #import "group/GroupInstanceImpl.h" @@ -1039,9 +1042,11 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; [strongSelf signalingDataEmitted:mappedData]; } }]; + }, + .createAudioDeviceModule = [](webrtc::TaskQueueFactory *taskQueueFactory) -> rtc::scoped_refptr { + return rtc::make_ref_counted(false, false, 1); } }); - _state = OngoingCallStateInitializing; _signalBars = 4; } diff --git a/submodules/UndoUI/Sources/UndoOverlayController.swift b/submodules/UndoUI/Sources/UndoOverlayController.swift index 7a51adf24d..e4a4f49ee8 100644 --- a/submodules/UndoUI/Sources/UndoOverlayController.swift +++ b/submodules/UndoUI/Sources/UndoOverlayController.swift @@ -12,7 +12,7 @@ public enum UndoOverlayContent { case hidArchive(title: String, text: String, undo: Bool) case revealedArchive(title: String, text: String, undo: Bool) case succeed(text: String) - case info(text: String) + case info(title: String?, text: String) case emoji(name: String, text: String) case swipeToReply(title: String, text: String) case actionSucceeded(title: String, text: String, cancel: String) @@ -40,6 +40,7 @@ public enum UndoOverlayContent { case paymentSent(currencyValue: String, itemTitle: String) case inviteRequestSent(title: String, text: String) case image(image: UIImage, text: String) + case notificationSoundAdded(title: String, text: String, action: (() -> Void)?) } public enum UndoOverlayAction { diff --git a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift index b6a61b2ee6..72242fba8e 100644 --- a/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift +++ b/submodules/UndoUI/Sources/UndoOverlayControllerNode.swift @@ -167,13 +167,17 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.textNode.maximumNumberOfLines = 5 displayUndo = false self.originalRemainingSeconds = 3 - case let .info(text): + case let .info(title, text): self.avatarNode = nil self.iconNode = nil self.iconCheckNode = nil self.animationNode = AnimationNode(animation: "anim_infotip", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0) self.animatedStickerNode = nil + if let title = title { + self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white) + } + let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white) let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white) let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .natural) @@ -750,6 +754,32 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { self.textNode.maximumNumberOfLines = 2 displayUndo = false self.originalRemainingSeconds = 5 + case let .notificationSoundAdded(title, text, action): + self.avatarNode = nil + self.iconNode = nil + self.iconCheckNode = nil + self.animationNode = AnimationNode(animation: "anim_notificationsound", colors: [:], scale: 0.066) + self.animatedStickerNode = nil + self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white) + + + let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white) + let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white) + let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor) + let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return nil }), textAlignment: .natural) + self.textNode.attributedText = attributedText + + self.textNode.maximumNumberOfLines = 5 + displayUndo = false + self.originalRemainingSeconds = 5 + + if let action = action { + self.textNode.tapAttributeAction = { attributes, _ in + if let _ = attributes[NSAttributedString.Key(rawValue: "URL")] { + action() + } + } + } case let .image(image, text): self.avatarNode = nil self.iconNode = ASImageNode() @@ -792,7 +822,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode { switch content { case .removedChat: self.panelWrapperNode.addSubnode(self.timerTextNode) - case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent: + case .archivedChat, .hidArchive, .revealedArchive, .autoDelete, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified, .chatAddedToFolder, .chatRemovedFromFolder, .messagesUnpinned, .setProximityAlert, .invitedToVoiceChat, .linkCopied, .banned, .importedMessage, .audioRate, .forward, .gigagroupConversion, .linkRevoked, .voiceChatRecording, .voiceChatFlag, .voiceChatCanSpeak, .sticker, .copy, .mediaSaved, .paymentSent, .image, .inviteRequestSent, .notificationSoundAdded: break case .dice: self.panelWrapperNode.clipsToBounds = true