Add account switching application shortcut

This commit is contained in:
Ilya Laktyushin 2019-11-21 21:37:21 +04:00
parent 85ab1872ae
commit 4ffb3bc52b
16 changed files with 1346 additions and 1246 deletions

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_lt_user.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -5136,3 +5136,5 @@ Any member of this group will be able to see messages in the channel.";
"Appearance.TextSize.Title" = "Text Size"; "Appearance.TextSize.Title" = "Text Size";
"Appearance.TextSize.UseSystem" = "User System Text Size"; "Appearance.TextSize.UseSystem" = "User System Text Size";
"Appearance.TextSize.Apply" = "Set"; "Appearance.TextSize.Apply" = "Set";
"Shortcut.SwitchAccount" = "Switch Account";

View File

@ -0,0 +1,19 @@
load("//Config:buck_rule_macros.bzl", "static_library")
static_library(
name = "AccountUtils",
srcs = glob([
"Sources/**/*.swift",
]),
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
"//submodules/Postbox:Postbox#shared",
"//submodules/TelegramCore:TelegramCore#shared",
"//submodules/SyncCore:SyncCore#shared",
"//submodules/AccountContext:AccountContext",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
],
)

View File

@ -6,7 +6,9 @@ import SyncCore
import TelegramUIPreferences import TelegramUIPreferences
import AccountContext import AccountContext
func activeAccountsAndPeers(context: AccountContext, includePrimary: Bool = false) -> Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError> { public let maximumNumberOfAccounts = 3
public func activeAccountsAndPeers(context: AccountContext, includePrimary: Bool = false) -> Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError> {
let sharedContext = context.sharedContext let sharedContext = context.sharedContext
return context.sharedContext.activeAccounts return context.sharedContext.activeAccounts
|> mapToSignal { primary, activeAccounts, _ -> Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError> in |> mapToSignal { primary, activeAccounts, _ -> Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError> in

View File

@ -84,6 +84,7 @@ static_library(
"//submodules/DeleteChatPeerActionSheetItem:DeleteChatPeerActionSheetItem", "//submodules/DeleteChatPeerActionSheetItem:DeleteChatPeerActionSheetItem",
"//submodules/PhoneNumberFormat:PhoneNumberFormat", "//submodules/PhoneNumberFormat:PhoneNumberFormat",
"//submodules/OpenInExternalAppUI:OpenInExternalAppUI", "//submodules/OpenInExternalAppUI:OpenInExternalAppUI",
"//submodules/AccountUtils:AccountUtils",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -10,6 +10,7 @@ import ItemListUI
import ItemListPeerItem import ItemListPeerItem
import AccountContext import AccountContext
import AppIntents import AppIntents
import AccountUtils
private final class IntentsSettingsControllerArguments { private final class IntentsSettingsControllerArguments {
let context: AccountContext let context: AccountContext

View File

@ -7,8 +7,7 @@ import SyncCore
import OverlayStatusController import OverlayStatusController
import AccountContext import AccountContext
import PresentationDataUtils import PresentationDataUtils
import AccountUtils
private let maximumNumberOfAccounts = 3
func openEditSettings(context: AccountContext, accountsAndPeers: Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError>, focusOnItemTag: EditSettingsEntryTag? = nil, presentController: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void) -> Disposable { func openEditSettings(context: AccountContext, accountsAndPeers: Signal<((Account, Peer)?, [(Account, Peer, Int32)]), NoError>, focusOnItemTag: EditSettingsEntryTag? = nil, presentController: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void) -> Disposable {
let openEditingDisposable = MetaDisposable() let openEditingDisposable = MetaDisposable()

View File

@ -15,8 +15,7 @@ import CallListUI
import NotificationSoundSelectionUI import NotificationSoundSelectionUI
import PresentationDataUtils import PresentationDataUtils
import PhoneNumberFormat import PhoneNumberFormat
import AccountUtils
private let maximumNumberOfAccounts = 3
enum SettingsSearchableItemIcon { enum SettingsSearchableItemIcon {
case profile case profile

View File

@ -35,8 +35,7 @@ import AppBundle
import ContextUI import ContextUI
import WalletUI import WalletUI
import PhoneNumberFormat import PhoneNumberFormat
import AccountUtils
private let maximumNumberOfAccounts = 3
private let avatarFont = avatarPlaceholderFont(size: 13.0) private let avatarFont = avatarPlaceholderFont(size: 13.0)

View File

@ -201,6 +201,7 @@ framework(
"//submodules/LocationResources:LocationResources", "//submodules/LocationResources:LocationResources",
"//submodules/ItemListVenueItem:ItemListVenueItem", "//submodules/ItemListVenueItem:ItemListVenueItem",
"//submodules/SemanticStatusNode:SemanticStatusNode", "//submodules/SemanticStatusNode:SemanticStatusNode",
"//submodules/AccountUtils:AccountUtils",
], ],
frameworks = [ frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework", "$SDKROOT/System/Library/Frameworks/Foundation.framework",

View File

@ -34,6 +34,7 @@ import OpenSSLEncryptionProvider
import AppLock import AppLock
import PresentationDataUtils import PresentationDataUtils
import AppIntents import AppIntents
import AccountUtils
#if canImport(BackgroundTasks) #if canImport(BackgroundTasks)
import BackgroundTasks import BackgroundTasks
@ -960,14 +961,23 @@ final class SharedApplicationContext {
return true return true
}) })
|> mapToSignal { account -> Signal<(Account, LimitsConfiguration, CallListSettings)?, NoError> in |> mapToSignal { account -> Signal<(Account, LimitsConfiguration, CallListSettings)?, NoError> in
return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings in return sharedApplicationContext.sharedContext.accountManager.transaction { transaction -> CallListSettings? in
return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings ?? CallListSettings.defaultSettings return transaction.getSharedData(ApplicationSpecificSharedDataKeys.callListSettings) as? CallListSettings
}
|> reduceLeft(value: nil) { current, updated -> CallListSettings? in
var result: CallListSettings?
if let updated = updated {
result = updated
} else if let current = current {
result = current
}
return result
} }
|> mapToSignal { callListSettings -> Signal<(Account, LimitsConfiguration, CallListSettings)?, NoError> in |> mapToSignal { callListSettings -> Signal<(Account, LimitsConfiguration, CallListSettings)?, NoError> in
if let account = account { if let account = account {
return account.postbox.transaction { transaction -> (Account, LimitsConfiguration, CallListSettings)? in return account.postbox.transaction { transaction -> (Account, LimitsConfiguration, CallListSettings)? in
let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue
return (account, limitsConfiguration, callListSettings) return (account, limitsConfiguration, callListSettings ?? CallListSettings.defaultSettings)
} }
} else { } else {
return .single(nil) return .single(nil)
@ -1243,7 +1253,22 @@ final class SharedApplicationContext {
|> mapToSignal { context -> Signal<[ApplicationShortcutItem], NoError> in |> mapToSignal { context -> Signal<[ApplicationShortcutItem], NoError> in
if let context = context { if let context = context {
let presentationData = context.context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.context.sharedContext.currentPresentationData.with { $0 }
return .single(applicationShortcutItems(strings: presentationData.strings))
return activeAccountsAndPeers(context: context.context)
|> take(1)
|> map { primaryAndAccounts -> (Account, Peer, Int32)? in
return primaryAndAccounts.1.first
}
|> map { accountAndPeer -> String? in
if let (_, peer, _) = accountAndPeer {
return peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
} else {
return nil
}
} |> mapToSignal { otherAccountName -> Signal<[ApplicationShortcutItem], NoError> in
let presentationData = context.context.sharedContext.currentPresentationData.with { $0 }
return .single(applicationShortcutItems(strings: presentationData.strings, otherAccountName: otherAccountName))
}
} else { } else {
return .single([]) return .single([])
} }
@ -1792,12 +1817,14 @@ final class SharedApplicationContext {
let _ = (self.sharedContextPromise.get() let _ = (self.sharedContextPromise.get()
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { sharedContext in |> deliverOnMainQueue).start(next: { sharedContext in
let type = ApplicationShortcutItemType(rawValue: shortcutItem.type)
var immediately = type == .account
let proceed: () -> Void = { let proceed: () -> Void = {
let _ = (self.context.get() let _ = (self.context.get()
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { context in |> deliverOnMainQueue).start(next: { context in
if let context = context { if let context = context {
if let type = ApplicationShortcutItemType(rawValue: shortcutItem.type) { if let type = type {
switch type { switch type {
case .search: case .search:
context.openRootSearch() context.openRootSearch()
@ -1807,12 +1834,14 @@ final class SharedApplicationContext {
context.openRootCamera() context.openRootCamera()
case .savedMessages: case .savedMessages:
self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId) self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId)
case .account:
context.switchAccount()
} }
} }
} }
}) })
} }
if let appLockContext = sharedContext.sharedContext.appLockContext as? AppLockContextImpl { if let appLockContext = sharedContext.sharedContext.appLockContext as? AppLockContextImpl, !immediately {
let _ = (appLockContext.isCurrentlyLocked let _ = (appLockContext.isCurrentlyLocked
|> filter { !$0 } |> filter { !$0 }
|> take(1) |> take(1)

View File

@ -22,6 +22,7 @@ import ImageBlur
import WatchBridge import WatchBridge
import SettingsUI import SettingsUI
import AppLock import AppLock
import AccountUtils
final class UnauthorizedApplicationContext { final class UnauthorizedApplicationContext {
let sharedContext: SharedAccountContextImpl let sharedContext: SharedAccountContextImpl
@ -754,6 +755,27 @@ final class AuthorizedApplicationContext {
self.rootController.openRootCamera() self.rootController.openRootCamera()
} }
func switchAccount() {
let _ = (activeAccountsAndPeers(context: self.context)
|> take(1)
|> map { primaryAndAccounts -> (Account, Peer, Int32)? in
return primaryAndAccounts.1.first
}
|> map { accountAndPeer -> Account? in
if let (account, _, _) = accountAndPeer {
return account
} else {
return nil
}
}
|> deliverOnMainQueue).start(next: { [weak self] account in
guard let strongSelf = self, let account = account else {
return
}
strongSelf.context.sharedContext.switchToAccount(id: account.id, fromSettingsController: nil, withChatListController: nil)
})
}
private func updateCoveringViewSnaphot(_ visible: Bool) { private func updateCoveringViewSnaphot(_ visible: Bool) {
if visible { if visible {
let scale: CGFloat = 0.5 let scale: CGFloat = 0.5

View File

@ -7,11 +7,13 @@ enum ApplicationShortcutItemType: String {
case compose case compose
case camera case camera
case savedMessages case savedMessages
case account
} }
struct ApplicationShortcutItem: Equatable { struct ApplicationShortcutItem: Equatable {
let type: ApplicationShortcutItemType let type: ApplicationShortcutItemType
let title: String let title: String
let subtitle: String?
} }
@available(iOS 9.1, *) @available(iOS 9.1, *)
@ -27,16 +29,27 @@ extension ApplicationShortcutItem {
icon = UIApplicationShortcutIcon(templateImageName: "Shortcuts/Camera") icon = UIApplicationShortcutIcon(templateImageName: "Shortcuts/Camera")
case .savedMessages: case .savedMessages:
icon = UIApplicationShortcutIcon(templateImageName: "Shortcuts/SavedMessages") icon = UIApplicationShortcutIcon(templateImageName: "Shortcuts/SavedMessages")
case .account:
icon = UIApplicationShortcutIcon(templateImageName: "Shortcuts/Account")
} }
return UIApplicationShortcutItem(type: self.type.rawValue, localizedTitle: self.title, localizedSubtitle: nil, icon: icon, userInfo: nil) return UIApplicationShortcutItem(type: self.type.rawValue, localizedTitle: self.title, localizedSubtitle: self.subtitle, icon: icon, userInfo: nil)
} }
} }
func applicationShortcutItems(strings: PresentationStrings) -> [ApplicationShortcutItem] { func applicationShortcutItems(strings: PresentationStrings, otherAccountName: String?) -> [ApplicationShortcutItem] {
if let otherAccountName = otherAccountName {
return [ return [
ApplicationShortcutItem(type: .search, title: strings.Common_Search), ApplicationShortcutItem(type: .search, title: strings.Common_Search, subtitle: nil),
ApplicationShortcutItem(type: .compose, title: strings.Compose_NewMessage), ApplicationShortcutItem(type: .compose, title: strings.Compose_NewMessage, subtitle: nil),
ApplicationShortcutItem(type: .camera, title: strings.Camera_Title), ApplicationShortcutItem(type: .savedMessages, title: strings.Conversation_SavedMessages, subtitle: nil),
ApplicationShortcutItem(type: .savedMessages, title: strings.Conversation_SavedMessages) ApplicationShortcutItem(type: .account, title: strings.Shortcut_SwitchAccount, subtitle: otherAccountName)
] ]
} else {
return [
ApplicationShortcutItem(type: .search, title: strings.Common_Search, subtitle: nil),
ApplicationShortcutItem(type: .compose, title: strings.Compose_NewMessage, subtitle: nil),
ApplicationShortcutItem(type: .camera, title: strings.Camera_Title, subtitle: nil),
ApplicationShortcutItem(type: .savedMessages, title: strings.Conversation_SavedMessages, subtitle: nil)
]
}
} }