mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
f1e5016f46
@ -166,7 +166,7 @@ public struct PeerId: Hashable, CustomStringConvertible, Comparable, Codable {
|
||||
let offsetIdHighBits = (data >> (32 + 3)) & 0xffffffff
|
||||
let idHighBits = offsetIdHighBits << 32
|
||||
|
||||
if idHighBits == 0 {
|
||||
if idHighBits == 0 && namespaceBits != 0 {
|
||||
if let uint32Value = UInt32(exactly: idLowBits) {
|
||||
self.id = Id(rawValue: Int64(Int32(bitPattern: uint32Value)))
|
||||
} else {
|
||||
|
@ -28,8 +28,28 @@ public final class CallKitIntegration {
|
||||
var audioSessionActive: Signal<Bool, NoError> {
|
||||
return self.audioSessionActivePromise.get()
|
||||
}
|
||||
|
||||
private static let sharedInstance: CallKitIntegration? = CallKitIntegration()
|
||||
public static var shared: CallKitIntegration? {
|
||||
return self.sharedInstance
|
||||
}
|
||||
|
||||
func setup(
|
||||
startCall: @escaping (AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>,
|
||||
answerCall: @escaping (UUID) -> Void,
|
||||
endCall: @escaping (UUID) -> Signal<Bool, NoError>,
|
||||
setCallMuted: @escaping (UUID, Bool) -> Void,
|
||||
audioSessionActivationChanged: @escaping (Bool) -> Void
|
||||
) {
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
if sharedProviderDelegate == nil {
|
||||
sharedProviderDelegate = CallKitProviderDelegate()
|
||||
}
|
||||
(sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged)
|
||||
}
|
||||
}
|
||||
|
||||
init?(startCall: @escaping (AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal<Bool, NoError>, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) {
|
||||
private init?() {
|
||||
if !CallKitIntegration.isAvailable {
|
||||
return nil
|
||||
}
|
||||
@ -39,10 +59,6 @@ public final class CallKitIntegration {
|
||||
#else
|
||||
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
if sharedProviderDelegate == nil {
|
||||
sharedProviderDelegate = CallKitProviderDelegate()
|
||||
}
|
||||
(sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@ -68,9 +84,9 @@ public final class CallKitIntegration {
|
||||
}
|
||||
}
|
||||
|
||||
func reportIncomingCall(uuid: UUID, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
|
||||
public func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
(sharedProviderDelegate as? CallKitProviderDelegate)?.reportIncomingCall(uuid: uuid, handle: handle, isVideo: isVideo, displayTitle: displayTitle, completion: completion)
|
||||
(sharedProviderDelegate as? CallKitProviderDelegate)?.reportIncomingCall(uuid: uuid, stableId: stableId, handle: handle, isVideo: isVideo, displayTitle: displayTitle, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +117,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
|
||||
private let callController = CXCallController()
|
||||
|
||||
private var currentStartCallAccount: (UUID, AccountContext)?
|
||||
|
||||
private var alreadyReportedIncomingCalls = Set<UUID>()
|
||||
|
||||
private var startCall: ((AccountContext, UUID, String, Bool) -> Signal<Bool, NoError>)?
|
||||
private var answerCall: ((UUID) -> Void)?
|
||||
@ -163,7 +181,9 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
|
||||
}
|
||||
|
||||
func answerCall(uuid: UUID) {
|
||||
|
||||
let answerCallAction = CXAnswerCallAction(call: uuid)
|
||||
let transaction = CXTransaction(action: answerCallAction)
|
||||
self.requestTransaction(transaction)
|
||||
}
|
||||
|
||||
func startCall(context: AccountContext, peerId: PeerId, isVideo: Bool, displayTitle: String) {
|
||||
@ -189,7 +209,13 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate {
|
||||
})
|
||||
}
|
||||
|
||||
func reportIncomingCall(uuid: UUID, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
|
||||
func reportIncomingCall(uuid: UUID, stableId: Int64, handle: String, isVideo: Bool, displayTitle: String, completion: ((NSError?) -> Void)?) {
|
||||
if self.alreadyReportedIncomingCalls.contains(uuid) {
|
||||
completion?(nil)
|
||||
return
|
||||
}
|
||||
self.alreadyReportedIncomingCalls.insert(uuid)
|
||||
|
||||
let update = CXCallUpdate()
|
||||
update.remoteHandle = CXHandle(type: .generic, value: handle)
|
||||
update.localizedCallerName = displayTitle
|
||||
|
@ -608,27 +608,34 @@ public final class PresentationCallImpl: PresentationCall {
|
||||
case .ringing:
|
||||
presentationState = PresentationCallState(state: .ringing, videoState: mappedVideoState, remoteVideoState: mappedRemoteVideoState, remoteAudioState: mappedRemoteAudioState, remoteBatteryLevel: mappedRemoteBatteryLevel)
|
||||
if previous == nil || previousControl == nil {
|
||||
if !self.reportedIncomingCall {
|
||||
if !self.reportedIncomingCall, let stableId = sessionState.stableId {
|
||||
self.reportedIncomingCall = true
|
||||
self.callKitIntegration?.reportIncomingCall(uuid: self.internalId, handle: "\(self.peerId.id)", isVideo: sessionState.type == .video, displayTitle: self.peer?.debugDisplayTitle ?? "Unknown", completion: { [weak self] error in
|
||||
if let error = error {
|
||||
if error.domain == "com.apple.CallKit.error.incomingcall" && (error.code == -3 || error.code == 3) {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall device in DND mode")
|
||||
Queue.mainQueue().async {
|
||||
/*if let strongSelf = self {
|
||||
strongSelf.callSessionManager.drop(internalId: strongSelf.internalId, reason: .busy, debugLog: .single(nil))
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall error \(error)")
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.callSessionManager.drop(internalId: strongSelf.internalId, reason: .hangUp, debugLog: .single(nil))
|
||||
self.callKitIntegration?.reportIncomingCall(
|
||||
uuid: self.internalId,
|
||||
stableId: stableId,
|
||||
handle: "\(self.peerId.id)",
|
||||
isVideo: sessionState.type == .video,
|
||||
displayTitle: self.peer?.debugDisplayTitle ?? "Unknown",
|
||||
completion: { [weak self] error in
|
||||
if let error = error {
|
||||
if error.domain == "com.apple.CallKit.error.incomingcall" && (error.code == -3 || error.code == 3) {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall device in DND mode")
|
||||
Queue.mainQueue().async {
|
||||
/*if let strongSelf = self {
|
||||
strongSelf.callSessionManager.drop(internalId: strongSelf.internalId, reason: .busy, debugLog: .single(nil))
|
||||
}*/
|
||||
}
|
||||
} else {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall error \(error)")
|
||||
Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.callSessionManager.drop(internalId: strongSelf.internalId, reason: .hangUp, debugLog: .single(nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
case .accepting:
|
||||
|
@ -113,7 +113,14 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
return OngoingCallContext.versions(includeExperimental: includeExperimental, includeReference: includeReference)
|
||||
}
|
||||
|
||||
public init(accountManager: AccountManager<TelegramAccountManagerTypes>, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), isMediaPlaying: @escaping () -> Bool, resumeMediaPlayback: @escaping () -> Void, audioSession: ManagedAudioSession, activeAccounts: Signal<[AccountContext], NoError>) {
|
||||
public init(
|
||||
accountManager: AccountManager<TelegramAccountManagerTypes>,
|
||||
getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void),
|
||||
isMediaPlaying: @escaping () -> Bool,
|
||||
resumeMediaPlayback: @escaping () -> Void,
|
||||
audioSession: ManagedAudioSession,
|
||||
activeAccounts: Signal<[AccountContext], NoError>
|
||||
) {
|
||||
self.getDeviceAccessData = getDeviceAccessData
|
||||
self.accountManager = accountManager
|
||||
self.audioSession = audioSession
|
||||
@ -127,7 +134,8 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
||||
var setCallMutedImpl: ((UUID, Bool) -> Void)?
|
||||
var audioSessionActivationChangedImpl: ((Bool) -> Void)?
|
||||
|
||||
self.callKitIntegration = CallKitIntegration(startCall: { context, uuid, handle, isVideo in
|
||||
self.callKitIntegration = CallKitIntegration.shared
|
||||
self.callKitIntegration?.setup(startCall: { context, uuid, handle, isVideo in
|
||||
if let startCallImpl = startCallImpl {
|
||||
return startCallImpl(context, uuid, handle, isVideo)
|
||||
} else {
|
||||
|
@ -675,6 +675,11 @@ public struct AccountRunningImportantTasks: OptionSet {
|
||||
public struct MasterNotificationKey: Codable {
|
||||
public let id: Data
|
||||
public let data: Data
|
||||
|
||||
public init(id: Data, data: Data) {
|
||||
self.id = id
|
||||
self.data = data
|
||||
}
|
||||
}
|
||||
|
||||
public func masterNotificationsKey(account: Account, ignoreDisabled: Bool) -> Signal<MasterNotificationKey, NoError> {
|
||||
@ -810,7 +815,8 @@ public func accountBackupData(postbox: Postbox) -> Signal<AccountBackupData?, No
|
||||
peerId: state.peerId.toInt64(),
|
||||
masterDatacenterKey: authKey,
|
||||
masterDatacenterKeyId: datacenterAuthInfo.authKeyId,
|
||||
notificationEncryptionKeyId: notificationsKey?.id
|
||||
notificationEncryptionKeyId: notificationsKey?.id,
|
||||
notificationEncryptionKey: notificationsKey?.data
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -135,90 +135,95 @@ final class AccountManagerImpl<Types: AccountManagerTypes> {
|
||||
deinit {
|
||||
assert(self.queue.isCurrent())
|
||||
}
|
||||
|
||||
fileprivate func transactionSync<T>(ignoreDisabled: Bool, _ f: (AccountManagerModifier<Types>) -> T) -> T {
|
||||
self.valueBox.begin()
|
||||
|
||||
let transaction = AccountManagerModifier<Types>(getRecords: {
|
||||
return self.currentAtomicState.records.map { $0.1 }
|
||||
}, updateRecord: { id, update in
|
||||
let current = self.currentAtomicState.records[id]
|
||||
let updated = update(current)
|
||||
if updated != current {
|
||||
if let updated = updated {
|
||||
self.currentAtomicState.records[id] = updated
|
||||
} else {
|
||||
self.currentAtomicState.records.removeValue(forKey: id)
|
||||
}
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.currentRecordOperations.append(.set(id: id, record: updated))
|
||||
}
|
||||
}, getCurrent: {
|
||||
if let id = self.currentAtomicState.currentRecordId, let record = self.currentAtomicState.records[id] {
|
||||
return (record.id, record.attributes)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, setCurrentId: { id in
|
||||
self.currentAtomicState.currentRecordId = id
|
||||
self.currentMetadataOperations.append(.updateCurrentAccountId(id))
|
||||
self.currentAtomicStateUpdated = true
|
||||
}, getCurrentAuth: {
|
||||
if let record = self.currentAtomicState.currentAuthRecord {
|
||||
return record
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, createAuth: { attributes in
|
||||
let record = AuthAccountRecord<Types.Attribute>(id: generateAccountRecordId(), attributes: attributes)
|
||||
self.currentAtomicState.currentAuthRecord = record
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.currentMetadataOperations.append(.updateCurrentAuthAccountRecord(record))
|
||||
return record
|
||||
}, removeAuth: {
|
||||
self.currentAtomicState.currentAuthRecord = nil
|
||||
self.currentMetadataOperations.append(.updateCurrentAuthAccountRecord(nil))
|
||||
self.currentAtomicStateUpdated = true
|
||||
}, createRecord: { attributes in
|
||||
let id = generateAccountRecordId()
|
||||
let record = AccountRecord<Types.Attribute>(id: id, attributes: attributes, temporarySessionId: nil)
|
||||
self.currentAtomicState.records[id] = record
|
||||
self.currentRecordOperations.append(.set(id: id, record: record))
|
||||
self.currentAtomicStateUpdated = true
|
||||
return id
|
||||
}, getSharedData: { key in
|
||||
return self.sharedDataTable.get(key: key)
|
||||
}, updateSharedData: { key, f in
|
||||
let updated = f(self.sharedDataTable.get(key: key))
|
||||
self.sharedDataTable.set(key: key, value: updated, updatedKeys: &self.currentUpdatedSharedDataKeys)
|
||||
}, getAccessChallengeData: {
|
||||
return self.legacyMetadataTable.getAccessChallengeData()
|
||||
}, setAccessChallengeData: { data in
|
||||
self.currentUpdatedAccessChallengeData = data
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.legacyMetadataTable.setAccessChallengeData(data)
|
||||
self.currentAtomicState.accessChallengeData = data
|
||||
}, getVersion: {
|
||||
return self.legacyMetadataTable.getVersion()
|
||||
}, setVersion: { version in
|
||||
self.legacyMetadataTable.setVersion(version)
|
||||
}, getNotice: { key in
|
||||
self.noticeTable.get(key: key)
|
||||
}, setNotice: { key, value in
|
||||
self.noticeTable.set(key: key, value: value)
|
||||
self.currentUpdatedNoticeEntryKeys.insert(key)
|
||||
}, clearNotices: {
|
||||
self.noticeTable.clear()
|
||||
})
|
||||
|
||||
let result = f(transaction)
|
||||
|
||||
self.beforeCommit()
|
||||
|
||||
self.valueBox.commit()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
fileprivate func transaction<T>(ignoreDisabled: Bool, _ f: @escaping (AccountManagerModifier<Types>) -> T) -> Signal<T, NoError> {
|
||||
return Signal { subscriber in
|
||||
self.queue.justDispatch {
|
||||
self.valueBox.begin()
|
||||
|
||||
let transaction = AccountManagerModifier<Types>(getRecords: {
|
||||
return self.currentAtomicState.records.map { $0.1 }
|
||||
}, updateRecord: { id, update in
|
||||
let current = self.currentAtomicState.records[id]
|
||||
let updated = update(current)
|
||||
if updated != current {
|
||||
if let updated = updated {
|
||||
self.currentAtomicState.records[id] = updated
|
||||
} else {
|
||||
self.currentAtomicState.records.removeValue(forKey: id)
|
||||
}
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.currentRecordOperations.append(.set(id: id, record: updated))
|
||||
}
|
||||
}, getCurrent: {
|
||||
if let id = self.currentAtomicState.currentRecordId, let record = self.currentAtomicState.records[id] {
|
||||
return (record.id, record.attributes)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, setCurrentId: { id in
|
||||
self.currentAtomicState.currentRecordId = id
|
||||
self.currentMetadataOperations.append(.updateCurrentAccountId(id))
|
||||
self.currentAtomicStateUpdated = true
|
||||
}, getCurrentAuth: {
|
||||
if let record = self.currentAtomicState.currentAuthRecord {
|
||||
return record
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}, createAuth: { attributes in
|
||||
let record = AuthAccountRecord<Types.Attribute>(id: generateAccountRecordId(), attributes: attributes)
|
||||
self.currentAtomicState.currentAuthRecord = record
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.currentMetadataOperations.append(.updateCurrentAuthAccountRecord(record))
|
||||
return record
|
||||
}, removeAuth: {
|
||||
self.currentAtomicState.currentAuthRecord = nil
|
||||
self.currentMetadataOperations.append(.updateCurrentAuthAccountRecord(nil))
|
||||
self.currentAtomicStateUpdated = true
|
||||
}, createRecord: { attributes in
|
||||
let id = generateAccountRecordId()
|
||||
let record = AccountRecord<Types.Attribute>(id: id, attributes: attributes, temporarySessionId: nil)
|
||||
self.currentAtomicState.records[id] = record
|
||||
self.currentRecordOperations.append(.set(id: id, record: record))
|
||||
self.currentAtomicStateUpdated = true
|
||||
return id
|
||||
}, getSharedData: { key in
|
||||
return self.sharedDataTable.get(key: key)
|
||||
}, updateSharedData: { key, f in
|
||||
let updated = f(self.sharedDataTable.get(key: key))
|
||||
self.sharedDataTable.set(key: key, value: updated, updatedKeys: &self.currentUpdatedSharedDataKeys)
|
||||
}, getAccessChallengeData: {
|
||||
return self.legacyMetadataTable.getAccessChallengeData()
|
||||
}, setAccessChallengeData: { data in
|
||||
self.currentUpdatedAccessChallengeData = data
|
||||
self.currentAtomicStateUpdated = true
|
||||
self.legacyMetadataTable.setAccessChallengeData(data)
|
||||
self.currentAtomicState.accessChallengeData = data
|
||||
}, getVersion: {
|
||||
return self.legacyMetadataTable.getVersion()
|
||||
}, setVersion: { version in
|
||||
self.legacyMetadataTable.setVersion(version)
|
||||
}, getNotice: { key in
|
||||
self.noticeTable.get(key: key)
|
||||
}, setNotice: { key, value in
|
||||
self.noticeTable.set(key: key, value: value)
|
||||
self.currentUpdatedNoticeEntryKeys.insert(key)
|
||||
}, clearNotices: {
|
||||
self.noticeTable.clear()
|
||||
})
|
||||
|
||||
let result = f(transaction)
|
||||
|
||||
self.beforeCommit()
|
||||
|
||||
self.valueBox.commit()
|
||||
//self.valueBox.checkpoint()
|
||||
let result = self.transactionSync(ignoreDisabled: ignoreDisabled, f)
|
||||
|
||||
subscriber.putNext(result)
|
||||
subscriber.putCompletion()
|
||||
@ -293,6 +298,13 @@ final class AccountManagerImpl<Types: AccountManagerTypes> {
|
||||
})
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
fileprivate func _internalAccountRecordsSync() -> AccountRecordsView<Types> {
|
||||
let mutableView = MutableAccountRecordsView<Types>(getRecords: {
|
||||
return self.currentAtomicState.records.map { $0.1 }
|
||||
}, currentId: self.currentAtomicState.currentRecordId, currentAuth: self.currentAtomicState.currentAuthRecord)
|
||||
return AccountRecordsView<Types>(mutableView)
|
||||
}
|
||||
|
||||
fileprivate func sharedData(keys: Set<ValueBoxKey>) -> Signal<AccountSharedDataView<Types>, NoError> {
|
||||
return self.transaction(ignoreDisabled: false, { transaction -> Signal<AccountSharedDataView<Types>, NoError> in
|
||||
@ -517,6 +529,14 @@ public final class AccountManager<Types: AccountManagerTypes> {
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
public func _internalAccountRecordsSync() -> AccountRecordsView<Types> {
|
||||
var result: AccountRecordsView<Types>?
|
||||
self.impl.syncWith { impl in
|
||||
result = impl._internalAccountRecordsSync()
|
||||
}
|
||||
return result!
|
||||
}
|
||||
|
||||
public func sharedData(keys: Set<ValueBoxKey>) -> Signal<AccountSharedDataView<Types>, NoError> {
|
||||
return Signal { subscriber in
|
||||
|
@ -1170,6 +1170,74 @@ public final class AccountStateManager {
|
||||
func notifyDeletedMessages(messageIds: [MessageId]) {
|
||||
self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) })
|
||||
}
|
||||
|
||||
public final class IncomingCallUpdate {
|
||||
public let callId: Int64
|
||||
public let callAccessHash: Int64
|
||||
public let timestamp: Int32
|
||||
public let peer: EnginePeer
|
||||
|
||||
init(
|
||||
callId: Int64,
|
||||
callAccessHash: Int64,
|
||||
timestamp: Int32,
|
||||
peer: EnginePeer
|
||||
) {
|
||||
self.callId = callId
|
||||
self.callAccessHash = callAccessHash
|
||||
self.timestamp = timestamp
|
||||
self.peer = peer
|
||||
}
|
||||
}
|
||||
|
||||
public static func extractIncomingCallUpdate(data: Data) -> IncomingCallUpdate? {
|
||||
var rawData = data
|
||||
let reader = BufferReader(Buffer(data: data))
|
||||
if let signature = reader.readInt32(), signature == 0x3072cfa1 {
|
||||
if let compressedData = parseBytes(reader) {
|
||||
if let decompressedData = MTGzip.decompress(compressedData.makeData()) {
|
||||
rawData = decompressedData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let updates = Api.parse(Buffer(data: rawData)) as? Api.Updates else {
|
||||
return nil
|
||||
}
|
||||
switch updates {
|
||||
case let .updates(updates, users, _, _, _):
|
||||
var peers: [Peer] = []
|
||||
for user in users {
|
||||
peers.append(TelegramUser(user: user))
|
||||
}
|
||||
|
||||
for update in updates {
|
||||
switch update {
|
||||
case let .updatePhoneCall(phoneCall):
|
||||
switch phoneCall {
|
||||
case let .phoneCallRequested(_, id, accessHash, date, adminId, _, _, _):
|
||||
guard let peer = peers.first(where: { $0.id == PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)) }) else {
|
||||
return nil
|
||||
}
|
||||
return IncomingCallUpdate(
|
||||
callId: id,
|
||||
callAccessHash: accessHash,
|
||||
timestamp: date,
|
||||
peer: EnginePeer(peer)
|
||||
)
|
||||
default:
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func processIncomingCallUpdate(data: Data, completion: @escaping ((CallSessionRingingState, CallSession)?) -> Void) {
|
||||
var rawData = data
|
||||
|
@ -63,11 +63,53 @@ enum CallSessionInternalState {
|
||||
case active(id: Int64, accessHash: Int64, beginTimestamp: Int32, key: Data, keyId: Int64, keyVisualHash: Data, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowsP2P: Bool)
|
||||
case dropping(reason: CallSessionTerminationReason, disposable: Disposable)
|
||||
case terminated(id: Int64?, accessHash: Int64?, reason: CallSessionTerminationReason, reportRating: Bool, sendDebugLogs: Bool)
|
||||
|
||||
var stableId: Int64? {
|
||||
switch self {
|
||||
case let .ringing(id, _, _, _, _):
|
||||
return id
|
||||
case let .accepting(id, _, _, _, _):
|
||||
return id
|
||||
case let .awaitingConfirmation(id, _, _, _, _):
|
||||
return id
|
||||
case .requesting:
|
||||
return nil
|
||||
case let .requested(id, _, _, _, _, _):
|
||||
return id
|
||||
case let .confirming(id, _, _, _, _, _):
|
||||
return id
|
||||
case let .active(id, _, _, _, _, _, _, _, _, _):
|
||||
return id
|
||||
case .dropping:
|
||||
return nil
|
||||
case let .terminated(id, _, _, _, _):
|
||||
return id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public typealias CallSessionInternalId = UUID
|
||||
typealias CallSessionStableId = Int64
|
||||
|
||||
private final class StableIncomingUUIDs {
|
||||
static let shared = Atomic<StableIncomingUUIDs>(value: StableIncomingUUIDs())
|
||||
|
||||
private var dict: [Int64: UUID] = [:]
|
||||
|
||||
private init() {
|
||||
}
|
||||
|
||||
func get(id: Int64) -> UUID {
|
||||
if let value = self.dict[id] {
|
||||
return value
|
||||
} else {
|
||||
let value = UUID()
|
||||
self.dict[id] = value
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct CallSessionRingingState: Equatable {
|
||||
public let id: CallSessionInternalId
|
||||
public let peerId: PeerId
|
||||
@ -147,10 +189,27 @@ public struct CallSession {
|
||||
}
|
||||
|
||||
public let id: CallSessionInternalId
|
||||
public let stableId: Int64?
|
||||
public let isOutgoing: Bool
|
||||
public let type: CallType
|
||||
public let state: CallSessionState
|
||||
public let isVideoPossible: Bool
|
||||
|
||||
init(
|
||||
id: CallSessionInternalId,
|
||||
stableId: Int64?,
|
||||
isOutgoing: Bool,
|
||||
type: CallType,
|
||||
state: CallSessionState,
|
||||
isVideoPossible: Bool
|
||||
) {
|
||||
self.id = id
|
||||
self.stableId = stableId
|
||||
self.isOutgoing = isOutgoing
|
||||
self.type = type
|
||||
self.state = state
|
||||
self.isVideoPossible = isVideoPossible
|
||||
}
|
||||
}
|
||||
|
||||
public enum CallSessionConnection: Equatable {
|
||||
@ -384,7 +443,7 @@ private final class CallSessionManagerContext {
|
||||
let index = context.subscribers.add { next in
|
||||
subscriber.putNext(next)
|
||||
}
|
||||
subscriber.putNext(CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible))
|
||||
subscriber.putNext(CallSession(id: internalId, stableId: context.state.stableId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible))
|
||||
disposable.set(ActionDisposable {
|
||||
queue.async {
|
||||
if let strongSelf = self, let context = strongSelf.contexts[internalId] {
|
||||
@ -447,7 +506,7 @@ private final class CallSessionManagerContext {
|
||||
|
||||
private func contextUpdated(internalId: CallSessionInternalId) {
|
||||
if let context = self.contexts[internalId] {
|
||||
let session = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||
let session = CallSession(id: internalId, stableId: context.state.stableId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||
for subscriber in context.subscribers.copyItems() {
|
||||
subscriber(session)
|
||||
}
|
||||
@ -469,7 +528,7 @@ private final class CallSessionManagerContext {
|
||||
isVideoPossible = true
|
||||
//#endif
|
||||
|
||||
let internalId = CallSessionInternalId()
|
||||
let internalId = CallSessionManager.getStableIncomingUUID(stableId: stableId)
|
||||
let context = CallSessionContext(peerId: peerId, isOutgoing: false, type: isVideo ? .video : .audio, isVideoPossible: isVideoPossible, state: .ringing(id: stableId, accessHash: accessHash, gAHash: gAHash, b: b, versions: versions))
|
||||
self.contexts[internalId] = context
|
||||
let queue = self.queue
|
||||
@ -835,7 +894,7 @@ private final class CallSessionManagerContext {
|
||||
}
|
||||
}
|
||||
if let context = self.contexts[internalId] {
|
||||
let callSession = CallSession(id: internalId, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||
let callSession = CallSession(id: internalId, stableId: id, isOutgoing: context.isOutgoing, type: context.type, state: CallSessionState(context), isVideoPossible: context.isVideoPossible)
|
||||
if let resultRingingStateValue = resultRingingStateValue {
|
||||
resultRingingState = (resultRingingStateValue, callSession)
|
||||
}
|
||||
@ -948,6 +1007,12 @@ public enum CallRequestError {
|
||||
}
|
||||
|
||||
public final class CallSessionManager {
|
||||
public static func getStableIncomingUUID(stableId: Int64) -> UUID {
|
||||
return StableIncomingUUIDs.shared.with { impl in
|
||||
return impl.get(id: stableId)
|
||||
}
|
||||
}
|
||||
|
||||
private let queue = Queue()
|
||||
private var contextRef: Unmanaged<CallSessionManagerContext>?
|
||||
|
||||
|
@ -7,19 +7,22 @@ public struct AccountBackupData: Codable, Equatable {
|
||||
public var masterDatacenterKey: Data
|
||||
public var masterDatacenterKeyId: Int64
|
||||
public var notificationEncryptionKeyId: Data?
|
||||
public var notificationEncryptionKey: Data?
|
||||
|
||||
public init(
|
||||
masterDatacenterId: Int32,
|
||||
peerId: Int64,
|
||||
masterDatacenterKey: Data,
|
||||
masterDatacenterKeyId: Int64,
|
||||
notificationEncryptionKeyId: Data?
|
||||
notificationEncryptionKeyId: Data?,
|
||||
notificationEncryptionKey: Data?
|
||||
) {
|
||||
self.masterDatacenterId = masterDatacenterId
|
||||
self.peerId = peerId
|
||||
self.masterDatacenterKey = masterDatacenterKey
|
||||
self.masterDatacenterKeyId = masterDatacenterKeyId
|
||||
self.notificationEncryptionKeyId = notificationEncryptionKeyId
|
||||
self.notificationEncryptionKey = notificationEncryptionKey
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +175,35 @@ final class SharedApplicationContext {
|
||||
}
|
||||
}
|
||||
|
||||
private struct AccountManagerState {
|
||||
struct NotificationKey {
|
||||
var accountId: AccountRecordId
|
||||
var id: Data
|
||||
var key: Data
|
||||
}
|
||||
|
||||
var notificationKeys: [NotificationKey]
|
||||
}
|
||||
|
||||
private func extractAccountManagerState(records: AccountRecordsView<TelegramAccountManagerTypes>) -> AccountManagerState {
|
||||
return AccountManagerState(
|
||||
notificationKeys: records.records.compactMap { record -> AccountManagerState.NotificationKey? in
|
||||
for attribute in record.attributes {
|
||||
if case let .backupData(backupData) = attribute {
|
||||
if let notificationEncryptionKeyId = backupData.data?.notificationEncryptionKeyId, let notificationEncryptionKey = backupData.data?.notificationEncryptionKey {
|
||||
return AccountManagerState.NotificationKey(
|
||||
accountId: record.id,
|
||||
id: notificationEncryptionKeyId,
|
||||
key: notificationEncryptionKey
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@objc(AppDelegate) class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate, UNUserNotificationCenterDelegate {
|
||||
@objc var window: UIWindow?
|
||||
var nativeWindow: (UIWindow & WindowHost)?
|
||||
@ -192,6 +221,9 @@ final class SharedApplicationContext {
|
||||
|
||||
private let sharedContextPromise = Promise<SharedApplicationContext>()
|
||||
private let watchCommunicationManagerPromise = Promise<WatchCommunicationManager?>()
|
||||
|
||||
private var accountManager: AccountManager<TelegramAccountManagerTypes>?
|
||||
private var accountManagerState: AccountManagerState?
|
||||
|
||||
private var contextValue: AuthorizedApplicationContext?
|
||||
private let context = Promise<AuthorizedApplicationContext?>()
|
||||
@ -486,8 +518,6 @@ final class SharedApplicationContext {
|
||||
UNUserNotificationCenter.current().delegate = self
|
||||
}
|
||||
|
||||
telegramUIDeclareEncodables()
|
||||
|
||||
GlobalExperimentalSettings.isAppStoreBuild = buildConfig.isAppStoreBuild
|
||||
GlobalExperimentalSettings.enableFeed = false
|
||||
|
||||
@ -495,8 +525,6 @@ final class SharedApplicationContext {
|
||||
|
||||
self.hasActiveAudioSession.set(MediaManagerImpl.globalAudioSession.isActive())
|
||||
|
||||
initializeAccountManagement()
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: true, appBundleId: baseAppBundleId, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { url in
|
||||
var parsedUrl = URL(string: url)
|
||||
if let parsed = parsedUrl {
|
||||
@ -676,47 +704,29 @@ final class SharedApplicationContext {
|
||||
UIDevice.current.setValue(value, forKey: "orientation")
|
||||
UINavigationController.attemptRotationToDeviceOrientation()
|
||||
})
|
||||
|
||||
let accountManagerSignal = Signal<AccountManager<TelegramAccountManagerTypes>, NoError> { subscriber in
|
||||
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true)
|
||||
return (upgradedAccounts(accountManager: accountManager, rootPath: rootPath, encryptionParameters: encryptionParameters)
|
||||
|> deliverOnMainQueue).start(next: { progress in
|
||||
if self.dataImportSplash == nil {
|
||||
self.dataImportSplash = makeLegacyDataImportSplash(theme: nil, strings: nil)
|
||||
self.dataImportSplash?.serviceAction = {
|
||||
self.debugPressed()
|
||||
}
|
||||
self.mainWindow.coveringView = self.dataImportSplash
|
||||
}
|
||||
self.dataImportSplash?.progress = (.generic, progress)
|
||||
}, completed: {
|
||||
if let dataImportSplash = self.dataImportSplash {
|
||||
self.dataImportSplash = nil
|
||||
if self.mainWindow.coveringView === dataImportSplash {
|
||||
self.mainWindow.coveringView = nil
|
||||
}
|
||||
}
|
||||
subscriber.putNext(accountManager)
|
||||
subscriber.putCompletion()
|
||||
})
|
||||
|
||||
let accountManager = AccountManager<TelegramAccountManagerTypes>(basePath: rootPath + "/accounts-metadata", isTemporary: false, isReadOnly: false, useCaches: true)
|
||||
self.accountManager = accountManager
|
||||
|
||||
telegramUIDeclareEncodables()
|
||||
initializeAccountManagement()
|
||||
|
||||
self.accountManagerState = extractAccountManagerState(records: accountManager._internalAccountRecordsSync())
|
||||
let _ = (accountManager.accountRecords()
|
||||
|> deliverOnMainQueue).start(next: { view in
|
||||
self.accountManagerState = extractAccountManagerState(records: view)
|
||||
})
|
||||
|
||||
var systemUserInterfaceStyle: WindowUserInterfaceStyle = .light
|
||||
if #available(iOS 13.0, *) {
|
||||
if let traitCollection = window.rootViewController?.traitCollection {
|
||||
systemUserInterfaceStyle = WindowUserInterfaceStyle(style: traitCollection.userInterfaceStyle)
|
||||
}
|
||||
}
|
||||
|
||||
let sharedContextSignal = accountManagerSignal
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)
|
||||
|> mapToSignal { accountManager -> Signal<(AccountManager<TelegramAccountManagerTypes>, InitialPresentationDataAndSettings), NoError> in
|
||||
var systemUserInterfaceStyle: WindowUserInterfaceStyle = .light
|
||||
if #available(iOS 13.0, *) {
|
||||
if let traitCollection = window.rootViewController?.traitCollection {
|
||||
systemUserInterfaceStyle = WindowUserInterfaceStyle(style: traitCollection.userInterfaceStyle)
|
||||
}
|
||||
}
|
||||
return currentPresentationDataAndSettings(accountManager: accountManager, systemUserInterfaceStyle: systemUserInterfaceStyle)
|
||||
|> map { initialPresentationDataAndSettings -> (AccountManager, InitialPresentationDataAndSettings) in
|
||||
return (accountManager, initialPresentationDataAndSettings)
|
||||
}
|
||||
let sharedContextSignal = currentPresentationDataAndSettings(accountManager: accountManager, systemUserInterfaceStyle: systemUserInterfaceStyle)
|
||||
|> map { initialPresentationDataAndSettings -> (AccountManager, InitialPresentationDataAndSettings) in
|
||||
return (accountManager, initialPresentationDataAndSettings)
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { accountManager, initialPresentationDataAndSettings -> Signal<(SharedApplicationContext, LoggingSettings), NoError> in
|
||||
@ -1417,7 +1427,7 @@ final class SharedApplicationContext {
|
||||
}
|
||||
|
||||
public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType) {
|
||||
/*guard var encryptedPayload = payload.dictionaryPayload["p"] as? String else {
|
||||
guard var encryptedPayload = payload.dictionaryPayload["p"] as? String else {
|
||||
return
|
||||
}
|
||||
encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+")
|
||||
@ -1425,11 +1435,81 @@ final class SharedApplicationContext {
|
||||
while encryptedPayload.count % 4 != 0 {
|
||||
encryptedPayload.append("=")
|
||||
}
|
||||
guard let data = Data(base64Encoded: encryptedPayload) else {
|
||||
guard let payloadData = Data(base64Encoded: encryptedPayload) else {
|
||||
return
|
||||
}
|
||||
guard let keyId = notificationPayloadKeyId(data: payloadData) else {
|
||||
return
|
||||
}
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
guard let accountManagerState = self.accountManagerState else {
|
||||
return
|
||||
}
|
||||
|
||||
var maybeAccountId: AccountRecordId?
|
||||
var maybeNotificationKey: MasterNotificationKey?
|
||||
|
||||
for key in accountManagerState.notificationKeys {
|
||||
if key.id == keyId {
|
||||
maybeAccountId = key.accountId
|
||||
maybeNotificationKey = MasterNotificationKey(id: key.id, data: key.key)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
guard let accountId = maybeAccountId, let notificationKey = maybeNotificationKey else {
|
||||
return
|
||||
}
|
||||
guard let decryptedPayload = decryptedNotificationPayload(key: notificationKey, data: payloadData) else {
|
||||
return
|
||||
}
|
||||
guard let payloadJson = try? JSONSerialization.jsonObject(with: decryptedPayload, options: []) as? [String: Any] else {
|
||||
return
|
||||
}
|
||||
guard var updateString = payloadJson["updates"] as? String else {
|
||||
return
|
||||
}
|
||||
|
||||
updateString = updateString.replacingOccurrences(of: "-", with: "+")
|
||||
updateString = updateString.replacingOccurrences(of: "_", with: "/")
|
||||
while updateString.count % 4 != 0 {
|
||||
updateString.append("=")
|
||||
}
|
||||
guard let updateData = Data(base64Encoded: updateString) else {
|
||||
return
|
||||
}
|
||||
guard let callUpdate = AccountStateManager.extractIncomingCallUpdate(data: updateData) else {
|
||||
return
|
||||
}
|
||||
guard let callKitIntegration = CallKitIntegration.shared else {
|
||||
return
|
||||
}
|
||||
|
||||
callKitIntegration.reportIncomingCall(
|
||||
uuid: CallSessionManager.getStableIncomingUUID(stableId: callUpdate.callId),
|
||||
stableId: callUpdate.callId,
|
||||
handle: "\(callUpdate.peer.id.id)",
|
||||
isVideo: false,
|
||||
displayTitle: callUpdate.peer.debugDisplayTitle,
|
||||
completion: { error in
|
||||
if let error = error {
|
||||
if error.domain == "com.apple.CallKit.error.incomingcall" && (error.code == -3 || error.code == 3) {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall device in DND mode")
|
||||
} else {
|
||||
Logger.shared.log("PresentationCall", "reportIncomingCall error \(error)")
|
||||
/*Queue.mainQueue().async {
|
||||
if let strongSelf = self {
|
||||
strongSelf.callSessionManager.drop(internalId: strongSelf.internalId, reason: .hangUp, debugLog: .single(nil))
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
let _ = accountId
|
||||
|
||||
/*let semaphore = DispatchSemaphore(value: 0)
|
||||
var accountAndDecryptedPayload: (Account, Data)?
|
||||
|
||||
var sharedApplicationContextValue: SharedApplicationContext?
|
||||
@ -1486,6 +1566,7 @@ final class SharedApplicationContext {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
let _ = (self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sharedApplicationContext in
|
||||
|
@ -1507,7 +1507,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if count < 1 || true {
|
||||
if count < 1 {
|
||||
let _ = ApplicationSpecificNotice.incrementSharedMediaFastScrollingTooltip(accountManager: strongSelf.context.sharedContext.accountManager).start()
|
||||
|
||||
var currentNode: ASDisplayNode = strongSelf
|
||||
|
@ -1,121 +1 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramUIPreferences
|
||||
import MediaResources
|
||||
|
||||
private enum LegacyPreferencesKeyValues: Int32 {
|
||||
case cacheStorageSettings = 1
|
||||
case localizationSettings = 2
|
||||
case proxySettings = 5
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 4)
|
||||
key.setInt32(0, value: self.rawValue)
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
private enum UpgradedSharedDataKeyValues: Int32 {
|
||||
case cacheStorageSettings = 2
|
||||
case localizationSettings = 3
|
||||
case proxySettings = 4
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let key = ValueBoxKey(length: 4)
|
||||
key.setInt32(0, value: self.rawValue)
|
||||
return key
|
||||
}
|
||||
}
|
||||
|
||||
private enum LegacyApplicationSpecificPreferencesKeyValues: Int32 {
|
||||
case inAppNotificationSettings = 0
|
||||
case presentationPasscodeSettings = 1
|
||||
case automaticMediaDownloadSettings = 2
|
||||
case generatedMediaStoreSettings = 3
|
||||
case voiceCallSettings = 4
|
||||
case presentationThemeSettings = 5
|
||||
case instantPagePresentationSettings = 6
|
||||
case callListSettings = 7
|
||||
case experimentalSettings = 8
|
||||
case musicPlaybackSettings = 9
|
||||
case mediaInputSettings = 10
|
||||
case experimentalUISettings = 11
|
||||
case contactSynchronizationSettings = 12
|
||||
case stickerSettings = 13
|
||||
case watchPresetSettings = 14
|
||||
case webSearchSettings = 15
|
||||
case voipDerivedState = 16
|
||||
|
||||
var key: ValueBoxKey {
|
||||
return applicationSpecificPreferencesKey(self.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
private enum UpgradedApplicationSpecificSharedDataKeyValues: Int32 {
|
||||
case inAppNotificationSettings = 0
|
||||
case presentationPasscodeSettings = 1
|
||||
case automaticMediaDownloadSettings = 2
|
||||
case generatedMediaStoreSettings = 3
|
||||
case voiceCallSettings = 4
|
||||
case presentationThemeSettings = 5
|
||||
case instantPagePresentationSettings = 6
|
||||
case callListSettings = 7
|
||||
case experimentalSettings = 8
|
||||
case musicPlaybackSettings = 9
|
||||
case mediaInputSettings = 10
|
||||
case experimentalUISettings = 11
|
||||
case stickerSettings = 12
|
||||
case watchPresetSettings = 13
|
||||
case webSearchSettings = 14
|
||||
case contactSynchronizationSettings = 15
|
||||
|
||||
var key: ValueBoxKey {
|
||||
return applicationSpecificSharedDataKey(self.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
private let preferencesKeyMapping: [LegacyPreferencesKeyValues: UpgradedSharedDataKeyValues] = [
|
||||
.cacheStorageSettings: .cacheStorageSettings,
|
||||
.localizationSettings: .localizationSettings,
|
||||
.proxySettings: .proxySettings
|
||||
]
|
||||
|
||||
private let applicationSpecificPreferencesKeyMapping: [LegacyApplicationSpecificPreferencesKeyValues: UpgradedApplicationSpecificSharedDataKeyValues] = [
|
||||
.inAppNotificationSettings: .inAppNotificationSettings,
|
||||
.presentationPasscodeSettings: .presentationPasscodeSettings,
|
||||
.automaticMediaDownloadSettings: .automaticMediaDownloadSettings,
|
||||
.generatedMediaStoreSettings: .generatedMediaStoreSettings,
|
||||
.voiceCallSettings: .voiceCallSettings,
|
||||
.presentationThemeSettings: .presentationThemeSettings,
|
||||
.instantPagePresentationSettings: .instantPagePresentationSettings,
|
||||
.callListSettings: .callListSettings,
|
||||
.experimentalSettings: .experimentalSettings,
|
||||
.musicPlaybackSettings: .musicPlaybackSettings,
|
||||
.mediaInputSettings: .mediaInputSettings,
|
||||
.experimentalUISettings: .experimentalUISettings,
|
||||
.stickerSettings: .stickerSettings,
|
||||
.watchPresetSettings: .watchPresetSettings,
|
||||
.webSearchSettings: .webSearchSettings,
|
||||
.contactSynchronizationSettings: .contactSynchronizationSettings
|
||||
]
|
||||
|
||||
private func upgradedSharedDataValue(_ value: PreferencesEntry?) -> PreferencesEntry? {
|
||||
return value
|
||||
}
|
||||
|
||||
public func upgradedAccounts(accountManager: AccountManager<TelegramAccountManagerTypes>, rootPath: String, encryptionParameters: ValueBoxEncryptionParameters) -> Signal<Float, NoError> {
|
||||
return accountManager.transaction { transaction -> (Int32?, AccountRecordId?) in
|
||||
return (transaction.getVersion(), transaction.getCurrent()?.0)
|
||||
}
|
||||
|> mapToSignal { version, currentId -> Signal<Float, NoError> in
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
transaction.setVersion(4)
|
||||
}
|
||||
|> ignoreValues
|
||||
|> mapToSignal { _ -> Signal<Float, NoError> in
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user