mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-08 19:10:53 +00:00
Pre-release improvements
This commit is contained in:
parent
eb9ff7beda
commit
e93bc2efab
@ -722,9 +722,15 @@ private final class NotificationServiceHandler {
|
||||
return
|
||||
}
|
||||
strongSelf.stateManager = stateManager
|
||||
|
||||
let settings = stateManager.postbox.transaction { transaction -> NotificationSoundList? in
|
||||
return _internal_cachedNotificationSoundList(transaction: transaction)
|
||||
}
|
||||
|
||||
strongSelf.notificationKeyDisposable.set((existingMasterNotificationsKey(postbox: stateManager.postbox)
|
||||
|> deliverOn(strongSelf.queue)).start(next: { notificationsKey in
|
||||
strongSelf.notificationKeyDisposable.set((combineLatest(queue: strongSelf.queue,
|
||||
existingMasterNotificationsKey(postbox: stateManager.postbox),
|
||||
settings
|
||||
) |> deliverOn(strongSelf.queue)).start(next: { notificationsKey, notificationSoundList in
|
||||
guard let strongSelf = self else {
|
||||
let content = NotificationContent(isLockedMessage: nil)
|
||||
updateCurrentContent(content)
|
||||
@ -765,6 +771,7 @@ private final class NotificationServiceHandler {
|
||||
var peerId: PeerId?
|
||||
var messageId: MessageId.Id?
|
||||
var mediaAttachment: Media?
|
||||
var downloadNotificationSound: (file: TelegramMediaFile, path: String, fileName: String)?
|
||||
|
||||
var interactionAuthorId: PeerId?
|
||||
|
||||
@ -925,12 +932,31 @@ private final class NotificationServiceHandler {
|
||||
content.threadId = threadId
|
||||
}
|
||||
|
||||
if let sound = aps["sound"] as? String {
|
||||
if let customSoundPath = customSoundPath {
|
||||
content.sound = customSoundPath
|
||||
} else {
|
||||
content.sound = sound
|
||||
if let ringtoneString = aps["ringtone"] as? String, let fileId = Int64(ringtoneString) {
|
||||
content.sound = "0.m4a"
|
||||
if let notificationSoundList = notificationSoundList {
|
||||
for sound in notificationSoundList.sounds {
|
||||
if sound.file.fileId.id == fileId {
|
||||
let containerSoundsPath = appGroupUrl.path + "/Library/Sounds"
|
||||
let soundFileName = "\(fileId).mp3"
|
||||
let soundFilePath = containerSoundsPath + "/\(soundFileName)"
|
||||
|
||||
if !FileManager.default.fileExists(atPath: soundFilePath) {
|
||||
let _ = try? FileManager.default.createDirectory(atPath: containerSoundsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
if let filePath = stateManager.postbox.mediaBox.completedResourcePath(id: sound.file.resource.id, pathExtension: nil) {
|
||||
let _ = try? FileManager.default.copyItem(atPath: filePath, toPath: soundFilePath)
|
||||
} else {
|
||||
downloadNotificationSound = (sound.file, soundFilePath, soundFileName)
|
||||
}
|
||||
}
|
||||
|
||||
content.sound = soundFileName
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let sound = aps["sound"] as? String {
|
||||
content.sound = sound
|
||||
}
|
||||
|
||||
if let category = aps["category"] as? String {
|
||||
@ -1014,7 +1040,6 @@ private final class NotificationServiceHandler {
|
||||
|
||||
queue.async {
|
||||
guard let strongSelf = self, let stateManager = strongSelf.stateManager else {
|
||||
|
||||
let content = NotificationContent(isLockedMessage: isLockedMessage)
|
||||
updateCurrentContent(content)
|
||||
completed()
|
||||
@ -1078,17 +1103,79 @@ private final class NotificationServiceHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var fetchNotificationSoundSignal: Signal<Data?, NoError> = .single(nil)
|
||||
if let (downloadNotificationSound, _, _) = downloadNotificationSound {
|
||||
var fetchResource: TelegramMultipartFetchableResource?
|
||||
fetchResource = downloadNotificationSound.resource as? TelegramMultipartFetchableResource
|
||||
|
||||
if let resource = fetchResource {
|
||||
if let _ = strongSelf.stateManager?.postbox.mediaBox.completedResourcePath(resource) {
|
||||
} else {
|
||||
let intervals: Signal<[(Range<Int>, MediaBoxFetchPriority)], NoError> = .single([(0 ..< Int(Int32.max), MediaBoxFetchPriority.maximum)])
|
||||
fetchNotificationSoundSignal = Signal { subscriber in
|
||||
let collectedData = Atomic<Data>(value: Data())
|
||||
return standaloneMultipartFetch(
|
||||
postbox: stateManager.postbox,
|
||||
network: stateManager.network,
|
||||
resource: resource,
|
||||
datacenterId: resource.datacenterId,
|
||||
size: nil,
|
||||
intervals: intervals,
|
||||
parameters: MediaResourceFetchParameters(
|
||||
tag: nil,
|
||||
info: resourceFetchInfo(resource: resource),
|
||||
isRandomAccessAllowed: true
|
||||
),
|
||||
encryptionKey: nil,
|
||||
decryptedSize: nil,
|
||||
continueInBackground: false,
|
||||
useMainConnection: true
|
||||
).start(next: { result in
|
||||
switch result {
|
||||
case let .dataPart(_, data, _, _):
|
||||
let _ = collectedData.modify { current in
|
||||
var current = current
|
||||
current.append(data)
|
||||
return current
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}, error: { _ in
|
||||
subscriber.putNext(nil)
|
||||
subscriber.putCompletion()
|
||||
}, completed: {
|
||||
subscriber.putNext(collectedData.with({ $0 }))
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Will fetch media")
|
||||
let _ = (fetchMediaSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(nil))
|
||||
|> deliverOn(queue)).start(next: { mediaData in
|
||||
let _ = (combineLatest(queue: queue,
|
||||
fetchMediaSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(nil)),
|
||||
fetchNotificationSoundSignal
|
||||
|> timeout(10.0, queue: queue, alternate: .single(nil))
|
||||
)
|
||||
|> deliverOn(queue)).start(next: { mediaData, notificationSoundData in
|
||||
guard let strongSelf = self, let stateManager = strongSelf.stateManager else {
|
||||
completed()
|
||||
return
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Did fetch media \(mediaData == nil ? "Non-empty" : "Empty")")
|
||||
|
||||
if let notificationSoundData = notificationSoundData {
|
||||
Logger.shared.log("NotificationService \(episode)", "Did fetch notificationSoundData")
|
||||
|
||||
if let (_, filePath, fileName) = downloadNotificationSound {
|
||||
let _ = try? notificationSoundData.write(to: URL(fileURLWithPath: filePath))
|
||||
}
|
||||
}
|
||||
|
||||
Logger.shared.log("NotificationService \(episode)", "Will get unread count")
|
||||
let _ = (getCurrentRenderedTotalUnreadCount(
|
||||
|
@ -4060,6 +4060,7 @@ Unused sets are archived when you add more.";
|
||||
"Undo.ChatDeleted" = "Chat deleted";
|
||||
"Undo.ChatCleared" = "Chat cleared";
|
||||
"Undo.ChatClearedForBothSides" = "Chat cleared for both sides";
|
||||
"Undo.ChatClearedForEveryone" = "Chat cleared for everyone";
|
||||
"Undo.SecretChatDeleted" = "Secret Chat deleted";
|
||||
"Undo.LeftChannel" = "Left channel";
|
||||
"Undo.LeftGroup" = "Left group";
|
||||
|
@ -363,9 +363,10 @@ public final class NavigateToChatControllerParams {
|
||||
public let chatListFilter: Int32?
|
||||
public let chatNavigationStack: [PeerId]
|
||||
public let changeColors: Bool
|
||||
public let setupController: (ChatController) -> Void
|
||||
public let completion: (ChatController) -> Void
|
||||
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = [], changeColors: Bool = false, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
public init(navigationController: NavigationController, chatController: ChatController? = nil, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, attachBotStart: ChatControllerInitialAttachBotStart? = nil, updateTextInputState: ChatTextInputState? = nil, activateInput: Bool = false, keepStack: NavigateToChatKeepStack = .default, useExisting: Bool = true, purposefulAction: (() -> Void)? = nil, scrollToEndIfExists: Bool = false, activateMessageSearch: (ChatSearchDomain, String)? = nil, peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil, reportReason: ReportReason? = nil, animated: Bool = true, options: NavigationAnimationOptions = [], parentGroupId: PeerGroupId? = nil, chatListFilter: Int32? = nil, chatNavigationStack: [PeerId] = [], changeColors: Bool = false, setupController: @escaping (ChatController) -> Void = { _ in }, completion: @escaping (ChatController) -> Void = { _ in }) {
|
||||
self.navigationController = navigationController
|
||||
self.chatController = chatController
|
||||
self.chatLocationContextHolder = chatLocationContextHolder
|
||||
@ -390,6 +391,7 @@ public final class NavigateToChatControllerParams {
|
||||
self.chatListFilter = chatListFilter
|
||||
self.chatNavigationStack = chatNavigationStack
|
||||
self.changeColors = changeColors
|
||||
self.setupController = setupController
|
||||
self.completion = completion
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,11 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
case check
|
||||
}
|
||||
|
||||
public enum TextColor {
|
||||
case primary
|
||||
case accent
|
||||
}
|
||||
|
||||
let presentationData: ItemListPresentationData
|
||||
let icon: UIImage?
|
||||
let iconSize: CGSize?
|
||||
@ -28,13 +33,14 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
let title: String
|
||||
let style: ItemListCheckboxItemStyle
|
||||
let color: ItemListCheckboxItemColor
|
||||
let textColor: TextColor
|
||||
let checked: Bool
|
||||
let zeroSeparatorInsets: Bool
|
||||
public let sectionId: ItemListSectionId
|
||||
let action: () -> Void
|
||||
let deleteAction: (() -> 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, deleteAction: (() -> Void)? = nil) {
|
||||
public init(presentationData: ItemListPresentationData, icon: UIImage? = nil, iconSize: CGSize? = nil, iconPlacement: IconPlacement = .default, title: String, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, textColor: TextColor = .primary, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void, deleteAction: (() -> Void)? = nil) {
|
||||
self.presentationData = presentationData
|
||||
self.icon = icon
|
||||
self.iconSize = iconSize
|
||||
@ -42,6 +48,7 @@ public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||
self.title = title
|
||||
self.style = style
|
||||
self.color = color
|
||||
self.textColor = textColor
|
||||
self.checked = checked
|
||||
self.zeroSeparatorInsets = zeroSeparatorInsets
|
||||
self.sectionId = sectionId
|
||||
@ -181,7 +188,15 @@ public class ItemListCheckboxItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let titleColor: UIColor
|
||||
switch item.textColor {
|
||||
case .primary:
|
||||
titleColor = item.presentationData.theme.list.itemPrimaryTextColor
|
||||
case .accent:
|
||||
titleColor = item.presentationData.theme.list.itemAccentColor
|
||||
}
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.title, font: titleFont, textColor: titleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 20.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let separatorHeight = UIScreenPixel
|
||||
|
||||
|
@ -183,7 +183,7 @@ private enum NotificationSoundSelectionEntry: ItemListNodeEntry {
|
||||
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: {
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: icon, iconSize: nil, iconPlacement: .check, title: text, style: .left, textColor: .accent, checked: false, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.upload()
|
||||
})
|
||||
case let .cloudInfo(text):
|
||||
@ -479,6 +479,20 @@ public func presentCustomNotificationSoundFilePicker(context: AccountContext, co
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let resources = try url.resourceValues(forKeys:[.fileSizeKey])
|
||||
if let size = resources.fileSize {
|
||||
if Int32(size) > settings.maxSize {
|
||||
//TODO:localize
|
||||
presentUndo(.info(title: "Audio is too large", text: "The file is over \(dataSizeString(Int64(settings.maxSize), formatting: DataSizeStringFormatting(presentationData: presentationData)))."))
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("Error: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = NSFileCoordinator(filePresenter: nil)
|
||||
var error: NSError?
|
||||
coordinator.coordinate(readingItemAt: url, options: .forUploading, error: &error, byAccessor: { url in
|
||||
|
@ -425,7 +425,11 @@ public final class MediaBox {
|
||||
}
|
||||
|
||||
public func completedResourcePath(_ resource: MediaResource, pathExtension: String? = nil) -> String? {
|
||||
let paths = self.storePathsForId(resource.id)
|
||||
return self.completedResourcePath(id: resource.id, pathExtension: pathExtension)
|
||||
}
|
||||
|
||||
public func completedResourcePath(id: MediaResourceId, pathExtension: String? = nil) -> String? {
|
||||
let paths = self.storePathsForId(id)
|
||||
if let _ = fileSize(paths.complete) {
|
||||
self.timeBasedCleanup.touch(paths: [
|
||||
paths.complete
|
||||
|
@ -212,7 +212,7 @@ private enum NotificationPeerExceptionEntry: ItemListNodeEntry {
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(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: {
|
||||
return ItemListCheckboxItem(presentationData: presentationData, icon: icon, iconSize: nil, iconPlacement: .check, title: text, style: .left, textColor: .accent, checked: false, zeroSeparatorInsets: false, sectionId: self.section, action: {
|
||||
arguments.upload()
|
||||
})
|
||||
case let .displayPreviewsHeader(_, _, text):
|
||||
|
@ -214,10 +214,25 @@ private func apiInputPeerNotifySettings(_ settings: MessageNotificationSettings)
|
||||
|
||||
private func pushedNotificationSettings(network: Network, settings: GlobalNotificationSettingsSet) -> Signal<Void, NoError> {
|
||||
let pushedChats = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyChats, settings: apiInputPeerNotifySettings(settings.groupChats)))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|
||||
let pushedUsers = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyUsers, settings: apiInputPeerNotifySettings(settings.privateChats)))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|
||||
let pushedChannels = network.request(Api.functions.account.updateNotifySettings(peer: Api.InputNotifyPeer.inputNotifyBroadcasts, settings: apiInputPeerNotifySettings(settings.channels)))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|
||||
let pushedContactsJoined = network.request(Api.functions.account.setContactSignUpNotification(silent: settings.contactsJoined ? .boolFalse : .boolTrue))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|
||||
return combineLatest(pushedChats, pushedUsers, pushedChannels, pushedContactsJoined)
|
||||
|> retryRequest
|
||||
|> mapToSignal { _ -> Signal<Void, NoError> in return .complete() }
|
||||
}
|
||||
|
@ -129,14 +129,16 @@ private func pushPeerNotificationSettings(postbox: Postbox, network: Network, pe
|
||||
}
|
||||
let inputSettings = Api.InputPeerNotifySettings.inputPeerNotifySettings(flags: flags, showPreviews: showPreviews, silent: nil, muteUntil: muteUntil, sound: sound)
|
||||
return network.request(Api.functions.account.updateNotifySettings(peer: .inputNotifyPeer(peer: inputPeer), settings: inputSettings))
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.updateCurrentPeerNotificationSettings([notificationPeerId: settings])
|
||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
|
||||
}
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.transaction { transaction -> Void in
|
||||
transaction.updateCurrentPeerNotificationSettings([notificationPeerId: settings])
|
||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
||||
transaction.updatePendingPeerNotificationSettings(peerId: peerId, settings: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let pending = transaction.getPendingPeerNotificationSettings(peerId), pending.isEqual(to: settings) {
|
||||
|
@ -124,7 +124,7 @@ func _internal_cachedNotificationSoundListCacheKey() -> ItemCacheEntryId {
|
||||
return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.notificationSoundList, key: key)
|
||||
}
|
||||
|
||||
func _internal_cachedNotificationSoundList(transaction: Transaction) -> NotificationSoundList? {
|
||||
public func _internal_cachedNotificationSoundList(transaction: Transaction) -> NotificationSoundList? {
|
||||
let cached = transaction.retrieveItemCacheEntry(id: _internal_cachedNotificationSoundListCacheKey())?.get(NotificationSoundList.self)
|
||||
if let cached = cached {
|
||||
return cached
|
||||
|
@ -62,8 +62,10 @@ public func timeIntervalString(strings: PresentationStrings, value: Int32, prefe
|
||||
return strings.MessageTimer_Days(max(1, value / (60 * 60 * 24)))
|
||||
} else if value <= 60 * 60 * 24 * 30 {
|
||||
return strings.MessageTimer_Weeks(max(1, value / (60 * 60 * 24 * 7)))
|
||||
} else {
|
||||
} else if value <= 60 * 60 * 24 * 365 {
|
||||
return strings.MessageTimer_Months(max(1, value / (60 * 60 * 24 * 30)))
|
||||
} else {
|
||||
return strings.MessageTimer_Years(max(1, value / (60 * 60 * 24 * 365)))
|
||||
}
|
||||
} else {
|
||||
if value < 60 {
|
||||
@ -76,8 +78,10 @@ public func timeIntervalString(strings: PresentationStrings, value: Int32, prefe
|
||||
return strings.MessageTimer_Days(max(1, value / (60 * 60 * 24)))
|
||||
} else if value < 60 * 60 * 24 * 30 {
|
||||
return strings.MessageTimer_Weeks(max(1, value / (60 * 60 * 24 * 7)))
|
||||
} else {
|
||||
} else if value < 60 * 60 * 24 * 365 {
|
||||
return strings.MessageTimer_Months(max(1, value / (60 * 60 * 24 * 30)))
|
||||
} else {
|
||||
return strings.MessageTimer_Years(max(1, value / (60 * 60 * 24 * 365)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,11 @@ public func mediaContentKind(_ media: EngineMedia, message: EngineMessage? = nil
|
||||
case let .dice(dice):
|
||||
return .dice(dice.emoji)
|
||||
case let .invoice(invoice):
|
||||
return .invoice(invoice.title)
|
||||
if !invoice.description.isEmpty {
|
||||
return .invoice(invoice.description)
|
||||
} else {
|
||||
return .invoice(invoice.title)
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
@ -9767,6 +9767,43 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
func beginClearHistory(type: InteractiveHistoryClearingType) {
|
||||
guard case let .peer(peerId) = self.chatLocation else {
|
||||
return
|
||||
}
|
||||
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
|
||||
self.chatDisplayNode.historyNode.historyAppearsCleared = true
|
||||
|
||||
let statusText: String
|
||||
if case .scheduledMessages = self.presentationInterfaceState.subject {
|
||||
statusText = self.presentationData.strings.Undo_ScheduledMessagesCleared
|
||||
} else if case .forEveryone = type {
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser {
|
||||
statusText = self.presentationData.strings.Undo_ChatClearedForBothSides
|
||||
} else {
|
||||
statusText = self.presentationData.strings.Undo_ChatClearedForEveryone
|
||||
}
|
||||
} else {
|
||||
statusText = self.presentationData.strings.Undo_ChatCleared
|
||||
}
|
||||
|
||||
self.present(UndoOverlayController(presentationData: self.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(text: statusText), elevatedLayout: false, action: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
if value == .commit {
|
||||
let _ = strongSelf.context.engine.messages.clearHistoryInteractively(peerId: peerId, type: type).start(completed: {
|
||||
self?.chatDisplayNode.historyNode.historyAppearsCleared = false
|
||||
})
|
||||
return true
|
||||
} else if value == .undo {
|
||||
strongSelf.chatDisplayNode.historyNode.historyAppearsCleared = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
private func navigationButtonAction(_ action: ChatNavigationButtonAction) {
|
||||
switch action {
|
||||
case .spacer:
|
||||
@ -9775,36 +9812,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
|
||||
case .clearHistory:
|
||||
if case let .peer(peerId) = self.chatLocation {
|
||||
let context = self.context
|
||||
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { [weak self] type in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
|
||||
strongSelf.chatDisplayNode.historyNode.historyAppearsCleared = true
|
||||
|
||||
let statusText: String
|
||||
if case .scheduledMessages = strongSelf.presentationInterfaceState.subject {
|
||||
statusText = strongSelf.presentationData.strings.Undo_ScheduledMessagesCleared
|
||||
} else if case .forEveryone = type {
|
||||
statusText = strongSelf.presentationData.strings.Undo_ChatClearedForBothSides
|
||||
} else {
|
||||
statusText = strongSelf.presentationData.strings.Undo_ChatCleared
|
||||
}
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(text: statusText), elevatedLayout: false, action: { value in
|
||||
if value == .commit {
|
||||
let _ = context.engine.messages.clearHistoryInteractively(peerId: peerId, type: type).start(completed: {
|
||||
self?.chatDisplayNode.historyNode.historyAppearsCleared = false
|
||||
})
|
||||
return true
|
||||
} else if value == .undo {
|
||||
self?.chatDisplayNode.historyNode.historyAppearsCleared = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
self?.beginClearHistory(type: type)
|
||||
}
|
||||
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> Bool in
|
||||
|
@ -681,6 +681,67 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
}
|
||||
|
||||
for media in message.media {
|
||||
if let file = media as? TelegramMediaFile, let size = file.size, let duration = file.duration, (["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
|
||||
f(.default)
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let settings = NotificationSoundSettings.extract(from: context.currentAppConfiguration.with({ $0 }))
|
||||
if size > settings.maxSize {
|
||||
//TODO:localize
|
||||
controllerInteraction.displayUndo(.info(title: "Audio is too large", text: "The file is over \(dataSizeString(Int64(settings.maxSize), formatting: DataSizeStringFormatting(presentationData: presentationData)))."))
|
||||
} else if Double(duration) > Double(settings.maxDuration) {
|
||||
//TODO:localize
|
||||
controllerInteraction.displayUndo(.info(title: "Audio is too long", text: "The duration is longer than \(stringForDuration(Int32(settings.maxDuration)))."))
|
||||
} else {
|
||||
let _ = (context.engine.peers.saveNotificationSound(file: .message(message: MessageReference(message), media: file))
|
||||
|> deliverOnMainQueue).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))
|
||||
}))
|
||||
})
|
||||
}
|
||||
})))
|
||||
|
||||
/*
|
||||
|
||||
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()
|
||||
}
|
||||
})*/
|
||||
}
|
||||
actions.append(.separator)
|
||||
}
|
||||
|
||||
var isReplyThreadHead = false
|
||||
if case let .replyThread(replyThreadMessage) = chatPresentationInterfaceState.chatLocation {
|
||||
isReplyThreadHead = messages[0].id == replyThreadMessage.effectiveTopId
|
||||
@ -870,66 +931,6 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
}
|
||||
|
||||
for media in message.media {
|
||||
if let file = media as? TelegramMediaFile, let size = file.size, let duration = file.duration, (["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
|
||||
f(.default)
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let settings = NotificationSoundSettings.extract(from: context.currentAppConfiguration.with({ $0 }))
|
||||
if size > settings.maxSize {
|
||||
//TODO:localize
|
||||
controllerInteraction.displayUndo(.info(title: "Audio is too large", text: "The file is over \(dataSizeString(Int64(settings.maxSize), formatting: DataSizeStringFormatting(presentationData: presentationData)))."))
|
||||
} else if Double(duration) > Double(settings.maxDuration) {
|
||||
//TODO:localize
|
||||
controllerInteraction.displayUndo(.info(title: "Audio is too long", text: "The duration is longer than \(stringForDuration(Int32(settings.maxDuration)))."))
|
||||
} else {
|
||||
let _ = (context.engine.peers.saveNotificationSound(file: .message(message: MessageReference(message), media: file))
|
||||
|> deliverOnMainQueue).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))
|
||||
}))
|
||||
})
|
||||
}
|
||||
})))
|
||||
|
||||
/*
|
||||
|
||||
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 {
|
||||
|
@ -279,6 +279,8 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
private var initialTime: Int32?
|
||||
private var pickerView: TimerPickerView?
|
||||
|
||||
private let autoremoveTimerValues: [Int32]
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
||||
var completion: ((Int32) -> Void)?
|
||||
@ -370,6 +372,25 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
break
|
||||
}
|
||||
|
||||
self.autoremoveTimerValues = [
|
||||
1 * 24 * 60 * 60 as Int32,
|
||||
2 * 24 * 60 * 60 as Int32,
|
||||
3 * 24 * 60 * 60 as Int32,
|
||||
4 * 24 * 60 * 60 as Int32,
|
||||
5 * 24 * 60 * 60 as Int32,
|
||||
6 * 24 * 60 * 60 as Int32,
|
||||
1 * 7 * 24 * 60 * 60 as Int32,
|
||||
2 * 7 * 24 * 60 * 60 as Int32,
|
||||
3 * 7 * 24 * 60 * 60 as Int32,
|
||||
1 * 31 * 24 * 60 * 60 as Int32,
|
||||
2 * 30 * 24 * 60 * 60 as Int32,
|
||||
3 * 31 * 24 * 60 * 60 as Int32,
|
||||
4 * 30 * 24 * 60 * 60 as Int32,
|
||||
5 * 31 * 24 * 60 * 60 as Int32,
|
||||
6 * 30 * 24 * 60 * 60 as Int32,
|
||||
365 * 24 * 60 * 60 as Int32
|
||||
]
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = nil
|
||||
@ -452,13 +473,14 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
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
|
||||
var selectedRowIndex = 0
|
||||
for i in 0 ..< self.autoremoveTimerValues.count {
|
||||
if self.autoremoveTimerValues[i] <= value {
|
||||
selectedRowIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
pickerView.selectRow(Int(days), inComponent: 0, animated: false)
|
||||
pickerView.selectRow(Int(hours), inComponent: 1, animated: false)
|
||||
pickerView.selectRow(Int(minutes), inComponent: 2, animated: false)
|
||||
pickerView.selectRow(selectedRowIndex, inComponent: 0, animated: false)
|
||||
}
|
||||
case .mute:
|
||||
let pickerView = TimerDatePickerView()
|
||||
@ -487,7 +509,7 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
case .sendTimer:
|
||||
return 1
|
||||
case .autoremove:
|
||||
return 3
|
||||
return 1
|
||||
case .mute:
|
||||
return 0
|
||||
}
|
||||
@ -498,16 +520,7 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
case .sendTimer:
|
||||
return timerValues.count
|
||||
case .autoremove:
|
||||
switch component {
|
||||
case 0:
|
||||
return 365
|
||||
case 1:
|
||||
return 24
|
||||
case 2:
|
||||
return 60
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
return self.autoremoveTimerValues.count
|
||||
case .mute:
|
||||
return 0
|
||||
}
|
||||
@ -536,19 +549,12 @@ class ChatTimerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate, UIPi
|
||||
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()
|
||||
}
|
||||
let value = self.autoremoveTimerValues[row]
|
||||
|
||||
itemView.value = (Int32(row), string)
|
||||
let string: String
|
||||
string = timeIntervalString(strings: self.presentationData.strings, value: value)
|
||||
|
||||
itemView.value = (value, string)
|
||||
|
||||
return itemView
|
||||
case .mute:
|
||||
|
@ -64,6 +64,7 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
|
||||
if let attachBotStart = params.attachBotStart {
|
||||
controller.presentAttachmentBot(botId: attachBotStart.botId, payload: attachBotStart.payload)
|
||||
}
|
||||
params.setupController(controller)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ final class TelegramGlobalSettings {
|
||||
|
||||
final class PeerInfoScreenData {
|
||||
let peer: Peer?
|
||||
let chatPeer: Peer?
|
||||
let cachedData: CachedPeerData?
|
||||
let status: PeerInfoStatusData?
|
||||
let notificationSettings: TelegramPeerNotificationSettings?
|
||||
@ -186,6 +187,7 @@ final class PeerInfoScreenData {
|
||||
|
||||
init(
|
||||
peer: Peer?,
|
||||
chatPeer: Peer?,
|
||||
cachedData: CachedPeerData?,
|
||||
status: PeerInfoStatusData?,
|
||||
notificationSettings: TelegramPeerNotificationSettings?,
|
||||
@ -202,6 +204,7 @@ final class PeerInfoScreenData {
|
||||
requestsContext: PeerInvitationImportersContext?
|
||||
) {
|
||||
self.peer = peer
|
||||
self.chatPeer = chatPeer
|
||||
self.cachedData = cachedData
|
||||
self.status = status
|
||||
self.notificationSettings = notificationSettings
|
||||
@ -428,6 +431,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[peerId],
|
||||
chatPeer: peerView.peers[peerId],
|
||||
cachedData: peerView.cachedData,
|
||||
status: nil,
|
||||
notificationSettings: nil,
|
||||
@ -453,6 +457,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
case .none, .settings:
|
||||
return .single(PeerInfoScreenData(
|
||||
peer: nil,
|
||||
chatPeer: nil,
|
||||
cachedData: nil,
|
||||
status: nil,
|
||||
notificationSettings: nil,
|
||||
@ -566,7 +571,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
combinedKeys.append(.peerChatState(peerId: secretChatId))
|
||||
}
|
||||
return combineLatest(
|
||||
context.account.viewTracker.peerView(userPeerId, updateData: true),
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
peerInfoAvailableMediaPanes(context: context, peerId: peerId),
|
||||
context.account.postbox.combinedView(keys: combinedKeys),
|
||||
status
|
||||
@ -595,6 +600,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[userPeerId],
|
||||
chatPeer: peerView.peers[peerId],
|
||||
cachedData: peerView.cachedData,
|
||||
status: status,
|
||||
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||
@ -680,6 +686,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[peerId],
|
||||
chatPeer: peerView.peers[peerId],
|
||||
cachedData: peerView.cachedData,
|
||||
status: status,
|
||||
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||
@ -858,6 +865,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen
|
||||
|
||||
return PeerInfoScreenData(
|
||||
peer: peerView.peers[groupId],
|
||||
chatPeer: peerView.peers[groupId],
|
||||
cachedData: peerView.cachedData,
|
||||
status: status,
|
||||
notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings,
|
||||
|
@ -3701,7 +3701,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
case .more:
|
||||
guard let data = self.data, let peer = data.peer else {
|
||||
guard let data = self.data, let peer = data.peer, let chatPeer = data.chatPeer else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.presentationData
|
||||
@ -3753,10 +3753,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
|
||||
var canSetupAutoremoveTimeout = false
|
||||
|
||||
if let secretChat = peer as? TelegramSecretChat {
|
||||
if let secretChat = chatPeer as? TelegramSecretChat {
|
||||
currentAutoremoveTimeout = secretChat.messageAutoremoveTimeout
|
||||
canSetupAutoremoveTimeout = true
|
||||
} else if let group = peer as? TelegramGroup {
|
||||
canSetupAutoremoveTimeout = false
|
||||
} else if let group = chatPeer as? TelegramGroup {
|
||||
if case .creator = group.role {
|
||||
canSetupAutoremoveTimeout = true
|
||||
} else if case let .admin(rights, _) = group.role {
|
||||
@ -3764,11 +3764,11 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
}
|
||||
} else if let user = peer as? TelegramUser {
|
||||
} else if let user = chatPeer as? TelegramUser {
|
||||
if user.id != strongSelf.context.account.peerId && user.botInfo == nil {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
} else if let channel = chatPeer as? TelegramChannel {
|
||||
if channel.hasPermission(.deleteAllMessages) {
|
||||
canSetupAutoremoveTimeout = true
|
||||
}
|
||||
@ -3807,17 +3807,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
31 * 24 * 60 * 60
|
||||
]
|
||||
|
||||
if let _ = currentAutoremoveTimeout {
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Disable", icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
self?.setAutoremove(timeInterval: nil)
|
||||
})))
|
||||
}
|
||||
|
||||
for value in presetValues {
|
||||
subItems.append(.action(ContextMenuActionItem(text: timeIntervalString(strings: strings, value: value), icon: { _ in
|
||||
return nil
|
||||
@ -3837,6 +3826,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
self?.openAutoremove(currentValue: currentAutoremoveTimeout)
|
||||
})))
|
||||
|
||||
if let _ = currentAutoremoveTimeout {
|
||||
//TODO:localize
|
||||
subItems.append(.action(ContextMenuActionItem(text: "Disable", textColor: .destructive, icon: { _ in
|
||||
return nil
|
||||
}, action: { _, f in
|
||||
f(.default)
|
||||
|
||||
self?.setAutoremove(timeInterval: nil)
|
||||
})))
|
||||
}
|
||||
|
||||
subItems.append(.separator)
|
||||
|
||||
//TODO:localize
|
||||
@ -4339,8 +4339,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})))
|
||||
subItems.append(.separator)
|
||||
|
||||
//TODO:localize
|
||||
|
||||
guard let anyType = clearPeerHistory.canClearForEveryone ?? clearPeerHistory.canClearForMyself else {
|
||||
return
|
||||
}
|
||||
@ -4348,8 +4346,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
let title: String
|
||||
switch anyType {
|
||||
case .user, .secretChat, .savedMessages:
|
||||
//TODO:localize
|
||||
title = "Are you sure you want to delete all messages with \(EnginePeer(chatPeer).compactDisplayTitle)?"
|
||||
case .group, .channel:
|
||||
//TODO:localize
|
||||
title = "Are you sure you want to delete all messages in \(EnginePeer(chatPeer).compactDisplayTitle)?"
|
||||
}
|
||||
|
||||
@ -4361,27 +4361,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
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)
|
||||
strongSelf.openChatWithClearedHistory(type: type)
|
||||
}
|
||||
|
||||
if let canClearForEveryone = clearPeerHistory.canClearForEveryone {
|
||||
@ -4775,6 +4756,28 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
}
|
||||
}
|
||||
|
||||
private func openChatWithClearedHistory(type: InteractiveHistoryClearingType) {
|
||||
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(id: self.peerId), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), setupController: { controller in
|
||||
(controller as? ChatControllerImpl)?.beginClearHistory(type: type)
|
||||
}, completion: { [weak self] _ in
|
||||
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil {
|
||||
var viewControllers = navigationController.viewControllers
|
||||
viewControllers = viewControllers.filter { controller in
|
||||
if controller is PeerInfoScreen {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
navigationController.setViewControllers(viewControllers, animated: false)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
private func openAddContact() {
|
||||
let _ = (getUserPeer(postbox: self.context.account.postbox, peerId: self.peerId)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer, _ in
|
||||
|
Loading…
x
Reference in New Issue
Block a user