mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-28 10:55:40 +00:00
Various improvements
This commit is contained in:
parent
7cf87859a8
commit
6f5cd84019
@ -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 }
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()))
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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> {
|
||||||
|
|||||||
@ -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),
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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? {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user