Various improvements

This commit is contained in:
Ilya Laktyushin 2025-11-04 14:43:17 +04:00
parent 7cf87859a8
commit 6f5cd84019
17 changed files with 201 additions and 122 deletions

View File

@ -1467,6 +1467,8 @@ public protocol SharedAccountContext: AnyObject {
func makeNewContactScreen(context: AccountContext, peer: EnginePeer?, phoneNumber: String?, shareViaException: Bool, completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void) -> ViewController
func makeLoginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, canAutoDismissIfNeeded: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController
func navigateToCurrentCall()
var hasOngoingCall: ValuePromise<Bool> { get }
var immediateHasOngoingCall: Bool { get }

View File

@ -2,8 +2,10 @@ import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import TelegramPresentationData
import ProgressNavigationButtonNode
import AccountContext
public final class AuthorizationSequenceEmailEntryController: ViewController {
public enum Mode {
@ -39,7 +41,10 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
public var authorization: Any?
public var authorizationDelegate: Any?
public init(presentationData: PresentationData, mode: Mode, blocking: Bool = false, back: @escaping () -> Void) {
private var inBackground = false
private var inBackgroundDisposable: Disposable?
public init(context: AccountContext? = nil, presentationData: PresentationData, mode: Mode, blocking: Bool = false, back: @escaping () -> Void) {
self.presentationData = presentationData
self.mode = mode
self.blocking = blocking
@ -58,12 +63,43 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
self.navigationBar?.backPressed = {
back()
}
if self.blocking {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
}
if let context {
self.inBackgroundDisposable = (context.sharedContext.applicationBindings.applicationInForeground
|> deliverOnMainQueue).start(next: { [weak self] value in
guard let self else {
return
}
let previousValue = self.inBackground
self.inBackground = value
if !value && previousValue {
let _ = (context.engine.notices.getServerProvidedSuggestions(reload: true)
|> deliverOnMainQueue).start(next: { [weak self] currentValues in
guard let self else {
return
}
if !currentValues.contains(.setupLoginEmail) && !currentValues.contains(.setupLoginEmailBlocking) {
self.dismiss()
}
})
}
})
}
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.inBackgroundDisposable?.dispose()
}
override public func loadDisplayNode() {
self.displayNode = AuthorizationSequenceEmailEntryControllerNode(strings: self.presentationData.strings, theme: self.presentationData.theme, mode: self.mode)
self.displayNodeDidLoad()
@ -92,10 +128,6 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
return
}
if self.blocking {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
}
if self.inProgress {
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
self.navigationItem.rightBarButtonItem = item
@ -118,7 +150,7 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
}
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
let hadLayout = self.validLayout != nil

View File

@ -136,6 +136,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
private let suggestAutoarchiveDisposable = MetaDisposable()
private let dismissAutoarchiveDisposable = MetaDisposable()
private var didSuggestAutoarchive = false
private var didSuggestLoginEmailSetup = false
private var presentationData: PresentationData
private let presentationDataValue = Promise<PresentationData>()
@ -2551,6 +2552,35 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard let strongSelf = self else {
return
}
let context = strongSelf.context
if values.contains(.setupLoginEmail) || values.contains(.setupLoginEmailBlocking) {
if strongSelf.didSuggestLoginEmailSetup {
return
}
strongSelf.didSuggestLoginEmailSetup = true
let _ = (context.engine.notices.getServerProvidedSuggestions(reload: true)
|> deliverOnMainQueue).start(next: { [weak self] currentValues in
guard let strongSelf = self, currentValues.contains(.setupLoginEmail) || currentValues.contains(.setupLoginEmailBlocking) else {
return
}
if let navigationController = strongSelf.navigationController as? NavigationController {
let blocking = currentValues.contains(.setupLoginEmailBlocking)
let controller = strongSelf.context.sharedContext.makeLoginEmailSetupController(context: strongSelf.context, blocking: blocking, emailPattern: nil, canAutoDismissIfNeeded: true, navigationController: navigationController, completion: {
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: blocking ? ServerProvidedSuggestion.setupLoginEmailBlocking.id : ServerProvidedSuggestion.setupLoginEmail.id).startStandalone()
}, dismiss: {
if !blocking {
let _ = context.engine.notices.dismissServerProvidedSuggestion(suggestion: ServerProvidedSuggestion.setupLoginEmail.id).startStandalone()
}
})
navigationController.pushViewController(controller)
}
})
return
}
if strongSelf.didSuggestAutoarchive {
return
}

View File

@ -32,7 +32,7 @@ final class LoginEmailSetupDelegate: NSObject, ASAuthorizationControllerDelegate
}
}
public func loginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, navigationController: NavigationController?, completion: @escaping () -> Void) -> ViewController {
public func loginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, canAutoDismissIfNeeded: Bool = false, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var dismissEmailControllerImpl: (() -> Void)?
var presentControllerImpl: ((ViewController) -> Void)?
@ -65,7 +65,7 @@ public func loginEmailSetupController(context: AccountContext, blocking: Bool, e
}
}
let emailController = AuthorizationSequenceEmailEntryController(presentationData: presentationData, mode: emailPattern != nil ? .change : .setup, blocking: blocking, back: {
let emailController = AuthorizationSequenceEmailEntryController(context: canAutoDismissIfNeeded ? context : nil, presentationData: presentationData, mode: emailPattern != nil ? .change : .setup, blocking: blocking, back: {
dismissEmailControllerImpl?()
})
emailController.proceedWithEmail = { [weak emailController] email in
@ -78,6 +78,7 @@ public func loginEmailSetupController(context: AccountContext, blocking: Bool, e
let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: {
dismissCodeControllerImpl?()
dismiss()
})
presentControllerImpl = { [weak codeController] c in

View File

@ -682,8 +682,12 @@ private func privacyAndSecurityControllerEntries(
showLoginEmail = true
}
if showLoginEmail {
var hasLoginEmail = false
if let loginEmail {
hasLoginEmail = !loginEmail.contains(" ")
}
entries.append(.loginEmail(presentationData.theme, presentationData.strings.PrivacySettings_LoginEmail, loginEmail))
entries.append(.loginEmailInfo(presentationData.theme, loginEmail == nil ? presentationData.strings.PrivacySettings_LoginEmailSetupInfo : presentationData.strings.PrivacySettings_LoginEmailInfo))
entries.append(.loginEmailInfo(presentationData.theme, !hasLoginEmail ? presentationData.strings.PrivacySettings_LoginEmailSetupInfo : presentationData.strings.PrivacySettings_LoginEmailInfo))
}
entries.append(.privacyHeader(presentationData.theme, presentationData.strings.PrivacySettings_PrivacyTitle))
@ -1329,7 +1333,7 @@ public func privacyAndSecurityController(
}, openDataSettings: {
pushControllerImpl?(dataPrivacyController(context: context), true)
}, openEmailSettings: { emailPattern in
if let emailPattern = emailPattern {
if let emailPattern, !emailPattern.contains(" ") {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = textAlertController(
context: context, title: emailPattern, text: presentationData.strings.PrivacySettings_LoginEmailAlertText, actions: [
@ -1542,7 +1546,7 @@ public func privacyAndSecurityController(
setupEmailImpl = { emailPattern in
let controller = loginEmailSetupController(context: context, blocking: false, emailPattern: emailPattern, navigationController: getNavigationControllerImpl?(), completion: {
updatedTwoStepAuthData?()
})
}, dismiss: {})
pushControllerImpl?(controller, true)
}

View File

@ -3367,7 +3367,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
public func disableVideo() {
self.hasVideo = false
self.useFrontCamera = true;
self.useFrontCamera = true
if let _ = self.videoCapturer {
self.videoCapturer = nil
self.isVideoMutedDisposable.set(nil)

View File

@ -19,6 +19,7 @@ final class AccountTaskManager {
private var stateDisposable: Disposable?
private let tasksDisposable = MetaDisposable()
private let configurationDisposable = MetaDisposable()
private let promoDisposable = MetaDisposable()
private let managedTopReactionsDisposable = MetaDisposable()
@ -133,7 +134,6 @@ final class AccountTaskManager {
tasks.add(managedAutodownloadSettingsUpdates(accountManager: self.accountManager, network: self.stateManager.network).start())
tasks.add(managedTermsOfServiceUpdates(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedAppUpdateInfo(network: self.stateManager.network, stateManager: self.stateManager).start())
tasks.add(managedPromoInfoUpdates(accountPeerId: self.accountPeerId, postbox: self.stateManager.postbox, network: self.stateManager.network, viewTracker: self.viewTracker).start())
tasks.add(managedLocalizationUpdatesOperations(accountManager: self.accountManager, postbox: self.stateManager.postbox, network: self.stateManager.network).start())
tasks.add(managedPendingPeerNotificationSettings(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
tasks.add(managedSynchronizeAppLogEventsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
@ -155,10 +155,12 @@ final class AccountTaskManager {
self.tasksDisposable.dispose()
self.configurationDisposable.dispose()
self.managedTopReactionsDisposable.dispose()
self.promoDisposable.dispose()
}
func reloadAppConfiguration() {
self.configurationDisposable.set(managedAppConfigurationUpdates(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
self.promoDisposable.set(managedPromoInfoUpdates(accountPeerId: self.accountPeerId, postbox: self.stateManager.postbox, network: self.stateManager.network, viewTracker: self.viewTracker).start())
}
}

View File

@ -186,6 +186,63 @@ extension ServerSuggestionInfo.Item {
}
}
func _internal_fetchPromoInfo(accountPeerId: EnginePeer.Id, postbox: Postbox, network: Network) -> Signal<Void, NoError> {
return network.request(Api.functions.help.getPromoData())
|> `catch` { _ -> Signal<Api.help.PromoData, NoError> in
return .single(.promoDataEmpty(expires: 10 * 60))
}
|> mapToSignal { data -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
switch data {
case .promoDataEmpty:
transaction.replaceAdditionalChatListItems([])
let suggestionInfo = ServerSuggestionInfo(
legacyItems: [],
items: [],
dismissedIds: []
)
transaction.updatePreferencesEntry(key: PreferencesKeys.serverSuggestionInfo(), { _ in
return PreferencesEntry(suggestionInfo)
})
case let .promoData(flags, expires, peer, psaType, psaMessage, pendingSuggestions, dismissedSuggestions, customPendingSuggestion, chats, users):
let _ = expires
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
var kind: PromoChatListItem.Kind?
if let psaType {
kind = .psa(type: psaType, message: psaMessage)
} else if ((flags & 1) << 0) != 0 {
kind = .proxy
}
var additionalChatListItems: [AdditionalChatListItem] = []
if let kind, let peer, let parsedPeer = transaction.getPeer(peer.peerId) {
additionalChatListItems.append(PromoChatListItem(peerId: parsedPeer.id, kind: kind))
}
transaction.replaceAdditionalChatListItems(additionalChatListItems)
var customItems: [ServerSuggestionInfo.Item] = []
if let customPendingSuggestion {
customItems.append(ServerSuggestionInfo.Item(customPendingSuggestion))
}
let suggestionInfo = ServerSuggestionInfo(
legacyItems: pendingSuggestions,
items: customItems,
dismissedIds: dismissedSuggestions
)
transaction.updatePreferencesEntry(key: PreferencesKeys.serverSuggestionInfo(), { _ in
return PreferencesEntry(suggestionInfo)
})
}
}
}
}
func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: Network, viewTracker: AccountViewTracker) -> Signal<Void, NoError> {
return Signal { subscriber in
let queue = Queue()
@ -193,62 +250,7 @@ func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: N
|> distinctUntilChanged
|> deliverOn(queue)
|> mapToSignal { _ -> Signal<Void, NoError> in
let appliedOnce: Signal<Void, NoError> = network.request(Api.functions.help.getPromoData())
|> `catch` { _ -> Signal<Api.help.PromoData, NoError> in
return .single(.promoDataEmpty(expires: 10 * 60))
}
|> mapToSignal { data -> Signal<Void, NoError> in
return postbox.transaction { transaction -> Void in
switch data {
case .promoDataEmpty:
transaction.replaceAdditionalChatListItems([])
let suggestionInfo = ServerSuggestionInfo(
legacyItems: [],
items: [],
dismissedIds: []
)
transaction.updatePreferencesEntry(key: PreferencesKeys.serverSuggestionInfo(), { _ in
return PreferencesEntry(suggestionInfo)
})
case let .promoData(flags, expires, peer, psaType, psaMessage, pendingSuggestions, dismissedSuggestions, customPendingSuggestion, chats, users):
let _ = expires
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
var kind: PromoChatListItem.Kind?
if let psaType {
kind = .psa(type: psaType, message: psaMessage)
} else if ((flags & 1) << 0) != 0 {
kind = .proxy
}
var additionalChatListItems: [AdditionalChatListItem] = []
if let kind, let peer, let parsedPeer = transaction.getPeer(peer.peerId) {
additionalChatListItems.append(PromoChatListItem(peerId: parsedPeer.id, kind: kind))
}
transaction.replaceAdditionalChatListItems(additionalChatListItems)
var customItems: [ServerSuggestionInfo.Item] = []
if let customPendingSuggestion {
customItems.append(ServerSuggestionInfo.Item(customPendingSuggestion))
}
let suggestionInfo = ServerSuggestionInfo(
legacyItems: pendingSuggestions,
items: customItems,
dismissedIds: dismissedSuggestions
)
transaction.updatePreferencesEntry(key: PreferencesKeys.serverSuggestionInfo(), { _ in
return PreferencesEntry(suggestionInfo)
})
}
}
}
return (appliedOnce
return (_internal_fetchPromoInfo(accountPeerId: accountPeerId, postbox: postbox, network: network)
|> then(
Signal<Void, NoError>.complete()
|> delay(10.0 * 60.0, queue: Queue.concurrentDefaultQueue()))

View File

@ -167,6 +167,9 @@ func _internal_dismissServerProvidedSuggestion(account: Account, suggestion: Str
} else {
dismissedSuggestions[account.id] = Set([suggestion])
}
if suggestion == ServerProvidedSuggestion.setupLoginEmailBlocking.id {
return .complete()
}
return account.network.request(Api.functions.help.dismissSuggestion(peer: .inputPeerEmpty, suggestion: suggestion))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)

View File

@ -21,8 +21,15 @@ public extension TelegramEngine {
|> ignoreValues
}
public func getServerProvidedSuggestions() -> Signal<[ServerProvidedSuggestion], NoError> {
return _internal_getServerProvidedSuggestions(account: self.account)
public func getServerProvidedSuggestions(reload: Bool = false) -> Signal<[ServerProvidedSuggestion], NoError> {
if reload {
return _internal_fetchPromoInfo(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network)
|> mapToSignal {
return _internal_getServerProvidedSuggestions(account: self.account)
}
} else {
return _internal_getServerProvidedSuggestions(account: self.account)
}
}
public func getServerDismissedSuggestions() -> Signal<[String], NoError> {

View File

@ -315,7 +315,6 @@ private final class CameraScreenComponent: CombinedComponent {
private weak var liveStreamCall: PresentationGroupCall?
private var liveStreamVideoCapturer: OngoingCallVideoCapturer?
private var liveStreamVideoDisposable: Disposable?
private var liveStreamAudioDisposable: Disposable?
var cameraState: CameraState?
var swipeHint: CaptureControlsComponent.SwipeHint = .none
@ -370,7 +369,6 @@ private final class CameraScreenComponent: CombinedComponent {
self.lastGalleryAssetsDisposable?.dispose()
self.resultDisposable.dispose()
self.liveStreamVideoDisposable?.dispose()
self.liveStreamAudioDisposable?.dispose()
}
func setupRecentAssetSubscription() {
@ -1148,12 +1146,14 @@ private final class CameraScreenComponent: CombinedComponent {
controller.present(alertController, in: .window(.root))
}
func setupStreamCamera(call: PresentationGroupCall) {
func setupLiveStreamCamera(call: PresentationGroupCall) {
guard self.liveStreamVideoCapturer == nil, let call = call as? PresentationGroupCallImpl, let controller = self.getController() else {
return
}
self.liveStreamCall = call
call.setIsMuted(action: .unmuted)
let liveStreamMediaSource = controller.node.liveStreamMediaSource
let videoCapturer = OngoingCallVideoCapturer(keepLandscape: false, isCustom: true)
self.liveStreamVideoCapturer = videoCapturer
@ -1166,15 +1166,6 @@ private final class CameraScreenComponent: CombinedComponent {
videoCapturer.injectSampleBuffer(sampleBuffer, rotation: .up, completion: {})
}
}
self.liveStreamAudioDisposable = liveStreamMediaSource.addOnAudioUpdated { [weak self, weak liveStreamMediaSource] in
guard let self, let liveStreamMediaSource, let call = self.liveStreamCall as? PresentationGroupCallImpl else {
return
}
if let audioData = liveStreamMediaSource.currentAudioOutput {
call.addExternalAudioData(data: audioData)
}
}
Queue.mainQueue().after(1.0) {
call.requestVideo(capturer: videoCapturer, useFrontCamera: false)
}
@ -1500,7 +1491,7 @@ private final class CameraScreenComponent: CombinedComponent {
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
didSetupMediaStream: { [weak state] call in
state?.setupStreamCamera(call: call)
state?.setupLiveStreamCamera(call: call)
}
),
availableSize: availableSize,
@ -1540,7 +1531,7 @@ private final class CameraScreenComponent: CombinedComponent {
)
}
if component.cameraState.isStreaming {
if component.cameraState.mode == .live && component.cameraState.isStreaming {
let endStreamButton = endStreamButton.update(
component: GlassBarButtonComponent(
size: CGSize(width: 56.0, height: 40.0),

View File

@ -101,8 +101,8 @@ final class LiveStreamMediaSource {
private var onAudioUpdatedListeners = Bag<() -> Void>()
public init() {
let width: Int32 = 1080
let height: Int32 = 1920
let width: Int32 = 720
let height: Int32 = 1280
let dimensions = CGSize(width: CGFloat(width), height: CGFloat(height))
@ -165,7 +165,7 @@ final class LiveStreamMediaSource {
qualityPreset: nil
),
dimensions: CGSize(width: 1080.0, height: 1920.0),
outputDimensions: CGSize(width: 1080.0, height: 1920.0),
outputDimensions: CGSize(width: 720.0, height: 1280.0),
textScale: 1.0,
videoDuration: nil,
additionalVideoDuration: nil

View File

@ -5589,13 +5589,6 @@ public final class StoryItemSetContainerComponent: Component {
return
}
#if DEBUG
if "".isEmpty {
self.performDeleteAction()
return
}
#endif
self.isEditingStory = true
self.updateIsProgressPaused()
self.state?.updated(transition: .easeInOut(duration: 0.2))

View File

@ -8780,18 +8780,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
func addPeerContact() {
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let peerStatusSettings = self.presentationInterfaceState.contactStatus?.peerStatusSettings, let contactData = DeviceContactExtendedData(peer: EnginePeer(peer)) {
self.present(context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: self.context), environment: ShareControllerAppEnvironment(sharedContext: self.context.sharedContext), subject: .create(peer: peer, contactData: contactData, isSharing: true, shareViaException: peerStatusSettings.contains(.addExceptionWhenAddingContact), completion: { [weak self] peer, stableId, contactData in
guard let strongSelf = self else {
return
}
if let peer = peer as? TelegramUser {
if let phone = peer.phone, !phone.isEmpty {
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let peerStatusSettings = self.presentationInterfaceState.contactStatus?.peerStatusSettings {
let controller = self.context.sharedContext.makeNewContactScreen(
context: self.context,
peer: EnginePeer(peer),
phoneNumber: nil,
shareViaException: peerStatusSettings.contains(.addExceptionWhenAddingContact),
completion: { [weak self] peer, _, _ in
guard let self, let peer else {
return
}
self?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.AddContact_StatusSuccess(EnginePeer(peer).compactDisplayTitle).string, true)), in: .window(.root))
self.present(OverlayStatusController(theme: self.presentationData.theme, type: .genericSuccess(self.presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).string, true)), in: .window(.root))
}
}), completed: nil, cancelled: nil), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
)
self.push(controller)
}
}
@ -9777,7 +9779,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
)
strongSelf.chatDisplayNode.dismissInput()
strongSelf.present(controller, in: .window(.root))
strongSelf.push(controller)
})
}

View File

@ -199,29 +199,35 @@ public class ComposeControllerImpl: ViewController, ComposeController {
}
switch status {
case .allowed:
let contactData = DeviceContactExtendedData(basicData: DeviceContactBasicData(firstName: "", lastName: "", phoneNumbers: [DeviceContactPhoneNumberData(label: "_$!<Mobile>!$_", value: "+")]), middleName: "", prefix: "", suffix: "", organization: "", jobTitle: "", department: "", emailAddresses: [], urls: [], addresses: [], birthdayDate: nil, socialProfiles: [], instantMessagingProfiles: [], note: "")
(strongSelf.navigationController as? NavigationController)?.pushViewController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .create(peer: nil, contactData: contactData, isSharing: false, shareViaException: false, completion: { peer, stableId, contactData in
case .allowed:
let controller = strongSelf.context.sharedContext.makeNewContactScreen(
context: strongSelf.context,
peer: nil,
phoneNumber: nil,
shareViaException: false,
completion: { [weak self] peer, stableId, contactData in
guard let strongSelf = self else {
return
}
if let peer = peer {
DispatchQueue.main.async {
if let navigationController = strongSelf.navigationController as? NavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(EnginePeer(peer))))
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer)))
}
}
} else {
} else if let stableId, let contactData {
(strongSelf.navigationController as? NavigationController)?.replaceAllButRootController(strongSelf.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: strongSelf.context), environment: ShareControllerAppEnvironment(sharedContext: strongSelf.context.sharedContext), subject: .vcard(nil, stableId, contactData), completed: nil, cancelled: nil), animated: true)
}
}), completed: nil, cancelled: nil))
case .notDetermined:
DeviceAccess.authorizeAccess(to: .contacts)
default:
let presentationData = strongSelf.presentationData
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.AccessDenied_Title, text: presentationData.strings.Contacts_AccessDeniedError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
self?.context.sharedContext.applicationBindings.openSettings()
})]), in: .window(.root))
}
)
(strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
case .notDetermined:
DeviceAccess.authorizeAccess(to: .contacts)
default:
let presentationData = strongSelf.presentationData
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.AccessDenied_Title, text: presentationData.strings.Contacts_AccessDeniedError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
self?.context.sharedContext.applicationBindings.openSettings()
})]), in: .window(.root))
}
})
}

