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 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() func navigateToCurrentCall()
var hasOngoingCall: ValuePromise<Bool> { get } var hasOngoingCall: ValuePromise<Bool> { get }
var immediateHasOngoingCall: Bool { get } var immediateHasOngoingCall: Bool { get }

View File

@ -2,8 +2,10 @@ import Foundation
import UIKit import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit
import TelegramPresentationData import TelegramPresentationData
import ProgressNavigationButtonNode import ProgressNavigationButtonNode
import AccountContext
public final class AuthorizationSequenceEmailEntryController: ViewController { public final class AuthorizationSequenceEmailEntryController: ViewController {
public enum Mode { public enum Mode {
@ -39,7 +41,10 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
public var authorization: Any? public var authorization: Any?
public var authorizationDelegate: 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.presentationData = presentationData
self.mode = mode self.mode = mode
self.blocking = blocking self.blocking = blocking
@ -58,12 +63,43 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
self.navigationBar?.backPressed = { self.navigationBar?.backPressed = {
back() 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) { required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
deinit {
self.inBackgroundDisposable?.dispose()
}
override public func loadDisplayNode() { override public func loadDisplayNode() {
self.displayNode = AuthorizationSequenceEmailEntryControllerNode(strings: self.presentationData.strings, theme: self.presentationData.theme, mode: self.mode) self.displayNode = AuthorizationSequenceEmailEntryControllerNode(strings: self.presentationData.strings, theme: self.presentationData.theme, mode: self.mode)
self.displayNodeDidLoad() self.displayNodeDidLoad()
@ -91,11 +127,7 @@ public final class AuthorizationSequenceEmailEntryController: ViewController {
guard let layout = self.validLayout, layout.size.width < 360.0 else { guard let layout = self.validLayout, layout.size.width < 360.0 else {
return return
} }
if self.blocking {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
}
if self.inProgress { if self.inProgress {
let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor)) let item = UIBarButtonItem(customDisplayNode: ProgressNavigationButtonNode(color: self.presentationData.theme.rootController.navigationBar.accentTextColor))
self.navigationItem.rightBarButtonItem = item 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) super.containerLayoutUpdated(layout, transition: transition)
let hadLayout = self.validLayout != nil let hadLayout = self.validLayout != nil

View File

@ -136,6 +136,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
private let suggestAutoarchiveDisposable = MetaDisposable() private let suggestAutoarchiveDisposable = MetaDisposable()
private let dismissAutoarchiveDisposable = MetaDisposable() private let dismissAutoarchiveDisposable = MetaDisposable()
private var didSuggestAutoarchive = false private var didSuggestAutoarchive = false
private var didSuggestLoginEmailSetup = false
private var presentationData: PresentationData private var presentationData: PresentationData
private let presentationDataValue = Promise<PresentationData>() private let presentationDataValue = Promise<PresentationData>()
@ -2551,6 +2552,35 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
guard let strongSelf = self else { guard let strongSelf = self else {
return 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 { if strongSelf.didSuggestAutoarchive {
return 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 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var dismissEmailControllerImpl: (() -> Void)? var dismissEmailControllerImpl: (() -> Void)?
var presentControllerImpl: ((ViewController) -> 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?() dismissEmailControllerImpl?()
}) })
emailController.proceedWithEmail = { [weak emailController] email in emailController.proceedWithEmail = { [weak emailController] email in
@ -78,6 +78,7 @@ public func loginEmailSetupController(context: AccountContext, blocking: Bool, e
let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: { let codeController = AuthorizationSequenceCodeEntryController(presentationData: presentationData, back: {
dismissCodeControllerImpl?() dismissCodeControllerImpl?()
dismiss()
}) })
presentControllerImpl = { [weak codeController] c in presentControllerImpl = { [weak codeController] c in

View File

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

View File

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

View File

@ -19,6 +19,7 @@ final class AccountTaskManager {
private var stateDisposable: Disposable? private var stateDisposable: Disposable?
private let tasksDisposable = MetaDisposable() private let tasksDisposable = MetaDisposable()
private let configurationDisposable = MetaDisposable() private let configurationDisposable = MetaDisposable()
private let promoDisposable = MetaDisposable()
private let managedTopReactionsDisposable = 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(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(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(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(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(managedPendingPeerNotificationSettings(postbox: self.stateManager.postbox, network: self.stateManager.network).start())
tasks.add(managedSynchronizeAppLogEventsOperations(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.tasksDisposable.dispose()
self.configurationDisposable.dispose() self.configurationDisposable.dispose()
self.managedTopReactionsDisposable.dispose() self.managedTopReactionsDisposable.dispose()
self.promoDisposable.dispose()
} }
func reloadAppConfiguration() { func reloadAppConfiguration() {
self.configurationDisposable.set(managedAppConfigurationUpdates(postbox: self.stateManager.postbox, network: self.stateManager.network).start()) 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> { func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: Network, viewTracker: AccountViewTracker) -> Signal<Void, NoError> {
return Signal { subscriber in return Signal { subscriber in
let queue = Queue() let queue = Queue()
@ -193,62 +250,7 @@ func managedPromoInfoUpdates(accountPeerId: PeerId, postbox: Postbox, network: N
|> distinctUntilChanged |> distinctUntilChanged
|> deliverOn(queue) |> deliverOn(queue)
|> mapToSignal { _ -> Signal<Void, NoError> in |> mapToSignal { _ -> Signal<Void, NoError> in
let appliedOnce: Signal<Void, NoError> = network.request(Api.functions.help.getPromoData()) return (_internal_fetchPromoInfo(accountPeerId: accountPeerId, postbox: postbox, network: network)
|> `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
|> then( |> then(
Signal<Void, NoError>.complete() Signal<Void, NoError>.complete()
|> delay(10.0 * 60.0, queue: Queue.concurrentDefaultQueue())) |> delay(10.0 * 60.0, queue: Queue.concurrentDefaultQueue()))

View File

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

View File

@ -21,8 +21,15 @@ public extension TelegramEngine {
|> ignoreValues |> ignoreValues
} }
public func getServerProvidedSuggestions() -> Signal<[ServerProvidedSuggestion], NoError> { public func getServerProvidedSuggestions(reload: Bool = false) -> Signal<[ServerProvidedSuggestion], NoError> {
return _internal_getServerProvidedSuggestions(account: self.account) 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> { public func getServerDismissedSuggestions() -> Signal<[String], NoError> {

View File

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

View File

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

View File

@ -5588,14 +5588,7 @@ public final class StoryItemSetContainerComponent: Component {
guard let component = self.component else { guard let component = self.component else {
return return
} }
#if DEBUG
if "".isEmpty {
self.performDeleteAction()
return
}
#endif
self.isEditingStory = true self.isEditingStory = true
self.updateIsProgressPaused() self.updateIsProgressPaused()
self.state?.updated(transition: .easeInOut(duration: 0.2)) self.state?.updated(transition: .easeInOut(duration: 0.2))

View File

@ -8780,18 +8780,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
func addPeerContact() { func addPeerContact() {
if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let peerStatusSettings = self.presentationInterfaceState.contactStatus?.peerStatusSettings, let contactData = DeviceContactExtendedData(peer: EnginePeer(peer)) { if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer as? TelegramUser, let peerStatusSettings = self.presentationInterfaceState.contactStatus?.peerStatusSettings {
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 let controller = self.context.sharedContext.makeNewContactScreen(
guard let strongSelf = self else { context: self.context,
return peer: EnginePeer(peer),
} phoneNumber: nil,
if let peer = peer as? TelegramUser { shareViaException: peerStatusSettings.contains(.addExceptionWhenAddingContact),
if let phone = peer.phone, !phone.isEmpty { completion: { [weak self] peer, _, _ in
guard let self, let peer else {
return
} }
self.present(OverlayStatusController(theme: self.presentationData.theme, type: .genericSuccess(self.presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).string, true)), in: .window(.root))
self?.present(OverlayStatusController(theme: strongSelf.presentationData.theme, type: .genericSuccess(strongSelf.presentationData.strings.AddContact_StatusSuccess(EnginePeer(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.chatDisplayNode.dismissInput()
strongSelf.present(controller, in: .window(.root)) strongSelf.push(controller)
}) })
} }

View File

@ -199,29 +199,35 @@ public class ComposeControllerImpl: ViewController, ComposeController {
} }
switch status { switch status {
case .allowed: 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: "") let controller = strongSelf.context.sharedContext.makeNewContactScreen(
(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 context: strongSelf.context,
peer: nil,
phoneNumber: nil,
shareViaException: false,
completion: { [weak self] peer, stableId, contactData in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if let peer = peer { if let peer = peer {
DispatchQueue.main.async { DispatchQueue.main.async {
if let navigationController = strongSelf.navigationController as? NavigationController { 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) (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) (strongSelf.navigationController as? NavigationController)?.pushViewController(controller)
default: case .notDetermined:
let presentationData = strongSelf.presentationData DeviceAccess.authorizeAccess(to: .contacts)
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: { default:
self?.context.sharedContext.applicationBindings.openSettings() let presentationData = strongSelf.presentationData
})]), in: .window(.root)) 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: case .loginEmail:
if let navigationController { 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) 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 { 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) 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? { private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {