Files
Swiftgram/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreenSettingsActions.swift
2026-03-10 23:45:27 +02:00

396 lines
22 KiB
Swift

import SGStrings
import SGSettingsUI
import Foundation
import UIKit
import Display
import AccountContext
import SwiftSignalKit
import Postbox
import TelegramCore
import SettingsUI
import PeerInfoStoryGridScreen
import CallListUI
import PassportUI
import AccountUtils
import OverlayStatusController
import PremiumUI
import TelegramPresentationData
import PresentationDataUtils
import PasswordSetupUI
import InstantPageCache
extension PeerInfoScreenNode {
func openSettings(section: PeerInfoSettingsSection) {
let push: (ViewController) -> Void = { [weak self] c in
guard let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController else {
return
}
if strongSelf.isMyProfile {
navigationController.pushViewController(c)
} else {
var updatedControllers = navigationController.viewControllers
for controller in navigationController.viewControllers.reversed() {
if controller !== strongSelf && !(controller is TabBarController) {
updatedControllers.removeLast()
} else {
break
}
}
updatedControllers.append(c)
var animated = true
if let validLayout = strongSelf.validLayout?.0, case .regular = validLayout.metrics.widthClass {
animated = false
}
navigationController.setViewControllers(updatedControllers, animated: animated)
}
}
switch section {
case .swiftgram:
self.controller?.push(sgSettingsController(context: self.context))
case .swiftgramPro:
if self.context.sharedContext.immediateSGStatus.status > 1 {
self.controller?.push(self.context.sharedContext.makeSGProController(context: self.context))
} else {
if let payWallController = self.context.sharedContext.makeSGPayWallController(context: self.context) {
self.controller?.present(payWallController, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} else {
self.controller?.present(self.context.sharedContext.makeSGUpdateIOSController(), animated: true)
}
}
case .avatar:
self.controller?.openAvatarForEditing()
case .edit:
self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
case .proxy:
self.controller?.push(proxySettingsController(context: self.context))
case .profile:
self.controller?.push(PeerInfoScreenImpl(
context: self.context,
updatedPresentationData: self.controller?.updatedPresentationData,
peerId: self.context.account.peerId,
avatarInitiallyExpanded: false,
isOpenedFromChat: false,
nearbyPeerDistance: nil,
reactionSourceMessageId: nil,
callMessages: [],
isMyProfile: true,
profileGiftsContext: self.data?.profileGiftsContext
))
case .stories:
push(PeerInfoStoryGridScreen(context: self.context, peerId: self.context.account.peerId, scope: .saved))
case .savedMessages:
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
guard let self, let peer = peer else {
return
}
if let controller = self.controller, let navigationController = controller.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer)))
}
})
case .recentCalls:
push(CallListController(context: context, mode: .navigation))
case .devices:
let _ = (self.activeSessionsContextAndCount.get()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self] activeSessionsContextAndCount in
if let strongSelf = self, let activeSessionsContextAndCount = activeSessionsContextAndCount {
let (activeSessionsContext, _, webSessionsContext) = activeSessionsContextAndCount
push(recentSessionsController(context: strongSelf.context, activeSessionsContext: activeSessionsContext, webSessionsContext: webSessionsContext, websitesOnly: false))
}
})
case .chatFolders:
let controller = self.context.sharedContext.makeFilterSettingsController(context: self.context, modal: false, scrollToTags: false, dismissed: nil)
push(controller)
case .notificationsAndSounds:
if let settings = self.data?.globalSettings {
push(notificationsAndSoundsController(context: self.context, exceptionsList: settings.notificationExceptions))
}
case .privacyAndSecurity:
if let settings = self.data?.globalSettings {
let _ = (combineLatest(self.blockedPeers.get(), self.hasTwoStepAuth.get())
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self] blockedPeersContext, hasTwoStepAuth in
if let strongSelf = self {
let loginEmailPattern = strongSelf.twoStepAuthData.get() |> map { data -> String? in
return data?.loginEmailPattern
}
push(privacyAndSecurityController(context: strongSelf.context, initialSettings: settings.privacySettings, updatedSettings: { [weak self] settings in
self?.privacySettings.set(.single(settings))
}, updatedBlockedPeers: { [weak self] blockedPeersContext in
self?.blockedPeers.set(.single(blockedPeersContext))
}, updatedHasTwoStepAuth: { [weak self] hasTwoStepAuthValue in
self?.hasTwoStepAuth.set(.single(hasTwoStepAuthValue))
}, focusOnItemTag: nil, activeSessionsContext: settings.activeSessionsContext, webSessionsContext: settings.webSessionsContext, blockedPeersContext: blockedPeersContext, hasTwoStepAuth: hasTwoStepAuth, loginEmailPattern: loginEmailPattern, updatedTwoStepAuthData: { [weak self] in
if let strongSelf = self {
strongSelf.twoStepAuthData.set(
strongSelf.context.engine.auth.twoStepAuthData()
|> map(Optional.init)
|> `catch` { _ -> Signal<TwoStepAuthData?, NoError> in
return .single(nil)
}
)
}
}, requestPublicPhotoSetup: { [weak self] completion in
if let self {
self.controller?.openAvatarForEditing(mode: .fallback, completion: completion)
}
}, requestPublicPhotoRemove: { [weak self] completion in
if let self {
self.controller?.openAvatarRemoval(mode: .fallback, completion: completion)
}
}))
}
})
}
case .passwordSetup:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.6, execute: { [weak self] in
guard let self else {
return
}
let _ = self.context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupPassword.id).startStandalone()
})
let controller = self.context.sharedContext.makeSetupTwoFactorAuthController(context: self.context)
push(controller)
case .dataAndStorage:
push(dataAndStorageController(context: self.context))
case .appearance:
push(themeSettingsController(context: self.context))
case .language:
push(LocalizationListController(context: self.context))
case .premium:
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .settings, forceDark: false, dismissed: nil)
self.controller?.push(controller)
case .premiumGift:
guard let controller = self.controller, !controller.presentAccountFrozenInfoIfNeeded() else {
return
}
let _ = (self.context.account.stateManager.contactBirthdays
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] birthdays in
guard let self else {
return
}
let giftsController = self.context.sharedContext.makePremiumGiftController(context: self.context, source: .settings(birthdays), completion: nil)
self.controller?.push(giftsController)
})
case .stickers:
if let settings = self.data?.globalSettings {
push(installedStickerPacksController(context: self.context, mode: .general, archivedPacks: settings.archivedStickerPacks, updatedPacks: { [weak self] packs in
self?.archivedPacks.set(.single(packs))
}))
}
case .passport:
self.controller?.push(SecureIdAuthController(context: self.context, mode: .list))
case .watch:
push(watchSettingsController(context: self.context))
case .support:
let supportPeer = Promise<PeerId?>()
supportPeer.set(context.engine.peers.supportPeerId())
self.controller?.present(textAlertController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData, title: nil, text: self.presentationData.strings.Settings_FAQ_Intro, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_FAQ_Button, action: { [weak self] in
self?.openFaq()
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { [weak self] in
guard let self else {
return
}
self.supportPeerDisposable.set((supportPeer.get() |> take(1) |> deliverOnMainQueue).startStrict(next: { [weak self] peerId in
if let strongSelf = self, let peerId = peerId {
push(strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil))
}
}))
})]), in: .window(.root))
case .faq:
self.openFaq()
case .tips:
self.openTips()
case .phoneNumber:
guard let controller = self.controller, !controller.presentAccountFrozenInfoIfNeeded() else {
return
}
if let user = self.data?.peer as? TelegramUser, let phoneNumber = user.phone {
let introController = PrivacyIntroController(context: self.context, mode: .changePhoneNumber(phoneNumber), proceedAction: { [weak self] in
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
navigationController.replaceTopController(ChangePhoneNumberController(context: strongSelf.context), animated: true)
}
})
push(introController)
}
case .username:
guard let controller = self.controller, !controller.presentAccountFrozenInfoIfNeeded() else {
return
}
push(usernameSetupController(context: self.context))
case .addAccount:
let _ = (activeAccountsAndPeers(context: context)
|> take(1)
|> deliverOnMainQueue
).startStandalone(next: { [weak self] accountAndPeer, accountsAndPeers in
guard let strongSelf = self else {
return
}
var maximumAvailableAccounts: Int = maximumSwiftgramNumberOfAccounts
if accountAndPeer?.1.isPremium == true && !strongSelf.context.account.testingEnvironment {
maximumAvailableAccounts = maximumSwiftgramNumberOfAccounts
}
var count: Int = 1
for (accountContext, peer, _) in accountsAndPeers {
if !accountContext.account.testingEnvironment {
if peer.isPremium {
maximumAvailableAccounts = maximumSwiftgramNumberOfAccounts
}
count += 1
}
}
if count >= maximumAvailableAccounts {
var replaceImpl: ((ViewController) -> Void)?
let controller = PremiumLimitScreen(context: strongSelf.context, subject: .accounts, count: Int32(count), action: {
let controller = PremiumIntroScreen(context: strongSelf.context, source: .accounts)
replaceImpl?(controller)
return true
})
replaceImpl = { [weak controller] c in
controller?.replace(with: c)
}
if let navigationController = strongSelf.context.sharedContext.mainWindow?.viewController as? NavigationController {
navigationController.pushViewController(controller)
}
} else {
// MARK: Swiftgram
if count + 1 > maximumSafeNumberOfAccounts {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let alertController = textAlertController(context: strongSelf.context, updatedPresentationData: strongSelf.controller?.updatedPresentationData, title: presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: i18n("Auth.AccountBackupReminder", presentationData.strings.baseLanguageCode), actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
})
])
if let controller = strongSelf.controller {
controller.present(alertController, in: .window(.root))
} else {
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
}
} else {
strongSelf.context.sharedContext.beginNewAuth(testingEnvironment: strongSelf.context.account.testingEnvironment)
}
//
}
})
case .logout:
if let user = self.data?.peer as? TelegramUser, let phoneNumber = user.phone {
if let controller = self.controller, let navigationController = controller.navigationController as? NavigationController {
self.controller?.push(logoutOptionsController(context: self.context, navigationController: navigationController, canAddAccounts: true, phoneNumber: phoneNumber))
}
}
case .rememberPassword:
let context = self.context
let controller = TwoFactorDataInputScreen(sharedContext: self.context.sharedContext, engine: .authorized(self.context.engine), mode: .rememberPassword(doneText: self.presentationData.strings.TwoFactorSetup_Done_Action), stateUpdated: { _ in
}, presentation: .modalInLargeLayout)
controller.twoStepAuthSettingsController = { configuration in
return twoStepVerificationUnlockSettingsController(context: context, mode: .access(intro: false, data: .single(TwoStepVerificationUnlockSettingsControllerData.access(configuration: TwoStepVerificationAccessConfiguration(configuration: configuration, password: nil)))))
}
controller.passwordRemembered = {
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.validatePassword.id).startStandalone()
}
push(controller)
case .emojiStatus:
self.headerNode.invokeDisplayPremiumIntro()
case .profileColor:
self.interaction.editingOpenNameColorSetup()
case .powerSaving:
push(energySavingSettingsScreen(context: self.context))
case .businessSetup:
guard let controller = self.controller, !controller.presentAccountFrozenInfoIfNeeded() else {
return
}
push(self.context.sharedContext.makeBusinessSetupScreen(context: self.context))
case .premiumManagement:
guard let controller = self.controller else {
return
}
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
let url = premiumConfiguration.subscriptionManagementUrl
guard !url.isEmpty else {
return
}
self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: !url.hasPrefix("tg://") && !url.contains("?start="), presentationData: self.context.sharedContext.currentPresentationData.with({$0}), navigationController: controller.navigationController as? NavigationController, dismissInput: {})
case .stars:
if let starsContext = self.controller?.starsContext {
push(self.context.sharedContext.makeStarsTransactionsScreen(context: self.context, starsContext: starsContext))
}
case .ton:
if let tonContext = self.controller?.tonContext {
push(self.context.sharedContext.makeStarsTransactionsScreen(context: self.context, starsContext: tonContext))
}
}
}
func setupFaqIfNeeded() {
if !self.didSetCachedFaq {
self.cachedFaq.set(.single(nil) |> then(cachedFaqInstantPage(context: self.context) |> map(Optional.init)))
self.didSetCachedFaq = true
}
}
func openFaq(anchor: String? = nil) {
self.setupFaqIfNeeded()
let presentationData = self.presentationData
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
self?.controller?.present(controller, in: .window(.root))
return ActionDisposable { [weak controller] in
Queue.mainQueue().async() {
controller?.dismiss()
}
}
}
|> runOn(Queue.mainQueue())
|> delay(0.15, queue: Queue.mainQueue())
let progressDisposable = progressSignal.start()
let _ = (self.cachedFaq.get()
|> filter { $0 != nil }
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] resolvedUrl in
progressDisposable.dispose()
if let strongSelf = self, let resolvedUrl = resolvedUrl {
var resolvedUrl = resolvedUrl
if case let .instantView(webPage, _) = resolvedUrl, let customAnchor = anchor {
resolvedUrl = .instantView(webPage, customAnchor)
}
strongSelf.context.sharedContext.openResolvedUrl(resolvedUrl, context: strongSelf.context, urlContext: .generic, navigationController: strongSelf.controller?.navigationController as? NavigationController, forceExternal: false, forceUpdate: false, openPeer: { peer, navigation in
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, requestMessageActionUrlAuth: nil, joinVoiceChat: nil, present: { [weak self] controller, arguments in
self?.controller?.push(controller)
}, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
}
})
}
private func openTips() {
let controller = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: nil))
self.controller?.present(controller, in: .window(.root))
let context = self.context
let navigationController = self.controller?.navigationController as? NavigationController
self.tipsPeerDisposable.set((self.context.engine.peers.resolvePeerByName(name: self.presentationData.strings.Settings_TipsUsername, referrer: nil)
|> mapToSignal { result -> Signal<EnginePeer?, NoError> in
guard case let .result(result) = result else {
return .complete()
}
return .single(result)
}
|> deliverOnMainQueue).startStrict(next: { [weak controller] peer in
controller?.dismiss()
if let peer = peer, let navigationController = navigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer)))
}
}))
}
}