mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
467 lines
24 KiB
Swift
467 lines
24 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import Display
|
|
import SwiftSignalKit
|
|
import TelegramCore
|
|
import LegacyComponents
|
|
import TelegramPresentationData
|
|
import ItemListUI
|
|
import PresentationDataUtils
|
|
import OverlayStatusController
|
|
import AccountContext
|
|
import AlertUI
|
|
import PresentationDataUtils
|
|
import UrlHandling
|
|
import AccountUtils
|
|
import PremiumUI
|
|
import PasswordSetupUI
|
|
import StorageUsageScreen
|
|
|
|
private struct DeleteAccountOptionsArguments {
|
|
let changePhoneNumber: () -> Void
|
|
let addAccount: () -> Void
|
|
let setupPrivacy: () -> Void
|
|
let setupTwoStepAuth: () -> Void
|
|
let setPasscode: () -> Void
|
|
let clearCache: () -> Void
|
|
let clearSyncedContacts: () -> Void
|
|
let deleteChats: () -> Void
|
|
let contactSupport: () -> Void
|
|
let deleteAccount: () -> Void
|
|
}
|
|
|
|
private enum DeleteAccountOptionsSection: Int32 {
|
|
case add
|
|
case privacy
|
|
case remove
|
|
case support
|
|
case delete
|
|
}
|
|
|
|
private enum DeleteAccountOptionsEntry: ItemListNodeEntry, Equatable {
|
|
case changePhoneNumber(PresentationTheme, String, String)
|
|
case addAccount(PresentationTheme, String, String)
|
|
|
|
case changePrivacy(PresentationTheme, String, String)
|
|
case setTwoStepAuth(PresentationTheme, String, String)
|
|
case setPasscode(PresentationTheme, String, String)
|
|
|
|
case clearCache(PresentationTheme, String, String)
|
|
case clearSyncedContacts(PresentationTheme, String, String)
|
|
case deleteChats(PresentationTheme, String, String)
|
|
|
|
case contactSupport(PresentationTheme, String, String)
|
|
|
|
case deleteAccount(PresentationTheme, String)
|
|
|
|
var section: ItemListSectionId {
|
|
switch self {
|
|
case .changePhoneNumber, .addAccount:
|
|
return DeleteAccountOptionsSection.add.rawValue
|
|
case .changePrivacy, .setTwoStepAuth, .setPasscode:
|
|
return DeleteAccountOptionsSection.privacy.rawValue
|
|
case .clearCache, .clearSyncedContacts, .deleteChats:
|
|
return DeleteAccountOptionsSection.remove.rawValue
|
|
case .contactSupport:
|
|
return DeleteAccountOptionsSection.support.rawValue
|
|
case .deleteAccount:
|
|
return DeleteAccountOptionsSection.delete.rawValue
|
|
}
|
|
}
|
|
|
|
var stableId: Int32 {
|
|
switch self {
|
|
case .changePhoneNumber:
|
|
return 0
|
|
case .addAccount:
|
|
return 1
|
|
case .changePrivacy:
|
|
return 2
|
|
case .setTwoStepAuth:
|
|
return 3
|
|
case .setPasscode:
|
|
return 4
|
|
case .clearCache:
|
|
return 5
|
|
case .clearSyncedContacts:
|
|
return 6
|
|
case .deleteChats:
|
|
return 7
|
|
case .contactSupport:
|
|
return 8
|
|
case .deleteAccount:
|
|
return 9
|
|
}
|
|
}
|
|
|
|
static func <(lhs: DeleteAccountOptionsEntry, rhs: DeleteAccountOptionsEntry) -> Bool {
|
|
return lhs.stableId < rhs.stableId
|
|
}
|
|
|
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
|
let arguments = arguments as! DeleteAccountOptionsArguments
|
|
switch self {
|
|
case let .changePhoneNumber(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.changePhoneNumber, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.changePhoneNumber()
|
|
})
|
|
case let .addAccount(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteAddAccount, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.addAccount()
|
|
})
|
|
case let .changePrivacy(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.security, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.setupPrivacy()
|
|
})
|
|
case let .setTwoStepAuth(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteSetTwoStepAuth, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.setupTwoStepAuth()
|
|
})
|
|
case let .setPasscode(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteSetPasscode, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.setPasscode()
|
|
})
|
|
case let .clearCache(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.dataAndStorage, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.clearCache()
|
|
})
|
|
case let .clearSyncedContacts(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.clearSynced, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.clearSyncedContacts()
|
|
})
|
|
case let .deleteChats(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.deleteChats, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.deleteChats()
|
|
})
|
|
case let .contactSupport(_, title, text):
|
|
return ItemListDisclosureItem(presentationData: presentationData, icon: PresentationResourcesSettings.support, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
|
|
arguments.contactSupport()
|
|
})
|
|
case let .deleteAccount(_, title):
|
|
return ItemListActionItem(presentationData: presentationData, title: title, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
|
|
arguments.deleteAccount()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
private func deleteAccountOptionsEntries(presentationData: PresentationData, canAddAccounts: Bool, hasTwoStepAuth: Bool, hasPasscode: Bool) -> [DeleteAccountOptionsEntry] {
|
|
var entries: [DeleteAccountOptionsEntry] = []
|
|
|
|
entries.append(.changePhoneNumber(presentationData.theme, presentationData.strings.DeleteAccount_Options_ChangePhoneNumberTitle, presentationData.strings.DeleteAccount_Options_ChangePhoneNumberText))
|
|
if canAddAccounts {
|
|
entries.append(.addAccount(presentationData.theme, presentationData.strings.DeleteAccount_Options_AddAccountTitle, presentationData.strings.DeleteAccount_Options_AddAccountText))
|
|
}
|
|
|
|
entries.append(.changePrivacy(presentationData.theme, presentationData.strings.DeleteAccount_Options_ChangePrivacyTitle, presentationData.strings.DeleteAccount_Options_ChangePrivacyText))
|
|
if !hasTwoStepAuth {
|
|
entries.append(.setTwoStepAuth(presentationData.theme, presentationData.strings.DeleteAccount_Options_SetTwoStepAuthTitle, presentationData.strings.DeleteAccount_Options_SetTwoStepAuthText))
|
|
}
|
|
if !hasPasscode {
|
|
entries.append(.setPasscode(presentationData.theme, presentationData.strings.DeleteAccount_Options_SetPasscodeTitle, presentationData.strings.DeleteAccount_Options_SetPasscodeText))
|
|
}
|
|
entries.append(.clearCache(presentationData.theme, presentationData.strings.DeleteAccount_Options_ClearCacheTitle, presentationData.strings.DeleteAccount_Options_ClearCacheText))
|
|
entries.append(.clearSyncedContacts(presentationData.theme, presentationData.strings.DeleteAccount_Options_ClearSyncedContactsTitle, presentationData.strings.DeleteAccount_Options_ClearSyncedContactsText))
|
|
entries.append(.deleteChats(presentationData.theme, presentationData.strings.DeleteAccount_Options_DeleteChatsTitle, presentationData.strings.DeleteAccount_Options_DeleteChatsText))
|
|
|
|
entries.append(.contactSupport(presentationData.theme, presentationData.strings.DeleteAccount_Options_ContactSupportTitle, presentationData.strings.DeleteAccount_Options_ContactSupportText))
|
|
|
|
entries.append(.deleteAccount(presentationData.theme, presentationData.strings.DeleteAccount_DeleteMyAccount))
|
|
|
|
return entries
|
|
}
|
|
|
|
public func deleteAccountOptionsController(context: AccountContext, navigationController: NavigationController, hasTwoStepAuth: Bool, twoStepAuthData: TwoStepVerificationAccessConfiguration?) -> ViewController {
|
|
var pushControllerImpl: ((ViewController) -> Void)?
|
|
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
|
var replaceTopControllerImpl: ((ViewController, Bool) -> Void)?
|
|
var dismissImpl: (() -> Void)?
|
|
|
|
let supportPeerDisposable = MetaDisposable()
|
|
|
|
let arguments = DeleteAccountOptionsArguments(changePhoneNumber: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_phone_change_tap")
|
|
|
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.engine.account.peerId))
|
|
|> deliverOnMainQueue).start(next: { accountPeer in
|
|
guard let accountPeer = accountPeer, case let .user(user) = accountPeer else {
|
|
return
|
|
}
|
|
let introController = PrivacyIntroController(context: context, mode: .changePhoneNumber(user.phone ?? ""), proceedAction: {
|
|
replaceTopControllerImpl?(ChangePhoneNumberController(context: context), false)
|
|
})
|
|
pushControllerImpl?(introController)
|
|
dismissImpl?()
|
|
})
|
|
}, addAccount: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_add_account_tap")
|
|
|
|
let _ = (activeAccountsAndPeers(context: context)
|
|
|> take(1)
|
|
|> deliverOnMainQueue
|
|
).start(next: { accountAndPeer, accountsAndPeers in
|
|
var maximumAvailableAccounts: Int = 3
|
|
if accountAndPeer?.1.isPremium == true && !context.account.testingEnvironment {
|
|
maximumAvailableAccounts = 4
|
|
}
|
|
var count: Int = 1
|
|
for (accountContext, peer, _) in accountsAndPeers {
|
|
if !accountContext.account.testingEnvironment {
|
|
if peer.isPremium {
|
|
maximumAvailableAccounts = 4
|
|
}
|
|
count += 1
|
|
}
|
|
}
|
|
|
|
if count >= maximumAvailableAccounts {
|
|
var replaceImpl: ((ViewController) -> Void)?
|
|
let controller = PremiumLimitScreen(context: context, subject: .accounts, count: Int32(count), action: {
|
|
let controller = PremiumIntroScreen(context: context, source: .accounts)
|
|
replaceImpl?(controller)
|
|
return true
|
|
})
|
|
replaceImpl = { [weak controller] c in
|
|
controller?.replace(with: c)
|
|
}
|
|
pushControllerImpl?(controller)
|
|
} else {
|
|
context.sharedContext.beginNewAuth(testingEnvironment: context.account.testingEnvironment)
|
|
|
|
dismissImpl?()
|
|
}
|
|
})
|
|
}, setupPrivacy: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_privacy_tap")
|
|
|
|
replaceTopControllerImpl?(makePrivacyAndSecurityController(context: context), false)
|
|
}, setupTwoStepAuth: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_2fa_tap")
|
|
|
|
if let data = twoStepAuthData {
|
|
switch data {
|
|
case .set:
|
|
break
|
|
case let .notSet(pendingEmail):
|
|
if pendingEmail == nil {
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
let controller = TwoFactorAuthSplashScreen(sharedContext: context.sharedContext, engine: .authorized(context.engine), mode: .intro(.init(
|
|
title: presentationData.strings.TwoFactorSetup_Intro_Title,
|
|
text: presentationData.strings.TwoFactorSetup_Intro_Text,
|
|
actionText: presentationData.strings.TwoFactorSetup_Intro_Action,
|
|
doneText: presentationData.strings.TwoFactorSetup_Done_Action,
|
|
phoneNumber: nil
|
|
)))
|
|
|
|
replaceTopControllerImpl?(controller, false)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
let controller = twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: twoStepAuthData.flatMap({ Signal<TwoStepVerificationUnlockSettingsControllerData, NoError>.single(.access(configuration: $0)) })))
|
|
replaceTopControllerImpl?(controller, false)
|
|
}, setPasscode: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_passcode_tap")
|
|
|
|
let _ = passcodeOptionsAccessController(context: context, pushController: { controller in
|
|
replaceTopControllerImpl?(controller, false)
|
|
}, completion: { _ in
|
|
replaceTopControllerImpl?(passcodeOptionsController(context: context), false)
|
|
}).start(next: { controller in
|
|
if let controller = controller {
|
|
pushControllerImpl?(controller)
|
|
}
|
|
})
|
|
dismissImpl?()
|
|
}, clearCache: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_cache_tap")
|
|
|
|
pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
|
|
return storageUsageExceptionsScreen(context: context, category: category)
|
|
}))
|
|
dismissImpl?()
|
|
}, clearSyncedContacts: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_contacts_tap")
|
|
|
|
replaceTopControllerImpl?(dataPrivacyController(context: context), false)
|
|
}, deleteChats: {
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_delete_chats_tap")
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
|
|
var faqUrl = presentationData.strings.DeleteAccount_DeleteMessagesURL
|
|
if faqUrl == "DeleteAccount.DeleteMessagesURL" || faqUrl.isEmpty {
|
|
faqUrl = "https://telegram.org/faq#q-can-i-delete-my-messages"
|
|
}
|
|
let resolvedUrl = resolveInstantViewUrl(account: context.account, url: faqUrl)
|
|
|> mapToSignal { result -> Signal<ResolvedUrl, NoError> in
|
|
guard case let .result(result) = result else {
|
|
return .complete()
|
|
}
|
|
return .single(result)
|
|
}
|
|
|
|
let resolvedUrlPromise = Promise<ResolvedUrl>()
|
|
resolvedUrlPromise.set(resolvedUrl)
|
|
|
|
let openFaq: (Promise<ResolvedUrl>) -> Void = { resolvedUrl in
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
|
presentControllerImpl?(controller, nil)
|
|
let _ = (resolvedUrl.get()
|
|
|> take(1)
|
|
|> deliverOnMainQueue).start(next: { [weak controller] resolvedUrl in
|
|
controller?.dismiss()
|
|
dismissImpl?()
|
|
|
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
|
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
|
pushControllerImpl?(controller)
|
|
}, dismissInput: {}, contentContext: nil)
|
|
})
|
|
}
|
|
|
|
openFaq(resolvedUrlPromise)
|
|
}, contactSupport: { [weak navigationController] in
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_tap")
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
|
|
let supportPeer = Promise<EnginePeer.Id?>()
|
|
supportPeer.set(context.engine.peers.supportPeerId())
|
|
|
|
var faqUrl = presentationData.strings.Settings_FAQ_URL
|
|
if faqUrl == "Settings.FAQ_URL" || faqUrl.isEmpty {
|
|
faqUrl = "https://telegram.org/faq#general"
|
|
}
|
|
let resolvedUrl = resolveInstantViewUrl(account: context.account, url: faqUrl)
|
|
|> mapToSignal { result -> Signal<ResolvedUrl, NoError> in
|
|
guard case let .result(result) = result else {
|
|
return .complete()
|
|
}
|
|
return .single(result)
|
|
}
|
|
|
|
let resolvedUrlPromise = Promise<ResolvedUrl>()
|
|
resolvedUrlPromise.set(resolvedUrl)
|
|
|
|
let openFaq: (Promise<ResolvedUrl>) -> Void = { resolvedUrl in
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
|
presentControllerImpl?(controller, nil)
|
|
let _ = (resolvedUrl.get()
|
|
|> take(1)
|
|
|> deliverOnMainQueue).start(next: { [weak controller] resolvedUrl in
|
|
controller?.dismiss()
|
|
dismissImpl?()
|
|
|
|
context.sharedContext.openResolvedUrl(resolvedUrl, context: context, urlContext: .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigation in
|
|
}, sendFile: nil, sendSticker: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { controller, arguments in
|
|
pushControllerImpl?(controller)
|
|
}, dismissInput: {}, contentContext: nil)
|
|
})
|
|
}
|
|
|
|
let alertController = textAlertController(context: context, title: nil, text: presentationData.strings.Settings_FAQ_Intro, actions: [
|
|
TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_FAQ_Button, action: {
|
|
openFaq(resolvedUrlPromise)
|
|
dismissImpl?()
|
|
}),
|
|
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
|
supportPeerDisposable.set((supportPeer.get()
|
|
|> take(1)
|
|
|> deliverOnMainQueue).start(next: { peerId in
|
|
guard let peerId = peerId else {
|
|
return
|
|
}
|
|
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
|
|> deliverOnMainQueue).start(next: { peer in
|
|
guard let peer = peer else {
|
|
return
|
|
}
|
|
if let navigationController = navigationController {
|
|
dismissImpl?()
|
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer)))
|
|
}
|
|
})
|
|
}))
|
|
})
|
|
])
|
|
alertController.dismissed = { _ in
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_support_cancel")
|
|
}
|
|
presentControllerImpl?(alertController, nil)
|
|
}, deleteAccount: {
|
|
let controller = deleteAccountDataController(context: context, mode: .peers, twoStepAuthData: twoStepAuthData)
|
|
replaceTopControllerImpl?(controller, true)
|
|
})
|
|
|
|
let signal = combineLatest(queue: .mainQueue(),
|
|
context.sharedContext.presentationData,
|
|
context.sharedContext.accountManager.accessChallengeData(),
|
|
activeAccountsAndPeers(context: context)
|
|
)
|
|
|> map { presentationData, accessChallengeData, accountsAndPeers -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
|
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
|
|
dismissImpl?()
|
|
})
|
|
|
|
var hasPasscode = false
|
|
switch accessChallengeData.data {
|
|
case .numericalPassword, .plaintextPassword:
|
|
hasPasscode = true
|
|
default:
|
|
break
|
|
}
|
|
|
|
let canAddAccounts = accountsAndPeers.1.count + 1 < maximumNumberOfAccounts
|
|
|
|
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.DeleteAccount_AlternativeOptionsTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
|
|
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: deleteAccountOptionsEntries(presentationData: presentationData, canAddAccounts: canAddAccounts, hasTwoStepAuth: hasTwoStepAuth, hasPasscode: hasPasscode), style: .blocks)
|
|
|
|
return (controllerState, (listState, arguments))
|
|
}
|
|
|
|
let controller = ItemListController(context: context, state: signal, tabBarItem: nil)
|
|
controller.navigationPresentation = .modal
|
|
pushControllerImpl = { [weak navigationController] value in
|
|
navigationController?.pushViewController(value, animated: false)
|
|
}
|
|
presentControllerImpl = { [weak controller] value, arguments in
|
|
controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
|
}
|
|
replaceTopControllerImpl = { [weak navigationController] c, complex in
|
|
if complex {
|
|
navigationController?.pushViewController(c, completion: { [weak navigationController, weak controller, weak c] in
|
|
if let navigationController = navigationController {
|
|
let controllers = navigationController.viewControllers.filter { $0 !== controller }
|
|
c?.navigationPresentation = .modal
|
|
navigationController.setViewControllers(controllers, animated: false)
|
|
}
|
|
})
|
|
} else {
|
|
if c is PrivacyAndSecurityControllerImpl {
|
|
if let navigationController = navigationController {
|
|
if let existing = navigationController.viewControllers.first(where: { $0 is PrivacyAndSecurityControllerImpl }) as? ViewController {
|
|
existing.scrollToTop?()
|
|
dismissImpl?()
|
|
} else {
|
|
navigationController.replaceTopController(c, animated: true)
|
|
}
|
|
}
|
|
} else {
|
|
navigationController?.replaceTopController(c, animated: true)
|
|
}
|
|
}
|
|
}
|
|
dismissImpl = { [weak controller] in
|
|
let _ = controller?.dismiss()
|
|
}
|
|
|
|
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_show")
|
|
|
|
return controller
|
|
}
|
|
|