Move contacts sync settings back to individual accounts

This commit is contained in:
Peter 2019-03-15 21:13:04 +04:00
parent 5b04bba7b2
commit 55aa20c2a5
16 changed files with 787 additions and 702 deletions

View File

@ -134,10 +134,10 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
}).start()
}
})
controller.loginWithNumber = { [weak self, weak controller] number in
controller.loginWithNumber = { [weak self, weak controller] number, syncContacts in
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash) |> deliverOnMainQueue).start(next: { [weak self] account in
strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, syncContacts: syncContacts) |> deliverOnMainQueue).start(next: { [weak self] account in
if let strongSelf = self {
controller?.inProgress = false
strongSelf.account = account
@ -399,7 +399,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
return controller
}
private func passwordEntryController(hint: String, suggestReset: Bool) -> AuthorizationSequencePasswordEntryController {
private func passwordEntryController(hint: String, suggestReset: Bool, syncContacts: Bool) -> AuthorizationSequencePasswordEntryController {
var currentController: AuthorizationSequencePasswordEntryController?
for c in self.viewControllers {
if let c = c as? AuthorizationSequencePasswordEntryController {
@ -425,7 +425,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((authorizeWithPassword(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, password: password) |> deliverOnMainQueue).start(error: { error in
strongSelf.actionDisposable.set((authorizeWithPassword(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, password: password, syncContacts: syncContacts) |> deliverOnMainQueue).start(error: { error in
Queue.mainQueue().async {
if let strongSelf = self, let controller = controller {
controller.inProgress = false
@ -458,8 +458,8 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
switch option {
case let .email(pattern):
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordEntry(hint, number, code, _) = state.contents {
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordRecovery(hint: hint, number: number, code: code, emailPattern: pattern)))
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordEntry(hint, number, code, _, syncContacts) = state.contents {
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: strongSelf.account.testingEnvironment, masterDatacenterId: strongSelf.account.masterDatacenterId, contents: .passwordRecovery(hint: hint, number: number, code: code, emailPattern: pattern, syncContacts: syncContacts)))
}
}).start()
case .none:
@ -507,7 +507,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
return controller
}
private func passwordRecoveryController(emailPattern: String) -> AuthorizationSequencePasswordRecoveryController {
private func passwordRecoveryController(emailPattern: String, syncContacts: Bool) -> AuthorizationSequencePasswordRecoveryController {
var currentController: AuthorizationSequencePasswordRecoveryController?
for c in self.viewControllers {
if let c = c as? AuthorizationSequencePasswordRecoveryController {
@ -533,7 +533,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((performPasswordRecovery(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code) |> deliverOnMainQueue).start(error: { error in
strongSelf.actionDisposable.set((performPasswordRecovery(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, code: code, syncContacts: syncContacts) |> deliverOnMainQueue).start(error: { error in
Queue.mainQueue().async {
if let strongSelf = self, let controller = controller {
controller.inProgress = false
@ -559,8 +559,8 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
controller.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.theme), title: nil, text: strongSelf.strings.TwoStepAuth_RecoveryFailed, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.strings.Common_OK, action: {})]), in: .window(.root))
let account = strongSelf.account
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordRecovery(hint, number, code, _) = state.contents {
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint, number: number, code: code, suggestReset: true)))
if let state = transaction.getState() as? UnauthorizedAccountState, case let .passwordRecovery(hint, number, code, _, syncContacts) = state.contents {
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .passwordEntry(hint: hint, number: number, code: code, suggestReset: true, syncContacts: syncContacts)))
}
}).start()
}
@ -715,7 +715,7 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
}
controllers.append(self.phoneEntryController(countryCode: countryCode, number: number))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
case let .confirmationCodeEntry(number, type, _, timeout, nextType, termsOfService):
case let .confirmationCodeEntry(number, type, _, timeout, nextType, termsOfService, syncContacts):
var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController())
@ -723,28 +723,28 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
controllers.append(self.phoneEntryController(countryCode: defaultCountryCode(), number: ""))
controllers.append(self.codeEntryController(number: number, type: type, nextType: nextType, timeout: timeout, termsOfService: termsOfService))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
case let .passwordEntry(hint, _, _, suggestReset):
case let .passwordEntry(hint, _, _, suggestReset, syncContacts):
var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController())
}
controllers.append(self.passwordEntryController(hint: hint, suggestReset: suggestReset))
controllers.append(self.passwordEntryController(hint: hint, suggestReset: suggestReset, syncContacts: syncContacts))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
case let .passwordRecovery(_, _, _, emailPattern):
case let .passwordRecovery(_, _, _, emailPattern, syncContacts):
var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController())
}
controllers.append(self.passwordRecoveryController(emailPattern: emailPattern))
controllers.append(self.passwordRecoveryController(emailPattern: emailPattern, syncContacts: syncContacts))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
case let .awaitingAccountReset(protectedUntil, number):
case let .awaitingAccountReset(protectedUntil, number, _):
var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController())
}
controllers.append(self.awaitingAccountResetController(protectedUntil: protectedUntil, number: number))
self.setViewControllers(controllers, animated: !self.viewControllers.isEmpty)
case let .signUp(_, _, _, firstName, lastName, termsOfService):
case let .signUp(_, _, _, firstName, lastName, termsOfService, syncContacts):
var controllers: [ViewController] = []
if !self.otherAccountPhoneNumbers.1.isEmpty {
controllers.append(self.splashController())

View File

@ -33,7 +33,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
self.controllerNode.inProgress = self.inProgress
}
}
var loginWithNumber: ((String) -> Void)?
var loginWithNumber: ((String, Bool) -> Void)?
private let termsDisposable = MetaDisposable()
@ -94,7 +94,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
return
}
self?.present(debugController(sharedContext: strongSelf.sharedContext, context: nil, modal: true), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})
}, hasOtherAccounts: self.otherAccountPhoneNumbers.0 != nil)
if let (code, name, number) = self.currentData {
self.controllerNode.codeAndNumber = (code, name, number)
}
@ -160,7 +160,7 @@ final class AuthorizationSequencePhoneEntryController: ViewController {
actions.append(TextAlertAction(type: .defaultAction, title: self.strings.Common_OK, action: {}))
self.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: self.theme), title: nil, text: self.strings.Login_PhoneNumberAlreadyAuthorized, actions: actions), in: .window(.root))
} else {
self.loginWithNumber?(self.controllerNode.currentNumber)
self.loginWithNumber?(self.controllerNode.currentNumber, self.controllerNode.syncContacts)
}
} else {
hapticFeedback.error()

View File

@ -162,14 +162,42 @@ private final class PhoneAndCountryNode: ASDisplayNode {
}
}
private final class ContactSyncNode: ASDisplayNode {
private let titleNode: ImmediateTextNode
let switchNode: SwitchNode
init(theme: PresentationTheme, strings: PresentationStrings) {
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1
self.titleNode.attributedText = NSAttributedString(string: strings.Privacy_ContactsSync, font: Font.regular(17.0), textColor: theme.list.itemPrimaryTextColor)
self.switchNode = SwitchNode()
self.switchNode.isOn = true
super.init()
self.addSubnode(self.titleNode)
self.addSubnode(self.switchNode)
}
func updateLayout(width: CGFloat) -> CGSize {
let switchSize = CGSize(width: 51.0, height: 31.0)
let titleSize = self.titleNode.updateLayout(CGSize(width: width - switchSize.width - 16.0 * 2.0 - 8.0, height: .greatestFiniteMagnitude))
let height: CGFloat = 40.0
self.titleNode.frame = CGRect(origin: CGPoint(x: 16.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
self.switchNode.frame = CGRect(origin: CGPoint(x: width - 16.0 - switchSize.width, y: floor((height - switchSize.height) / 2.0)), size: switchSize)
return CGSize(width: width, height: height)
}
}
final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
private let strings: PresentationStrings
private let theme: PresentationTheme
private let hasOtherAccounts: Bool
private let titleNode: ASTextNode
private let noticeNode: ASTextNode
private let phoneAndCountryNode: PhoneAndCountryNode
private let termsOfServiceNode: ImmediateTextNode
private let contactSyncNode: ContactSyncNode
private let debugAction: () -> Void
@ -185,6 +213,16 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
}
}
var syncContacts: Bool {
get {
if self.hasOtherAccounts {
return self.contactSyncNode.switchNode.isOn
} else {
return true
}
}
}
var selectCountryCode: (() -> Void)?
var checkPhone: (() -> Void)?
@ -196,10 +234,11 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
}
}
init(strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void) {
init(strings: PresentationStrings, theme: PresentationTheme, debugAction: @escaping () -> Void, hasOtherAccounts: Bool) {
self.strings = strings
self.theme = theme
self.debugAction = debugAction
self.hasOtherAccounts = hasOtherAccounts
self.titleNode = ASTextNode()
self.titleNode.isUserInteractionEnabled = true
@ -211,18 +250,7 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.noticeNode.displaysAsynchronously = false
self.noticeNode.attributedText = NSAttributedString(string: strings.Login_PhoneAndCountryHelp, font: Font.regular(16.0), textColor: theme.list.itemPrimaryTextColor, paragraphAlignment: .center)
self.termsOfServiceNode = ImmediateTextNode()
self.termsOfServiceNode.maximumNumberOfLines = 0
self.termsOfServiceNode.textAlignment = .center
self.termsOfServiceNode.displaysAsynchronously = false
let termsOfServiceAttributes = MarkdownAttributeSet(font: Font.regular(16.0), textColor: self.theme.list.itemPrimaryTextColor)
let termsOfServiceLinkAttributes = MarkdownAttributeSet(font: Font.regular(16.0), textColor: self.theme.list.itemAccentColor, additionalAttributes: [NSAttributedStringKey.underlineStyle.rawValue: NSUnderlineStyle.styleSingle.rawValue as NSNumber, TelegramTextAttributes.URL: ""])
let termsString = parseMarkdownIntoAttributedString(self.strings.Login_TermsOfServiceLabel.replacingOccurrences(of: "]", with: "]()"), attributes: MarkdownAttributes(body: termsOfServiceAttributes, bold: termsOfServiceAttributes, link: termsOfServiceLinkAttributes, linkAttribute: { _ in
return nil
}), textAlignment: .center)
self.termsOfServiceNode.attributedText = termsString
self.contactSyncNode = ContactSyncNode(theme: theme, strings: strings)
self.phoneAndCountryNode = PhoneAndCountryNode(strings: strings, theme: theme)
@ -235,9 +263,10 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.backgroundColor = theme.list.plainBackgroundColor
self.addSubnode(self.titleNode)
//self.addSubnode(self.termsOfServiceNode)
self.addSubnode(self.noticeNode)
self.addSubnode(self.phoneAndCountryNode)
self.addSubnode(self.contactSyncNode)
self.contactSyncNode.isHidden = true
self.phoneAndCountryNode.selectCountryCode = { [weak self] in
self?.selectCountryCode?()
@ -245,19 +274,6 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
self.phoneAndCountryNode.checkPhone = { [weak self] in
self?.checkPhone?()
}
self.termsOfServiceNode.highlightAttributeAction = { attributes in
if let _ = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] {
return NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)
} else {
return nil
}
}
self.termsOfServiceNode.tapAttributeAction = { attributes in
if let _ = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] as? String {
}
}
self.termsOfServiceNode.linkHighlightColor = theme.list.itemAccentColor.withAlphaComponent(0.5)
}
override func didLoad() {
@ -292,14 +308,15 @@ final class AuthorizationSequencePhoneEntryControllerNode: ASDisplayNode {
AuthorizationLayoutItem(node: self.noticeNode, size: noticeSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 18.0, maxValue: 18.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)),
AuthorizationLayoutItem(node: self.phoneAndCountryNode, size: CGSize(width: layout.size.width, height: 115.0), spacingBefore: AuthorizationLayoutItemSpacing(weight: 44.0, maxValue: 44.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0))
]
if layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 10.0)), items: items, transition: transition, failIfDoesNotFit: true) {
self.termsOfServiceNode.isHidden = false
let contactSyncSize = self.contactSyncNode.updateLayout(width: layout.size.width)
if self.hasOtherAccounts {
self.contactSyncNode.isHidden = false
items.append(AuthorizationLayoutItem(node: self.contactSyncNode, size: contactSyncSize, spacingBefore: AuthorizationLayoutItemSpacing(weight: 16.0, maxValue: 16.0), spacingAfter: AuthorizationLayoutItemSpacing(weight: 0.0, maxValue: 0.0)))
} else {
items.removeLast()
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 10.0)), items: items, transition: transition, failIfDoesNotFit: false)
self.termsOfServiceNode.isHidden = true
self.contactSyncNode.isHidden = true
}
let _ = layoutAuthorizationItems(bounds: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: layout.size.height - insets.top - insets.bottom - 10.0)), items: items, transition: transition, failIfDoesNotFit: false)
}
func activateInput() {

View File

@ -209,6 +209,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
private weak var silentPostTooltipController: TooltipController?
private weak var mediaRecordingModeTooltipController: TooltipController?
private weak var mediaRestrictedTooltipController: TooltipController?
private var forwardDisabledNoticeTooltipController: TooltipController?
private var mediaRestrictedTooltipControllerMode = true
private var screenCaptureEventsDisposable: Disposable?
@ -1158,6 +1159,24 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
}, cancelInteractiveKeyboardGestures: { [weak self] in
(self?.view.window as? WindowHost)?.cancelInteractiveKeyboardGestures()
self?.chatDisplayNode.cancelInteractiveKeyboardGestures()
}, displayForwardDisabledNotice: { [weak self] sourceNode, sourceRect, name in
guard let strongSelf = self else {
return
}
strongSelf.forwardDisabledNoticeTooltipController?.dismiss()
let tooltipController = TooltipController(content: .text(strongSelf.presentationInterfaceState.strings.Chat_ForwardHiddenAccount(name).0), timeout: 2.0, dismissByTapOutside: true)
strongSelf.forwardDisabledNoticeTooltipController = tooltipController
tooltipController.dismissed = { [weak tooltipController] in
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.forwardDisabledNoticeTooltipController === tooltipController {
strongSelf.forwardDisabledNoticeTooltipController = nil
}
}
strongSelf.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: {
if let strongSelf = self {
return (sourceNode, sourceRect)
}
return nil
}))
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
pollActionState: ChatInterfacePollActionState())

View File

@ -90,6 +90,8 @@ public final class ChatControllerInteraction {
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
let displayForwardDisabledNotice: (ASDisplayNode, CGRect, String) -> Void
var hiddenMedia: [MessageId: [Media]] = [:]
var selectionState: ChatInterfaceSelectionState?
var highlightedState: ChatInterfaceHighlightedState?
@ -98,7 +100,7 @@ public final class ChatControllerInteraction {
var pollActionState: ChatInterfacePollActionState
var searchTextHighightState: String?
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState) {
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool) -> Void, sendGif: @escaping (FileMediaReference) -> Void, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, displayForwardDisabledNotice: @escaping (ASDisplayNode, CGRect, String) -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState) {
self.openMessage = openMessage
self.openPeer = openPeer
self.openPeerMention = openPeerMention
@ -139,6 +141,7 @@ public final class ChatControllerInteraction {
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
self.displayForwardDisabledNotice = displayForwardDisabledNotice
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings
@ -161,7 +164,7 @@ public final class ChatControllerInteraction {
}, openAppStorePage: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
}, displayForwardDisabledNotice: { _, _, _ in }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState())
}
}

View File

@ -1597,6 +1597,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
item.controllerInteraction.navigateToMessage(item.message.id, sourceMessageId)
} else if let id = forwardInfo.source?.id ?? forwardInfo.author?.id {
item.controllerInteraction.openPeer(id, .info, nil)
} else if let authorSignature = forwardInfo.authorSignature {
item.controllerInteraction.displayForwardDisabledNotice(forwardInfoNode, forwardInfoNode.bounds, authorSignature)
}
return
}

View File

@ -364,7 +364,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
}, displayForwardDisabledNotice: { _, _, _ in }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
pollActionState: ChatInterfacePollActionState())
self.controllerInteraction = controllerInteraction

View File

@ -819,9 +819,10 @@ final class ContactListNode: ASDisplayNode {
let contactsWarningSuppressed = Promise<(Bool, Bool)>()
contactsWarningSuppressed.set(.single((false, false))
|> then(
combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]))
|> map { noticeView, sharedData -> (Bool, Bool) in
let synchronizeDeviceContacts: Bool = (sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings)?.synchronizeDeviceContacts ?? true
combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]))
|> map { noticeView, preferences -> (Bool, Bool) in
let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings
let synchronizeDeviceContacts: Bool = settings.synchronizeContacts
let suppressed: Bool
let timestamp = noticeView.value.flatMap({ ApplicationSpecificNotice.getTimestampValue($0) })
if let timestamp = timestamp, timestamp > 0 {

View File

@ -8,28 +8,28 @@ public enum ContactsSortOrder: Int32 {
}
public struct ContactSynchronizationSettings: Equatable, PreferencesEntry {
public var synchronizeDeviceContacts: Bool
public var _legacySynchronizeDeviceContacts: Bool
public var nameDisplayOrder: PresentationPersonNameOrder
public var sortOrder: ContactsSortOrder
public static var defaultSettings: ContactSynchronizationSettings {
return ContactSynchronizationSettings(synchronizeDeviceContacts: true, nameDisplayOrder: .firstLast, sortOrder: .presence)
return ContactSynchronizationSettings(_legacySynchronizeDeviceContacts: true, nameDisplayOrder: .firstLast, sortOrder: .presence)
}
public init(synchronizeDeviceContacts: Bool, nameDisplayOrder: PresentationPersonNameOrder, sortOrder: ContactsSortOrder) {
self.synchronizeDeviceContacts = synchronizeDeviceContacts
public init(_legacySynchronizeDeviceContacts: Bool, nameDisplayOrder: PresentationPersonNameOrder, sortOrder: ContactsSortOrder) {
self._legacySynchronizeDeviceContacts = _legacySynchronizeDeviceContacts
self.nameDisplayOrder = nameDisplayOrder
self.sortOrder = sortOrder
}
public init(decoder: PostboxDecoder) {
self.synchronizeDeviceContacts = decoder.decodeInt32ForKey("synchronizeDeviceContacts", orElse: 0) != 0
self._legacySynchronizeDeviceContacts = decoder.decodeInt32ForKey("synchronizeDeviceContacts", orElse: 0) != 0
self.nameDisplayOrder = PresentationPersonNameOrder(rawValue: decoder.decodeInt32ForKey("nameDisplayOrder", orElse: 0)) ?? .firstLast
self.sortOrder = ContactsSortOrder(rawValue: decoder.decodeInt32ForKey("sortOrder", orElse: 0)) ?? .presence
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.synchronizeDeviceContacts ? 1 : 0, forKey: "synchronizeDeviceContacts")
encoder.encodeInt32(self._legacySynchronizeDeviceContacts ? 1 : 0, forKey: "synchronizeDeviceContacts")
encoder.encodeInt32(self.nameDisplayOrder.rawValue, forKey: "nameDisplayOrder")
encoder.encodeInt32(self.sortOrder.rawValue, forKey: "sortOrder")
}

View File

@ -119,11 +119,14 @@ public class ContactsController: ViewController {
})
if #available(iOSApplicationExtension 10.0, *) {
self.authorizationDisposable = (combineLatest(DeviceAccess.authorizationStatus(context: context, subject: .contacts), combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]))
|> map { noticeView, sharedData -> (Bool, ContactsSortOrder) in
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings
let synchronizeDeviceContacts: Bool = settings?.synchronizeDeviceContacts ?? true
let sortOrder: ContactsSortOrder = settings?.sortOrder ?? .presence
self.authorizationDisposable = (combineLatest(DeviceAccess.authorizationStatus(context: context, subject: .contacts), combineLatest(context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.contactsPermissionWarningKey()), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]))
|> map { noticeView, preferences, sharedData -> (Bool, ContactsSortOrder) in
let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings
let synchronizeDeviceContacts: Bool = settings.synchronizeContacts
let contactsSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings
let sortOrder: ContactsSortOrder = contactsSettings?.sortOrder ?? .presence
if !synchronizeDeviceContacts {
return (true, sortOrder)
}

View File

@ -394,11 +394,13 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
return
}
let _ = updateContactSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
settings.synchronizeDeviceContacts = false
return settings
})
let _ = context.account.postbox.transaction({ transaction in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = false
return settings
})
}).start()
actionsDisposable.add(((deleteAllContacts(postbox: context.account.postbox, network: context.account.network) |> then(resetSavedContacts(network: context.account.network)))
|> deliverOnMainQueue).start(completed: {
@ -413,10 +415,12 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]))
}
}, updateSyncContacts: { value in
let _ = updateContactSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
settings.synchronizeDeviceContacts = value
return settings
let _ = context.account.postbox.transaction({ transaction in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = value
return settings
})
}).start()
}, updateSuggestFrequentContacts: { value in
let apply: () -> Void = {
@ -477,11 +481,13 @@ public func dataPrivacyController(context: AccountContext) -> ViewController {
actionsDisposable.add(managedUpdatedRecentPeers(accountPeerId: context.account.peerId, postbox: context.account.postbox, network: context.account.network).start())
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), recentPeers(account: context.account))
|> map { presentationData, state, noticeView, sharedData, recentPeers -> (ItemListControllerState, (ItemListNodeState<PrivacyAndSecurityEntry>, PrivacyAndSecurityEntry.ItemGenerationArguments)) in
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, statePromise.get(), context.sharedContext.accountManager.noticeEntry(key: ApplicationSpecificNotice.secretChatLinkPreviewsKey()), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.contactSynchronizationSettings]), context.account.postbox.preferencesView(keys: [PreferencesKeys.contactsSettings]), recentPeers(account: context.account))
|> map { presentationData, state, noticeView, sharedData, preferences, recentPeers -> (ItemListControllerState, (ItemListNodeState<PrivacyAndSecurityEntry>, PrivacyAndSecurityEntry.ItemGenerationArguments)) in
let secretChatLinkPreviews = noticeView.value.flatMap({ ApplicationSpecificNotice.getSecretChatLinkPreviews($0) })
let synchronizeDeviceContacts: Bool = (sharedData.entries[ApplicationSpecificSharedDataKeys.contactSynchronizationSettings] as? ContactSynchronizationSettings)?.synchronizeDeviceContacts ?? true
let settings: ContactsSettings = preferences.values[PreferencesKeys.contactsSettings] as? ContactsSettings ?? ContactsSettings.defaultSettings
let synchronizeDeviceContacts: Bool = settings.synchronizeContacts
let suggestRecentPeers: Bool
if let updatedSuggestFrequentContacts = state.updatedSuggestFrequentContacts {

View File

@ -73,7 +73,7 @@ final class OverlayPlayerControllerNode: ViewControllerTracingNode, UIGestureRec
}, openAppStorePage: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
}, displayForwardDisabledNotice: { _, _, _ in }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState())
self.dimNode = ASDisplayNode()

View File

@ -255,7 +255,7 @@ public class PeerMediaCollectionController: TelegramController {
}, openAppStorePage: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
}, displayForwardDisabledNotice: { _, _, _ in }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,
pollActionState: ChatInterfacePollActionState())
self.controllerInteraction = controllerInteraction

File diff suppressed because it is too large Load Diff

View File

@ -241,6 +241,37 @@ public func upgradedAccounts(accountManager: AccountManager, rootPath: String) -
signal = signal |> then(upgradeAccessChallengeData)
}
}
if version < 4 {
let updatedContactSynchronizationSettings = accountManager.transaction { transaction -> (ContactSynchronizationSettings, [AccountRecordId]) in
return (transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings) as? ContactSynchronizationSettings ?? ContactSynchronizationSettings.defaultSettings, transaction.getRecords().map({ $0.id }))
}
|> mapToSignal { globalSettings, ids -> Signal<Never, NoError> in
var importSignal: Signal<Never, NoError> = .complete()
for id in ids {
let importInfoAccounttSignal = accountTransaction(rootPath: rootPath, id: id, transaction: { transaction -> Void in
transaction.updatePreferencesEntry(key: PreferencesKeys.contactsSettings, { current in
var settings = current as? ContactsSettings ?? ContactsSettings.defaultSettings
settings.synchronizeContacts = globalSettings._legacySynchronizeDeviceContacts
return settings
})
})
|> ignoreValues
importSignal = importSignal |> then(importInfoAccounttSignal)
}
return importSignal
}
let applyVersion = accountManager.transaction { transaction -> Void in
transaction.setVersion(4)
}
|> ignoreValues
signal = signal |> then(
updatedContactSynchronizationSettings
|> then(
applyVersion
)
)
}
return signal
}
}