View File

@ -829,7 +829,7 @@ func openResolvedUrlImpl(
})
case .loginEmail:
if let navigationController {
let controller = loginEmailSetupController(context: context, blocking: true, emailPattern: nil, navigationController: navigationController, completion: {})
let controller = loginEmailSetupController(context: context, blocking: false, emailPattern: nil, navigationController: navigationController, completion: {}, dismiss: {})
navigationController.pushViewController(controller)
}
}

View File

@ -4038,6 +4038,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public func makeNewContactScreen(context: AccountContext, peer: EnginePeer?, phoneNumber: String?, shareViaException: Bool, completion: @escaping (EnginePeer?, DeviceContactStableId?, DeviceContactExtendedData?) -> Void) -> ViewController {
return NewContactScreen(context: context, initialData: NewContactScreen.initialData(peer: peer, phoneNumber: phoneNumber, shareViaException: shareViaException), completion: completion)
}
public func makeLoginEmailSetupController(context: AccountContext, blocking: Bool, emailPattern: String?, canAutoDismissIfNeeded: Bool, navigationController: NavigationController?, completion: @escaping () -> Void, dismiss: @escaping () -> Void) -> ViewController {
return loginEmailSetupController(context: context, blocking: blocking, emailPattern: emailPattern, canAutoDismissIfNeeded: canAutoDismissIfNeeded, navigationController: navigationController, completion: completion, dismiss: dismiss)
}
}
private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {