Swiftgram/submodules/SettingsUI/Sources/Privacy and Security/SelectivePrivacySettingsController.swift
2019-08-27 20:45:09 +04:00

1066 lines
58 KiB
Swift

import Foundation
import UIKit
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import AccountContext
enum SelectivePrivacySettingsKind {
case presence
case groupInvitations
case voiceCalls
case profilePhoto
case forwards
case phoneNumber
}
private enum SelectivePrivacySettingType {
case everybody
case contacts
case nobody
init(_ setting: SelectivePrivacySettings) {
switch setting {
case .disableEveryone:
self = .nobody
case .enableContacts:
self = .contacts
case .enableEveryone:
self = .everybody
}
}
}
enum SelectivePrivacySettingsPeerTarget {
case main
case callP2P
}
private final class SelectivePrivacySettingsControllerArguments {
let context: AccountContext
let updateType: (SelectivePrivacySettingType) -> Void
let openSelective: (SelectivePrivacySettingsPeerTarget, Bool) -> Void
let updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?
let updateCallIntegrationEnabled: ((Bool) -> Void)?
let updatePhoneDiscovery: ((Bool) -> Void)?
init(context: AccountContext, updateType: @escaping (SelectivePrivacySettingType) -> Void, openSelective: @escaping (SelectivePrivacySettingsPeerTarget, Bool) -> Void, updateCallP2PMode: ((SelectivePrivacySettingType) -> Void)?, updateCallIntegrationEnabled: ((Bool) -> Void)?, updatePhoneDiscovery: ((Bool) -> Void)?) {
self.context = context
self.updateType = updateType
self.openSelective = openSelective
self.updateCallP2PMode = updateCallP2PMode
self.updateCallIntegrationEnabled = updateCallIntegrationEnabled
self.updatePhoneDiscovery = updatePhoneDiscovery
}
}
private enum SelectivePrivacySettingsSection: Int32 {
case forwards
case setting
case peers
case callsP2P
case callsP2PPeers
case callsIntegrationEnabled
case phoneDiscovery
}
private func stringForUserCount(_ peers: [PeerId: SelectivePrivacyPeer], strings: PresentationStrings) -> String {
if peers.isEmpty {
return strings.PrivacyLastSeenSettings_EmpryUsersPlaceholder
} else {
var result = 0
for (_, peer) in peers {
result += peer.userCount
}
return strings.UserCount(Int32(result))
}
}
private enum SelectivePrivacySettingsEntry: ItemListNodeEntry {
case forwardsPreviewHeader(PresentationTheme, String)
case forwardsPreview(PresentationTheme, TelegramWallpaper, PresentationFontSize, PresentationStrings, PresentationDateTimeFormat, PresentationPersonNameOrder, String, Bool, String)
case settingHeader(PresentationTheme, String)
case everybody(PresentationTheme, String, Bool)
case contacts(PresentationTheme, String, Bool)
case nobody(PresentationTheme, String, Bool)
case settingInfo(PresentationTheme, String)
case exceptionsHeader(PresentationTheme, String)
case disableFor(PresentationTheme, String, String)
case enableFor(PresentationTheme, String, String)
case peersInfo(PresentationTheme, String)
case callsP2PHeader(PresentationTheme, String)
case callsP2PAlways(PresentationTheme, String, Bool)
case callsP2PContacts(PresentationTheme, String, Bool)
case callsP2PNever(PresentationTheme, String, Bool)
case callsP2PInfo(PresentationTheme, String)
case callsP2PDisableFor(PresentationTheme, String, String)
case callsP2PEnableFor(PresentationTheme, String, String)
case callsP2PPeersInfo(PresentationTheme, String)
case callsIntegrationEnabled(PresentationTheme, String, Bool)
case callsIntegrationInfo(PresentationTheme, String)
case phoneDiscoveryHeader(PresentationTheme, String)
case phoneDiscoveryEverybody(PresentationTheme, String, Bool)
case phoneDiscoveryMyContacts(PresentationTheme, String, Bool)
var section: ItemListSectionId {
switch self {
case .forwardsPreviewHeader, .forwardsPreview:
return SelectivePrivacySettingsSection.forwards.rawValue
case .settingHeader, .everybody, .contacts, .nobody, .settingInfo:
return SelectivePrivacySettingsSection.setting.rawValue
case .exceptionsHeader, .disableFor, .enableFor, .peersInfo:
return SelectivePrivacySettingsSection.peers.rawValue
case .callsP2PHeader, .callsP2PAlways, .callsP2PContacts, .callsP2PNever, .callsP2PInfo:
return SelectivePrivacySettingsSection.callsP2P.rawValue
case .callsP2PDisableFor, .callsP2PEnableFor, .callsP2PPeersInfo:
return SelectivePrivacySettingsSection.callsP2PPeers.rawValue
case .callsIntegrationEnabled, .callsIntegrationInfo:
return SelectivePrivacySettingsSection.callsIntegrationEnabled.rawValue
case .phoneDiscoveryHeader, .phoneDiscoveryEverybody, .phoneDiscoveryMyContacts:
return SelectivePrivacySettingsSection.phoneDiscovery.rawValue
}
}
var stableId: Int32 {
switch self {
case .forwardsPreviewHeader:
return 0
case .forwardsPreview:
return 1
case .settingHeader:
return 2
case .everybody:
return 3
case .contacts:
return 4
case .nobody:
return 5
case .settingInfo:
return 6
case .phoneDiscoveryHeader:
return 7
case .phoneDiscoveryEverybody:
return 8
case .phoneDiscoveryMyContacts:
return 9
case .exceptionsHeader:
return 10
case .disableFor:
return 11
case .enableFor:
return 12
case .peersInfo:
return 13
case .callsP2PHeader:
return 14
case .callsP2PAlways:
return 15
case .callsP2PContacts:
return 16
case .callsP2PNever:
return 17
case .callsP2PInfo:
return 18
case .callsP2PDisableFor:
return 19
case .callsP2PEnableFor:
return 20
case .callsP2PPeersInfo:
return 21
case .callsIntegrationEnabled:
return 22
case .callsIntegrationInfo:
return 23
}
}
static func ==(lhs: SelectivePrivacySettingsEntry, rhs: SelectivePrivacySettingsEntry) -> Bool {
switch lhs {
case let .forwardsPreviewHeader(lhsTheme, lhsText):
if case let .forwardsPreviewHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .forwardsPreview(lhsTheme, lhsWallpaper, lhsFontSize, lhsStrings, lhsTimeFormat, lhsNameOrder, lhsPeerName, lhsLinkEnabled, lhsTooltipText):
if case let .forwardsPreview(rhsTheme, rhsWallpaper, rhsFontSize, rhsStrings, rhsTimeFormat, rhsNameOrder, rhsPeerName, rhsLinkEnabled, rhsTooltipText) = rhs, lhsTheme === rhsTheme, lhsWallpaper == rhsWallpaper, lhsFontSize == rhsFontSize, lhsStrings === rhsStrings, lhsTimeFormat == rhsTimeFormat, lhsNameOrder == rhsNameOrder, lhsPeerName == rhsPeerName, lhsLinkEnabled == rhsLinkEnabled, lhsTooltipText == rhsTooltipText {
return true
} else {
return false
}
case let .settingHeader(lhsTheme, lhsText):
if case let .settingHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .everybody(lhsTheme, lhsText, lhsValue):
if case let .everybody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .contacts(lhsTheme, lhsText, lhsValue):
if case let .contacts(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .nobody(lhsTheme, lhsText, lhsValue):
if case let nobody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .exceptionsHeader(lhsTheme, lhsText):
if case let .exceptionsHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .settingInfo(lhsTheme, lhsText):
if case let .settingInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .disableFor(lhsTheme, lhsText, lhsValue):
if case let .disableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .enableFor(lhsTheme, lhsText, lhsValue):
if case let .enableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .peersInfo(lhsTheme, lhsText):
if case let .peersInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .callsP2PHeader(lhsTheme, lhsText):
if case let .callsP2PHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .callsP2PInfo(lhsTheme, lhsText):
if case let .callsP2PInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .callsP2PAlways(lhsTheme, lhsText, lhsValue):
if case let .callsP2PAlways(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsP2PContacts(lhsTheme, lhsText, lhsValue):
if case let .callsP2PContacts(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsP2PNever(lhsTheme, lhsText, lhsValue):
if case let .callsP2PNever(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsP2PDisableFor(lhsTheme, lhsText, lhsValue):
if case let .callsP2PDisableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsP2PEnableFor(lhsTheme, lhsText, lhsValue):
if case let .callsP2PEnableFor(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsP2PPeersInfo(lhsTheme, lhsText):
if case let .callsP2PPeersInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .callsIntegrationEnabled(lhsTheme, lhsText, lhsValue):
if case let .callsIntegrationEnabled(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callsIntegrationInfo(lhsTheme, lhsText):
if case let .callsIntegrationInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .phoneDiscoveryHeader(lhsTheme, lhsText):
if case let .phoneDiscoveryHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .phoneDiscoveryEverybody(lhsTheme, lhsText, lhsValue):
if case let .phoneDiscoveryEverybody(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .phoneDiscoveryMyContacts(lhsTheme, lhsText, lhsValue):
if case let .phoneDiscoveryMyContacts(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
}
}
static func <(lhs: SelectivePrivacySettingsEntry, rhs: SelectivePrivacySettingsEntry) -> Bool {
return lhs.stableId < rhs.stableId
}
func item(_ arguments: SelectivePrivacySettingsControllerArguments) -> ListViewItem {
switch self {
case let .forwardsPreviewHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, multiline: true, sectionId: self.section)
case let .forwardsPreview(theme, wallpaper, fontSize, strings, dateTimeFormat, nameDisplayOrder, peerName, linkEnabled, tooltipText):
return ForwardPrivacyChatPreviewItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, fontSize: fontSize, wallpaper: wallpaper, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, peerName: peerName, linkEnabled: linkEnabled, tooltipText: tooltipText)
case let .settingHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, multiline: true, sectionId: self.section)
case let .everybody(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.everybody)
})
case let .contacts(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.contacts)
})
case let .nobody(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateType(.nobody)
})
case let .settingInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .exceptionsHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .disableFor(theme, title, value):
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.main, false)
})
case let .enableFor(theme, title, value):
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.main, true)
})
case let .peersInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .callsP2PHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .callsP2PAlways(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateCallP2PMode?(.everybody)
})
case let .callsP2PContacts(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateCallP2PMode?(.contacts)
})
case let .callsP2PNever(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updateCallP2PMode?(.nobody)
})
case let .callsP2PInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .callsP2PDisableFor(theme, title, value):
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.callP2P, false)
})
case let .callsP2PEnableFor(theme, title, value):
return ItemListDisclosureItem(theme: theme, title: title, label: value, sectionId: self.section, style: .blocks, action: {
arguments.openSelective(.callP2P, true)
})
case let .callsP2PPeersInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .callsIntegrationEnabled(theme, text, value):
return ItemListSwitchItem(theme: theme, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
arguments.updateCallIntegrationEnabled?(value)
})
case let .callsIntegrationInfo(theme, text):
return ItemListTextItem(theme: theme, text: .plain(text), sectionId: self.section)
case let .phoneDiscoveryHeader(theme, text):
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
case let .phoneDiscoveryEverybody(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updatePhoneDiscovery?(true)
})
case let .phoneDiscoveryMyContacts(theme, text, value):
return ItemListCheckboxItem(theme: theme, title: text, style: .left, checked: value, zeroSeparatorInsets: false, sectionId: self.section, action: {
arguments.updatePhoneDiscovery?(false)
})
}
}
}
private struct SelectivePrivacySettingsControllerState: Equatable {
let setting: SelectivePrivacySettingType
let enableFor: [PeerId: SelectivePrivacyPeer]
let disableFor: [PeerId: SelectivePrivacyPeer]
let saving: Bool
let callDataSaving: VoiceCallDataSaving?
let callP2PMode: SelectivePrivacySettingType?
let callP2PEnableFor: [PeerId: SelectivePrivacyPeer]?
let callP2PDisableFor: [PeerId: SelectivePrivacyPeer]?
let callIntegrationAvailable: Bool?
let callIntegrationEnabled: Bool?
let phoneDiscoveryEnabled: Bool?
init(setting: SelectivePrivacySettingType, enableFor: [PeerId: SelectivePrivacyPeer], disableFor: [PeerId: SelectivePrivacyPeer], saving: Bool, callDataSaving: VoiceCallDataSaving?, callP2PMode: SelectivePrivacySettingType?, callP2PEnableFor: [PeerId: SelectivePrivacyPeer]?, callP2PDisableFor: [PeerId: SelectivePrivacyPeer]?, callIntegrationAvailable: Bool?, callIntegrationEnabled: Bool?, phoneDiscoveryEnabled: Bool?) {
self.setting = setting
self.enableFor = enableFor
self.disableFor = disableFor
self.saving = saving
self.callDataSaving = callDataSaving
self.callP2PMode = callP2PMode
self.callP2PEnableFor = callP2PEnableFor
self.callP2PDisableFor = callP2PDisableFor
self.callIntegrationAvailable = callIntegrationAvailable
self.callIntegrationEnabled = callIntegrationEnabled
self.phoneDiscoveryEnabled = phoneDiscoveryEnabled
}
static func ==(lhs: SelectivePrivacySettingsControllerState, rhs: SelectivePrivacySettingsControllerState) -> Bool {
if lhs.setting != rhs.setting {
return false
}
if lhs.enableFor != rhs.enableFor {
return false
}
if lhs.disableFor != rhs.disableFor {
return false
}
if lhs.saving != rhs.saving {
return false
}
if lhs.callDataSaving != rhs.callDataSaving {
return false
}
if lhs.callP2PMode != rhs.callP2PMode {
return false
}
if lhs.callP2PEnableFor != rhs.callP2PEnableFor {
return false
}
if lhs.callP2PDisableFor != rhs.callP2PDisableFor {
return false
}
if lhs.callIntegrationAvailable != rhs.callIntegrationAvailable {
return false
}
if lhs.callIntegrationEnabled != rhs.callIntegrationEnabled {
return false
}
if lhs.phoneDiscoveryEnabled != rhs.phoneDiscoveryEnabled {
return false
}
return true
}
func withUpdatedSetting(_ setting: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedSaving(_ saving: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedCallP2PMode(_ mode: SelectivePrivacySettingType) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: mode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedCallP2PEnableFor(_ enableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: enableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedCallP2PDisableFor(_ disableFor: [PeerId: SelectivePrivacyPeer]) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: disableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedCallsIntegrationEnabled(_ enabled: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: enabled, phoneDiscoveryEnabled: self.phoneDiscoveryEnabled)
}
func withUpdatedPhoneDiscoveryEnabled(_ phoneDiscoveryEnabled: Bool) -> SelectivePrivacySettingsControllerState {
return SelectivePrivacySettingsControllerState(setting: self.setting, enableFor: self.enableFor, disableFor: self.disableFor, saving: self.saving, callDataSaving: self.callDataSaving, callP2PMode: self.callP2PMode, callP2PEnableFor: self.callP2PEnableFor, callP2PDisableFor: self.callP2PDisableFor, callIntegrationAvailable: self.callIntegrationAvailable, callIntegrationEnabled: self.callIntegrationEnabled, phoneDiscoveryEnabled: phoneDiscoveryEnabled)
}
}
private func selectivePrivacySettingsControllerEntries(presentationData: PresentationData, kind: SelectivePrivacySettingsKind, state: SelectivePrivacySettingsControllerState, peerName: String) -> [SelectivePrivacySettingsEntry] {
var entries: [SelectivePrivacySettingsEntry] = []
let settingTitle: String
let settingInfoText: String
let disableForText: String
let enableForText: String
switch kind {
case .presence:
settingTitle = presentationData.strings.PrivacyLastSeenSettings_WhoCanSeeMyTimestamp
settingInfoText = presentationData.strings.PrivacyLastSeenSettings_CustomHelp
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
case .groupInvitations:
settingTitle = presentationData.strings.Privacy_GroupsAndChannels_WhoCanAddMe
settingInfoText = presentationData.strings.Privacy_GroupsAndChannels_CustomHelp
disableForText = presentationData.strings.Privacy_GroupsAndChannels_NeverAllow
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
case .voiceCalls:
settingTitle = presentationData.strings.Privacy_Calls_WhoCanCallMe
settingInfoText = presentationData.strings.Privacy_Calls_CustomHelp
disableForText = presentationData.strings.Privacy_GroupsAndChannels_NeverAllow
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
case .profilePhoto:
settingTitle = presentationData.strings.Privacy_ProfilePhoto_WhoCanSeeMyPhoto
settingInfoText = presentationData.strings.Privacy_ProfilePhoto_CustomHelp
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
case .forwards:
settingTitle = presentationData.strings.Privacy_Forwards_WhoCanForward
settingInfoText = presentationData.strings.Privacy_Forwards_CustomHelp
disableForText = presentationData.strings.Privacy_GroupsAndChannels_NeverAllow
enableForText = presentationData.strings.Privacy_GroupsAndChannels_AlwaysAllow
case .phoneNumber:
settingTitle = presentationData.strings.PrivacyPhoneNumberSettings_WhoCanSeeMyPhoneNumber
if state.setting == .nobody, state.phoneDiscoveryEnabled == false {
settingInfoText = presentationData.strings.PrivacyPhoneNumberSettings_CustomDisabledHelp
} else {
settingInfoText = presentationData.strings.PrivacyPhoneNumberSettings_CustomHelp
}
disableForText = presentationData.strings.PrivacyLastSeenSettings_NeverShareWith
enableForText = presentationData.strings.PrivacyLastSeenSettings_AlwaysShareWith
}
if case .forwards = kind {
let linkEnabled: Bool
let tootipText: String
switch state.setting {
case .everybody:
tootipText = presentationData.strings.Privacy_Forwards_AlwaysLink
linkEnabled = true
case .contacts:
tootipText = presentationData.strings.Privacy_Forwards_LinkIfAllowed
linkEnabled = true
case .nobody:
tootipText = presentationData.strings.Privacy_Forwards_NeverLink
linkEnabled = false
}
entries.append(.forwardsPreviewHeader(presentationData.theme, presentationData.strings.Privacy_Forwards_Preview))
entries.append(.forwardsPreview(presentationData.theme, presentationData.chatWallpaper, presentationData.fontSize, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, peerName, linkEnabled, tootipText))
}
entries.append(.settingHeader(presentationData.theme, settingTitle))
entries.append(.everybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.setting == .everybody))
entries.append(.contacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.setting == .contacts))
switch kind {
case .presence, .voiceCalls, .forwards, .phoneNumber:
entries.append(.nobody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenNobody, state.setting == .nobody))
case .groupInvitations, .profilePhoto:
break
}
entries.append(.settingInfo(presentationData.theme, settingInfoText))
if case .phoneNumber = kind, state.setting == .nobody {
entries.append(.phoneDiscoveryHeader(presentationData.theme, presentationData.strings.PrivacyPhoneNumberSettings_DiscoveryHeader))
entries.append(.phoneDiscoveryEverybody(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenEverybody, state.phoneDiscoveryEnabled != false))
entries.append(.phoneDiscoveryMyContacts(presentationData.theme, presentationData.strings.PrivacySettings_LastSeenContacts, state.phoneDiscoveryEnabled == false))
}
entries.append(.exceptionsHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_Exceptions))
switch state.setting {
case .everybody:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
case .contacts:
entries.append(.disableFor(presentationData.theme, disableForText, stringForUserCount(state.disableFor, strings: presentationData.strings)))
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
case .nobody:
entries.append(.enableFor(presentationData.theme, enableForText, stringForUserCount(state.enableFor, strings: presentationData.strings)))
}
entries.append(.peersInfo(presentationData.theme, presentationData.strings.PrivacyLastSeenSettings_CustomShareSettingsHelp))
if case .voiceCalls = kind, let p2pMode = state.callP2PMode, let integrationAvailable = state.callIntegrationAvailable, let integrationEnabled = state.callIntegrationEnabled {
entries.append(.callsP2PHeader(presentationData.theme, presentationData.strings.Privacy_Calls_P2P.uppercased()))
entries.append(.callsP2PAlways(presentationData.theme, presentationData.strings.Privacy_Calls_P2PAlways, p2pMode == .everybody))
entries.append(.callsP2PContacts(presentationData.theme, presentationData.strings.Privacy_Calls_P2PContacts, p2pMode == .contacts))
entries.append(.callsP2PNever(presentationData.theme, presentationData.strings.Privacy_Calls_P2PNever, p2pMode == .nobody))
entries.append(.callsP2PInfo(presentationData.theme, presentationData.strings.Privacy_Calls_P2PHelp))
if let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
switch callP2PMode {
case .everybody:
entries.append(.callsP2PDisableFor(presentationData.theme, disableForText, stringForUserCount(disableFor, strings: presentationData.strings)))
case .contacts:
entries.append(.callsP2PDisableFor(presentationData.theme, disableForText, stringForUserCount(disableFor, strings: presentationData.strings)))
entries.append(.callsP2PEnableFor(presentationData.theme, enableForText, stringForUserCount(enableFor, strings: presentationData.strings)))
case .nobody:
entries.append(.callsP2PEnableFor(presentationData.theme, enableForText, stringForUserCount(enableFor, strings: presentationData.strings)))
}
}
entries.append(.callsP2PPeersInfo(presentationData.theme, presentationData.strings.PrivacyLastSeenSettings_CustomShareSettingsHelp))
if integrationAvailable {
entries.append(.callsIntegrationEnabled(presentationData.theme, presentationData.strings.Privacy_Calls_Integration, integrationEnabled))
entries.append(.callsIntegrationInfo(presentationData.theme, presentationData.strings.Privacy_Calls_IntegrationHelp))
}
}
return entries
}
func selectivePrivacySettingsController(context: AccountContext, kind: SelectivePrivacySettingsKind, current: SelectivePrivacySettings, callSettings: (SelectivePrivacySettings, VoiceCallSettings)? = nil, phoneDiscoveryEnabled: Bool? = nil, voipConfiguration: VoipConfiguration? = nil, callIntegrationAvailable: Bool? = nil, updated: @escaping (SelectivePrivacySettings, (SelectivePrivacySettings, VoiceCallSettings)?, Bool?) -> Void) -> ViewController {
let strings = context.sharedContext.currentPresentationData.with { $0 }.strings
var initialEnableFor: [PeerId: SelectivePrivacyPeer] = [:]
var initialDisableFor: [PeerId: SelectivePrivacyPeer] = [:]
switch current {
case let .disableEveryone(enableFor):
initialEnableFor = enableFor
case let .enableContacts(enableFor, disableFor):
initialEnableFor = enableFor
initialDisableFor = disableFor
case let .enableEveryone(disableFor):
initialDisableFor = disableFor
}
var initialCallP2PEnableFor: [PeerId: SelectivePrivacyPeer]?
var initialCallP2PDisableFor: [PeerId: SelectivePrivacyPeer]?
if let callCurrent = callSettings?.0 {
switch callCurrent {
case let .disableEveryone(enableFor):
initialCallP2PEnableFor = enableFor
initialCallP2PDisableFor = [:]
case let .enableContacts(enableFor, disableFor):
initialCallP2PEnableFor = enableFor
initialCallP2PDisableFor = disableFor
case let .enableEveryone(disableFor):
initialCallP2PEnableFor = [:]
initialCallP2PDisableFor = disableFor
}
}
let initialState = SelectivePrivacySettingsControllerState(setting: SelectivePrivacySettingType(current), enableFor: initialEnableFor, disableFor: initialDisableFor, saving: false, callDataSaving: callSettings?.1.dataSaving, callP2PMode: callSettings != nil ? SelectivePrivacySettingType(callSettings!.0) : nil, callP2PEnableFor: initialCallP2PEnableFor, callP2PDisableFor: initialCallP2PDisableFor, callIntegrationAvailable: callIntegrationAvailable, callIntegrationEnabled: callSettings?.1.enableSystemIntegration, phoneDiscoveryEnabled: phoneDiscoveryEnabled)
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState)
let updateState: ((SelectivePrivacySettingsControllerState) -> SelectivePrivacySettingsControllerState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
var dismissImpl: (() -> Void)?
var pushControllerImpl: ((ViewController, Bool) -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
let actionsDisposable = DisposableSet()
let updateSettingsDisposable = MetaDisposable()
let addPeerDisposable = MetaDisposable()
actionsDisposable.add(addPeerDisposable)
let arguments = SelectivePrivacySettingsControllerArguments(context: context, updateType: { type in
updateState {
$0.withUpdatedSetting(type)
}
}, openSelective: { target, enable in
let title: String
if enable {
switch kind {
case .presence:
title = strings.PrivacyLastSeenSettings_AlwaysShareWith_Title
case .groupInvitations:
title = strings.Privacy_GroupsAndChannels_AlwaysAllow_Title
case .voiceCalls:
title = strings.Privacy_Calls_AlwaysAllow_Title
case .profilePhoto:
title = strings.Privacy_ProfilePhoto_AlwaysShareWith_Title
case .forwards:
title = strings.Privacy_Forwards_AlwaysAllow_Title
case .phoneNumber:
title = strings.PrivacyLastSeenSettings_AlwaysShareWith_Title
}
} else {
switch kind {
case .presence:
title = strings.PrivacyLastSeenSettings_NeverShareWith_Title
case .groupInvitations:
title = strings.Privacy_GroupsAndChannels_NeverAllow_Title
case .voiceCalls:
title = strings.Privacy_Calls_NeverAllow_Title
case .profilePhoto:
title = strings.Privacy_ProfilePhoto_NeverShareWith_Title
case .forwards:
title = strings.Privacy_Forwards_NeverAllow_Title
case .phoneNumber:
title = strings.PrivacyLastSeenSettings_NeverShareWith_Title
}
}
var peerIds: [PeerId: SelectivePrivacyPeer] = [:]
updateState { state in
if enable {
switch target {
case .main:
peerIds = state.enableFor
case .callP2P:
if let callP2PEnableFor = state.callP2PEnableFor {
peerIds = callP2PEnableFor
}
}
} else {
switch target {
case .main:
peerIds = state.disableFor
case .callP2P:
if let callP2PDisableFor = state.callP2PDisableFor {
peerIds = callP2PDisableFor
}
}
}
return state
}
if peerIds.isEmpty {
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .peerSelection(searchChatList: true, searchGroups: true), options: []))
addPeerDisposable.set((controller.result
|> take(1)
|> deliverOnMainQueue).start(next: { [weak controller] peerIds in
if peerIds.isEmpty {
controller?.dismiss()
return
}
let _ = (context.account.postbox.transaction { transaction -> [PeerId: SelectivePrivacyPeer] in
var updatedPeers: [PeerId: SelectivePrivacyPeer] = [:]
var existingIds = Set(updatedPeers.values.map { $0.peer.id })
for peerId in peerIds {
guard case let .peer(peerId) = peerId else {
continue
}
if let peer = transaction.getPeer(peerId), !existingIds.contains(peerId) {
existingIds.insert(peerId)
var participantCount: Int32?
if let channel = peer as? TelegramChannel, case .group = channel.info {
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData {
participantCount = cachedData.participantsSummary.memberCount
}
}
updatedPeers[peer.id] = SelectivePrivacyPeer(peer: peer, participantCount: participantCount)
}
}
return updatedPeers
}
|> deliverOnMainQueue).start(next: { updatedPeerIds in
controller?.dismiss()
updateState { state in
var state = state
if enable {
switch target {
case .main:
var disableFor = state.disableFor
for (key, _) in updatedPeerIds {
disableFor.removeValue(forKey: key)
}
return state.withUpdatedEnableFor(updatedPeerIds).withUpdatedDisableFor(disableFor)
case .callP2P:
var callP2PDisableFor = state.callP2PDisableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PDisableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PEnableFor(updatedPeerIds).withUpdatedCallP2PDisableFor(callP2PDisableFor)
}
} else {
switch target {
case .main:
var enableFor = state.enableFor
for (key, _) in updatedPeerIds {
enableFor.removeValue(forKey: key)
}
return state.withUpdatedDisableFor(updatedPeerIds).withUpdatedEnableFor(enableFor)
case .callP2P:
var callP2PEnableFor = state.callP2PEnableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PEnableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PDisableFor(updatedPeerIds).withUpdatedCallP2PEnableFor(callP2PEnableFor)
}
}
}
let controller = selectivePrivacyPeersController(context: context, title: title, initialPeers: updatedPeerIds, updated: { updatedPeerIds in
updateState { state in
if enable {
switch target {
case .main:
var disableFor = state.disableFor
for (key, _) in updatedPeerIds {
disableFor.removeValue(forKey: key)
}
return state.withUpdatedEnableFor(updatedPeerIds).withUpdatedDisableFor(disableFor)
case .callP2P:
var callP2PDisableFor = state.callP2PDisableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PDisableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PEnableFor(updatedPeerIds).withUpdatedCallP2PDisableFor(callP2PDisableFor)
}
} else {
switch target {
case .main:
var enableFor = state.enableFor
for (key, _) in updatedPeerIds {
enableFor.removeValue(forKey: key)
}
return state.withUpdatedDisableFor(updatedPeerIds).withUpdatedEnableFor(enableFor)
case .callP2P:
var callP2PEnableFor = state.callP2PEnableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PEnableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PDisableFor(updatedPeerIds).withUpdatedCallP2PEnableFor(callP2PEnableFor)
}
}
}
})
pushControllerImpl?(controller, false)
})
}))
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
} else {
let controller = selectivePrivacyPeersController(context: context, title: title, initialPeers: peerIds, updated: { updatedPeerIds in
updateState { state in
if enable {
switch target {
case .main:
var disableFor = state.disableFor
for (key, _) in updatedPeerIds {
disableFor.removeValue(forKey: key)
}
return state.withUpdatedEnableFor(updatedPeerIds).withUpdatedDisableFor(disableFor)
case .callP2P:
var callP2PDisableFor = state.callP2PDisableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PDisableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PEnableFor(updatedPeerIds).withUpdatedCallP2PDisableFor(callP2PDisableFor)
}
} else {
switch target {
case .main:
var enableFor = state.enableFor
for (key, _) in updatedPeerIds {
enableFor.removeValue(forKey: key)
}
return state.withUpdatedDisableFor(updatedPeerIds).withUpdatedEnableFor(enableFor)
case .callP2P:
var callP2PEnableFor = state.callP2PEnableFor ?? [:]
for (key, _) in updatedPeerIds {
callP2PEnableFor.removeValue(forKey: key)
}
return state.withUpdatedCallP2PDisableFor(updatedPeerIds).withUpdatedCallP2PEnableFor(callP2PEnableFor)
}
}
}
})
pushControllerImpl?(controller, true)
}
}, updateCallP2PMode: { mode in
updateState { state in
return state.withUpdatedCallP2PMode(mode)
}
}, updateCallIntegrationEnabled: { enabled in
updateState { state in
return state.withUpdatedCallsIntegrationEnabled(enabled)
}
let _ = updateVoiceCallSettingsSettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in
var settings = settings
settings.enableSystemIntegration = enabled
return settings
}).start()
}, updatePhoneDiscovery: { value in
updateState { state in
return state.withUpdatedPhoneDiscoveryEnabled(value)
}
})
let peerName = context.account.postbox.transaction { transaction -> String in
return (transaction.getPeer(context.account.peerId) as? TelegramUser)?.displayTitle ?? ""
}
let signal = combineLatest(context.sharedContext.presentationData, statePromise.get(), peerName) |> deliverOnMainQueue
|> map { presentationData, state, peerName -> (ItemListControllerState, (ItemListNodeState<SelectivePrivacySettingsEntry>, SelectivePrivacySettingsEntry.ItemGenerationArguments)) in
let title: String
switch kind {
case .presence:
title = presentationData.strings.PrivacySettings_LastSeenTitle
case .groupInvitations:
title = presentationData.strings.Privacy_GroupsAndChannels
case .voiceCalls:
title = presentationData.strings.Settings_CallSettings
case .profilePhoto:
title = presentationData.strings.Privacy_ProfilePhoto
case .forwards:
title = presentationData.strings.Privacy_Forwards
case .phoneNumber:
title = presentationData.strings.Privacy_PhoneNumber
}
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(entries: selectivePrivacySettingsControllerEntries(presentationData: presentationData, kind: kind, state: state, peerName: peerName), style: .blocks, animateChanges: false)
return (controllerState, (listState, arguments))
} |> afterDisposed {
actionsDisposable.dispose()
}
struct AppliedSettings: Equatable {
let settings: SelectivePrivacySettings
let callP2PSettings: SelectivePrivacySettings?
let callDataSaving: VoiceCallDataSaving?
let callIntegrationEnabled: Bool?
let phoneDiscoveryEnabled: Bool?
}
var appliedSettings: AppliedSettings?
let update: (Bool) -> Void = { save in
var wasSaving = false
var settings: SelectivePrivacySettings?
var callP2PSettings: SelectivePrivacySettings?
var phoneDiscoveryEnabled: Bool?
var callDataSaving: VoiceCallDataSaving?
var callIntegrationEnabled: Bool?
updateState { state in
wasSaving = state.saving
callDataSaving = state.callDataSaving
callIntegrationEnabled = state.callIntegrationEnabled
switch state.setting {
case .everybody:
settings = SelectivePrivacySettings.enableEveryone(disableFor: state.disableFor)
case .contacts:
settings = SelectivePrivacySettings.enableContacts(enableFor: state.enableFor, disableFor: state.disableFor)
case .nobody:
settings = SelectivePrivacySettings.disableEveryone(enableFor: state.enableFor)
}
if case .phoneNumber = kind, let value = state.phoneDiscoveryEnabled {
phoneDiscoveryEnabled = value
}
if case .voiceCalls = kind, let callP2PMode = state.callP2PMode, let disableFor = state.callP2PDisableFor, let enableFor = state.callP2PEnableFor {
switch callP2PMode {
case .everybody:
callP2PSettings = SelectivePrivacySettings.enableEveryone(disableFor: disableFor)
case .contacts:
callP2PSettings = SelectivePrivacySettings.enableContacts(enableFor: enableFor, disableFor: disableFor)
case .nobody:
callP2PSettings = SelectivePrivacySettings.disableEveryone(enableFor: enableFor)
}
}
return state.withUpdatedSaving(true)
}
if let settings = settings, !wasSaving {
let settingsToApply = AppliedSettings(settings: settings, callP2PSettings: callP2PSettings, callDataSaving: callDataSaving, callIntegrationEnabled: callIntegrationEnabled, phoneDiscoveryEnabled: phoneDiscoveryEnabled)
if appliedSettings == settingsToApply {
return
}
appliedSettings = settingsToApply
let type: UpdateSelectiveAccountPrivacySettingsType
switch kind {
case .presence:
type = .presence
case .groupInvitations:
type = .groupInvitations
case .voiceCalls:
type = .voiceCalls
case .profilePhoto:
type = .profilePhoto
case .forwards:
type = .forwards
case .phoneNumber:
type = .phoneNumber
}
let updateSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: type, settings: settings)
var updateCallP2PSettingsSignal: Signal<Void, NoError> = Signal.complete()
if let callP2PSettings = callP2PSettings {
updateCallP2PSettingsSignal = updateSelectiveAccountPrivacySettings(account: context.account, type: .voiceCallsP2P, settings: callP2PSettings)
}
var updatePhoneDiscoverySignal: Signal<Void, NoError> = Signal.complete()
if let phoneDiscoveryEnabled = phoneDiscoveryEnabled {
updatePhoneDiscoverySignal = updatePhoneNumberDiscovery(account: context.account, value: phoneDiscoveryEnabled)
}
let _ = (combineLatest(updateSettingsSignal, updateCallP2PSettingsSignal, updatePhoneDiscoverySignal)
|> deliverOnMainQueue).start(completed: {
})
if case .voiceCalls = kind, let dataSaving = callDataSaving, let callP2PSettings = callP2PSettings, let systemIntegrationEnabled = callIntegrationEnabled {
updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, enableSystemIntegration: systemIntegrationEnabled)), phoneDiscoveryEnabled)
} else {
updated(settings, nil, phoneDiscoveryEnabled)
}
}
}
let controller = ItemListController(context: context, state: signal)
controller.willDisappear = { [weak controller] _ in
if let controller = controller, let navigationController = controller.navigationController {
let index = navigationController.viewControllers.firstIndex(of: controller)
if index == nil || index == navigationController.viewControllers.count - 1 {
update(true)
}
}
}
controller.didDisappear = { [weak controller] _ in
if let controller = controller, controller.navigationController?.viewControllers.firstIndex(of: controller) == nil {
//update(true)
}
}
pushControllerImpl = { [weak controller] c, animated in
(controller?.navigationController as? NavigationController)?.pushViewController(c, animated: animated)
}
presentControllerImpl = { [weak controller] c, a in
controller?.present(c, in: .window(.root), with: a)
}
dismissImpl = { [weak controller] in
let _ = (controller?.navigationController as? NavigationController)?.popViewController(animated: true)
}
return controller
}