diff --git a/Telegram-iOS/Info.plist b/Telegram-iOS/Info.plist index d6e4e41038..f66daefe49 100644 --- a/Telegram-iOS/Info.plist +++ b/Telegram-iOS/Info.plist @@ -244,10 +244,8 @@ vk waze googlechrome - googlechromes firefox touch-http - touch-https yandexbrowser-open-url vimeo vine @@ -256,15 +254,16 @@ citymapper lyft opera-http - opera-https firefox-focus ddgQuickLink moovit alook dgis microsoft-edge-http - microsoft-edge-https brave + onionhttp + ucbrowser + dolphin LSRequiresIPhoneOS diff --git a/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift b/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift index 32741bd762..ced56576cc 100644 --- a/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift +++ b/submodules/OpenInExternalAppUI/Sources/OpenInOptions.swift @@ -142,6 +142,24 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope options.append(OpenInOption(identifier: "alook", application: .other(title: "Alook Browser", identifier: 1261944766, scheme: "alook", store: nil), action: { return .openUrl(url: "alook://\(url)") })) + + options.append(OpenInOption(identifier: "dolphin", application: .other(title: "Dolphin", identifier: 452204407, scheme: "dolphin", store: nil), action: { + return .openUrl(url: "dolphin://\(url)") + })) + + options.append(OpenInOption(identifier: "onion", application: .other(title: "Onion Browser", identifier: 519296448, scheme: "onionhttp", store: nil), action: { + if let url = URL(string: url), var components = URLComponents(url: url, resolvingAgainstBaseURL: true) { + components.scheme = components.scheme == "https" ? "onionhttps" : "onionhttp" + if let url = components.string { + return .openUrl(url: url) + } + } + return .none + })) + + options.append(OpenInOption(identifier: "ucbrowser", application: .other(title: "UC Browser", identifier: 1048518592, scheme: "ucbrowser", store: nil), action: { + return .openUrl(url: "ucbrowser://\(url)") + })) case let .location(location, withDirections): let lat = location.latitude diff --git a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift index e1baf72df7..4d63f9d81f 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/StorageUsageController.swift @@ -374,10 +374,12 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals var itemIndex = 0 + var selectedSize: Int64 = 0 let updateTotalSize: () -> Void = { [weak controller] in controller?.updateItem(groupIndex: 0, itemIndex: itemIndex, { item in let title: String var filteredSize = sizeIndex.values.reduce(0, { $0 + ($1.0 ? $1.1 : 0) }) + selectedSize = filteredSize if otherSize.0 { filteredSize += otherSize.1 @@ -438,6 +440,7 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals })) itemIndex += 1 } + selectedSize = totalSize if !items.isEmpty { items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0, action: { @@ -533,7 +536,7 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals |> deliverOnMainQueue).start(completed: { statsPromise.set(.single(.result(resultStats))) let deviceName = UIDevice.current.userInterfaceIdiom == .pad ? "iPad" : "iPhone" - presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: false, action: { _ in }), .current, nil) + presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: false, action: { _ in }), .current, nil) })) } @@ -578,12 +581,12 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals var itemIndex = 1 - var finalSize: Int64 = 0 + var selectedSize: Int64 = 0 let updateTotalSize: () -> Void = { [weak controller] in controller?.updateItem(groupIndex: 0, itemIndex: itemIndex, { item in let title: String let filteredSize = sizeIndex.values.reduce(0, { $0 + ($1.0 ? $1.1 : 0) }) - finalSize = filteredSize + selectedSize = filteredSize if filteredSize == 0 { title = presentationData.strings.Cache_ClearNone @@ -635,7 +638,7 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals } } } - finalSize = totalSize + selectedSize = totalSize if !items.isEmpty { items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0, action: { @@ -715,7 +718,7 @@ public func storageUsageController(context: AccountContext, isModal: Bool = fals |> deliverOnMainQueue).start(completed: { statsPromise.set(.single(.result(resultStats))) let deviceName = UIDevice.current.userInterfaceIdiom == .pad ? "iPad" : "iPhone" - presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(finalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: false, action: { _ in }), .current, nil) + presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: false, action: { _ in }), .current, nil) })) } diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index c496e317a8..c7234e1d93 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -279,6 +279,7 @@ public final class ShareController: ViewController { private let immediateExternalShare: Bool private let subject: ShareControllerSubject private let switchableAccounts: [AccountWithInfo] + private let immediatePeerId: PeerId? private let peers = Promise<([(RenderedPeer, PeerPresence?)], Peer)>() private let peersDisposable = MetaDisposable() @@ -289,11 +290,11 @@ public final class ShareController: ViewController { public var dismissed: ((Bool) -> Void)? - public convenience init(context: AccountContext, subject: ShareControllerSubject, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = []) { - self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, preferredAction: preferredAction, showInChat: showInChat, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts) + public convenience init(context: AccountContext, subject: ShareControllerSubject, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil) { + self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, preferredAction: preferredAction, showInChat: showInChat, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId) } - public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = []) { + public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil) { self.sharedContext = sharedContext self.currentContext = currentContext self.currentAccount = currentContext.account @@ -301,6 +302,7 @@ public final class ShareController: ViewController { self.externalShare = externalShare self.immediateExternalShare = immediateExternalShare self.switchableAccounts = switchableAccounts + self.immediatePeerId = immediatePeerId self.presentationData = self.sharedContext.currentPresentationData.with { $0 } @@ -701,12 +703,16 @@ public final class ShareController: ViewController { strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) } self.displayNodeDidLoad() - self.peersDisposable.set((self.peers.get() - |> deliverOnMainQueue).start(next: { [weak self] next in - if let strongSelf = self { - strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) - } - })) + + if let _ = self.immediatePeerId { + } else { + self.peersDisposable.set((self.peers.get() + |> deliverOnMainQueue).start(next: { [weak self] next in + if let strongSelf = self { + strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) + } + })) + } self._ready.set(self.controllerNode.ready.get()) } @@ -821,27 +827,31 @@ public final class ShareController: ViewController { return (resultPeers, accountPeer) } }) - self.peersDisposable.set((self.peers.get() - |> deliverOnMainQueue).start(next: { [weak self] next in - if let strongSelf = self { - strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) - - if animateIn { - strongSelf.readyDisposable.set((strongSelf.controllerNode.ready.get() - |> filter({ $0 }) - |> take(1) - |> deliverOnMainQueue).start(next: { [weak self] _ in - guard let strongSelf = self else { - return - } - strongSelf.controllerNode.animateIn() - })) + if let immediatePeerId = self.immediatePeerId { + self.sendImmediately(peerId: immediatePeerId) + } else { + self.peersDisposable.set((self.peers.get() + |> deliverOnMainQueue).start(next: { [weak self] next in + if let strongSelf = self { + strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) + + if animateIn { + strongSelf.readyDisposable.set((strongSelf.controllerNode.ready.get() + |> filter({ $0 }) + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] _ in + guard let strongSelf = self else { + return + } + strongSelf.controllerNode.animateIn() + })) + } } - } - })) + })) + } } - public func sendImmediately(peerId: PeerId) { + private func sendImmediately(peerId: PeerId) { self.controllerNode.send(peerId: peerId) } } diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index bdaca44f5e..ce4adcd07e 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -519,7 +519,12 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate } self.inputFieldNode.deactivateInput() - let transition = ContainedViewLayoutTransition.animated(duration: 0.12, curve: .easeInOut) + let transition: ContainedViewLayoutTransition + if peerId == nil { + transition = .animated(duration: 0.12, curve: .easeInOut) + } else { + transition = .immediate + } transition.updateAlpha(node: self.actionButtonNode, alpha: 0.0) transition.updateAlpha(node: self.inputFieldNode, alpha: 0.0) transition.updateAlpha(node: self.actionSeparatorNode, alpha: 0.0) diff --git a/submodules/TelegramUI/TelegramUI/AppDelegate.swift b/submodules/TelegramUI/TelegramUI/AppDelegate.swift index 89189798d5..28d12fed4d 100644 --- a/submodules/TelegramUI/TelegramUI/AppDelegate.swift +++ b/submodules/TelegramUI/TelegramUI/AppDelegate.swift @@ -1124,6 +1124,8 @@ final class SharedApplicationContext { authorizeNotifications = false } self.registerForNotifications(context: context.context, authorize: authorizeNotifications) + + self.resetIntentsIfNeeded(context: context.context) })) } else { self.mainWindow.viewController = nil @@ -1966,6 +1968,22 @@ final class SharedApplicationContext { self.window?.rootViewController?.present(activityController, animated: true, completion: nil) }) } + + private func resetIntentsIfNeeded(context: AccountContextImpl) { + let _ = (context.sharedContext.accountManager.transaction { transaction in + let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings) as? IntentsSettings ?? IntentsSettings.defaultSettings + if !settings.initiallyReset { + if #available(iOS 10.0, *) { + Queue.mainQueue().async { + INInteraction.deleteAll() + } + } + transaction.updateSharedData(ApplicationSpecificSharedDataKeys.intentsSettings, { entry in + return IntentsSettings(initiallyReset: true) + }) + } + }).start() + } } private func notificationPayloadKey(data: Data) -> Data? { diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift index 1921e8e8a0..7fe2d14a19 100644 --- a/submodules/TelegramUI/TelegramUI/ChatController.swift +++ b/submodules/TelegramUI/TelegramUI/ChatController.swift @@ -5144,12 +5144,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var itemIndex = 1 - var finalSize: Int64 = 0 + var selectedSize: Int64 = 0 let updateTotalSize: () -> Void = { [weak controller] in controller?.updateItem(groupIndex: 0, itemIndex: itemIndex, { item in let title: String let filteredSize = sizeIndex.values.reduce(0, { $0 + ($1.0 ? $1.1 : 0) }) - finalSize = filteredSize + selectedSize = filteredSize if filteredSize == 0 { title = presentationData.strings.Cache_ClearNone @@ -5183,7 +5183,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let validCategories: [PeerCacheUsageCategory] = [.image, .video, .audio, .file] var totalSize: Int64 = 0 - finalSize = totalSize func stringForCategory(strings: PresentationStrings, category: PeerCacheUsageCategory) -> String { switch category { @@ -5215,6 +5214,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } } + selectedSize = totalSize if items.isEmpty { strongSelf.presentClearCacheSuggestion() @@ -5280,7 +5280,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G |> deliverOnMainQueue).start(completed: { [weak self] in if let strongSelf = self, let layout = strongSelf.validLayout { let deviceName = UIDevice.current.userInterfaceIdiom == .pad ? "iPad" : "iPhone" - strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(finalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: true, action: { _ in }), in: .current) + strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", deviceName).0), elevatedLayout: true, action: { _ in }), in: .current) } })) @@ -8046,7 +8046,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } private func donateSendMessageIntent() { - guard case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.CloudUser && peerId != context.account.peerId else { + guard case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.CloudUser && peerId != self.context.account.peerId else { return } if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { @@ -8072,6 +8072,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } let interaction = INInteraction(intent: intent, response: nil) interaction.direction = .outgoing + interaction.groupIdentifier = "sendMessage_\(strongSelf.context.account.peerId.toInt64())" interaction.donate { error in if let error = error { print(error.localizedDescription) diff --git a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift index 523c90b498..1731b79a72 100644 --- a/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift +++ b/submodules/TelegramUI/TelegramUI/DeclareEncodables.swift @@ -51,6 +51,7 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(ChatArchiveSettings.self, f: { ChatArchiveSettings(decoder: $0) }) declareEncodable(MediaPlaybackStoredState.self, f: { MediaPlaybackStoredState(decoder: $0) }) declareEncodable(WebBrowserSettings.self, f: { WebBrowserSettings(decoder: $0) }) + declareEncodable(IntentsSettings.self, f: { IntentsSettings(decoder: $0) }) return }() diff --git a/submodules/TelegramUI/TelegramUI/ShareExtensionContext.swift b/submodules/TelegramUI/TelegramUI/ShareExtensionContext.swift index 0700368e9b..6304d1cdcd 100644 --- a/submodules/TelegramUI/TelegramUI/ShareExtensionContext.swift +++ b/submodules/TelegramUI/TelegramUI/ShareExtensionContext.swift @@ -278,6 +278,16 @@ public class ShareRootControllerImpl { |> then(.single(.done)) } + var immediatePeerId: PeerId? + if #available(iOS 13.0, *), let sendMessageIntent = self?.getExtensionContext()?.intent as? INSendMessageIntent { + if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") { + let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2)) + if let userId = Int32(string) { + immediatePeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + } + } + } + let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account in if let strongSelf = self, let inputItems = strongSelf.getExtensionContext()?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty { let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)! @@ -307,7 +317,7 @@ public class ShareRootControllerImpl { } else { return .single(.done) } - }), externalShare: false, switchableAccounts: otherAccounts) + }), externalShare: false, switchableAccounts: otherAccounts, immediatePeerId: immediatePeerId) shareController.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet) shareController.dismissed = { _ in self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil) @@ -326,16 +336,7 @@ public class ShareRootControllerImpl { strongSelf.currentShareController = shareController strongSelf.mainWindow?.present(shareController, on: .root) } - - if #available(iOS 13.0, *), let sendMessageIntent = self?.getExtensionContext()?.intent as? INSendMessageIntent { - if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") { - let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2)) - if let userId = Int32(string) { - shareController.sendImmediately(peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)) - } - } - } - + context.account.resetStateManagement() } diff --git a/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift b/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift new file mode 100644 index 0000000000..9cb936c6aa --- /dev/null +++ b/submodules/TelegramUIPreferences/Sources/IntentsSettings.swift @@ -0,0 +1,35 @@ +import Foundation +import Postbox +import SwiftSignalKit + +public struct IntentsSettings: PreferencesEntry, Equatable { + public let initiallyReset: Bool + + public static var defaultSettings: IntentsSettings { + return IntentsSettings(initiallyReset: false) + } + + public init(initiallyReset: Bool) { + self.initiallyReset = initiallyReset + } + + public init(decoder: PostboxDecoder) { + self.initiallyReset = decoder.decodeBoolForKey("initiallyReset", orElse: false) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeBool(self.initiallyReset, forKey: "initiallyReset") + } + + public func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? IntentsSettings { + return self == to + } else { + return false + } + } + + public static func ==(lhs: IntentsSettings, rhs: IntentsSettings) -> Bool { + return lhs.initiallyReset == rhs.initiallyReset + } +} diff --git a/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift b/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift index 49f8a0e05b..21684e9c6d 100644 --- a/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift +++ b/submodules/TelegramUIPreferences/Sources/PostboxKeys.swift @@ -31,6 +31,7 @@ private enum ApplicationSpecificSharedDataKeyValues: Int32 { case webSearchSettings = 14 case contactSynchronizationSettings = 15 case webBrowserSettings = 16 + case intentsSettings = 17 } public struct ApplicationSpecificSharedDataKeys { @@ -51,6 +52,7 @@ public struct ApplicationSpecificSharedDataKeys { public static let webSearchSettings = applicationSpecificSharedDataKey(ApplicationSpecificSharedDataKeyValues.webSearchSettings.rawValue) public static let contactSynchronizationSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.contactSynchronizationSettings.rawValue) public static let webBrowserSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.webBrowserSettings.rawValue) + public static let intentsSettings = applicationSpecificPreferencesKey(ApplicationSpecificSharedDataKeyValues.intentsSettings.rawValue) } private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {