mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Support for updated accounts API
Implemented Notification Service Extension
This commit is contained in:
parent
70ebab5a68
commit
d0d8f7dcd4
27 changed files with 1342 additions and 351 deletions
|
|
@ -11,7 +11,7 @@ private enum NotificationContentAuthorizationError {
|
|||
case unauthorized
|
||||
}
|
||||
|
||||
private var accountCache: (Account, AccountManager)?
|
||||
private var sharedAccountContext: SharedAccountContext?
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
|
|
@ -22,9 +22,27 @@ private func setupSharedLogger(_ path: String) {
|
|||
}
|
||||
}
|
||||
|
||||
private func parseFileLocationResource(_ dict: [AnyHashable: Any]) -> TelegramMediaResource? {
|
||||
guard let datacenterId = dict["datacenterId"] as? Int32 else {
|
||||
return nil
|
||||
}
|
||||
guard let volumeId = dict["volumeId"] as? Int64 else {
|
||||
return nil
|
||||
}
|
||||
guard let localId = dict["localId"] as? Int32 else {
|
||||
return nil
|
||||
}
|
||||
guard let secret = dict["secret"] as? Int64 else {
|
||||
return nil
|
||||
}
|
||||
var fileReference: Data?
|
||||
if let fileReferenceString = dict["fileReference"] as? String {
|
||||
fileReference = dataWithHexString(fileReferenceString)
|
||||
}
|
||||
return CloudFileMediaResource(datacenterId: Int(datacenterId), volumeId: volumeId, localId: localId, secret: secret, size: nil, fileReference: fileReference)
|
||||
}
|
||||
|
||||
class NotificationViewController: UIViewController, UNNotificationContentExtension {
|
||||
private let accountPromise = Promise<Account>()
|
||||
|
||||
private let imageNode = TransformImageNode()
|
||||
private var imageDimensions: CGSize?
|
||||
|
||||
|
|
@ -66,47 +84,37 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
|
|||
|
||||
setupSharedLogger(logsPath)
|
||||
|
||||
let account: Signal<(Account, AccountManager), NotificationContentAuthorizationError>
|
||||
if let accountCache = accountCache {
|
||||
account = .single(accountCache)
|
||||
} else {
|
||||
if sharedAccountContext == nil {
|
||||
initializeAccountManagement()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, containerPath: appGroupUrl.path, appSpecificScheme: BuildConfig.shared().appSpecificUrlScheme, openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
completion.completion(false)
|
||||
return
|
||||
}, canOpenUrl: { _ in
|
||||
return false
|
||||
}, getTopWindow: {
|
||||
return nil
|
||||
}, displayNotification: { _ in
|
||||
|
||||
}, applicationInForeground: .single(false), applicationIsActive: .single(false), clearMessageNotifications: { _ in
|
||||
}, pushIdleTimerExtension: {
|
||||
return EmptyDisposable
|
||||
}, openSettings: {}, openAppStorePage: {}, registerForNotifications: { _ in }, requestSiriAuthorization: { _ in }, siriAuthorization: { return .notDetermined }, getWindowHost: {
|
||||
return nil
|
||||
}, presentNativeController: { _ in
|
||||
}, dismissNativeController: {
|
||||
})
|
||||
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
initializeAccountManagement()
|
||||
account = accountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|> take(1)
|
||||
|> introduceError(NotificationContentAuthorizationError.self)
|
||||
|> mapToSignal { accountManager -> Signal<(Account, AccountManager), NotificationContentAuthorizationError> in
|
||||
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: telegramAccountAuxiliaryMethods)
|
||||
|> introduceError(NotificationContentAuthorizationError.self)
|
||||
|> mapToSignal { account -> Signal<(Account, AccountManager), NotificationContentAuthorizationError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
setupAccount(account)
|
||||
accountCache = (account, accountManager)
|
||||
return .single((account, accountManager))
|
||||
case .unauthorized:
|
||||
return .fail(.unauthorized)
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
sharedAccountContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
|
||||
}
|
||||
self.accountPromise.set(account
|
||||
|> map { $0.0 }
|
||||
|> `catch` { _ -> Signal<Account, NoError> in
|
||||
return .complete()
|
||||
})
|
||||
}
|
||||
|
||||
func didReceive(_ notification: UNNotification) {
|
||||
if let peerIdValue = notification.request.content.userInfo["peerId"] as? Int64, let messageIdNamespace = notification.request.content.userInfo["messageId.namespace"] as? Int32, let messageIdId = notification.request.content.userInfo["messageId.id"] as? Int32, let dict = notification.request.content.userInfo["mediaInfo"] as? [String: Any] {
|
||||
if let accountIdValue = notification.request.content.userInfo["accountId"] as? Int64, let peerIdValue = notification.request.content.userInfo["peerId"] as? Int64, let messageIdNamespace = notification.request.content.userInfo["messageId.namespace"] as? Int32, let messageIdId = notification.request.content.userInfo["messageId.id"] as? Int32, let dict = notification.request.content.userInfo["mediaInfo"] as? [String: Any] {
|
||||
let messageId = MessageId(peerId: PeerId(peerIdValue), namespace: messageIdNamespace, id: messageIdId)
|
||||
|
||||
if let imageInfo = dict["image"] as? [String: Any] {
|
||||
|
|
@ -139,19 +147,36 @@ class NotificationViewController: UIViewController, UNNotificationContentExtensi
|
|||
|> map { $0.1 })
|
||||
}
|
||||
|
||||
self.applyDisposable.set((self.accountPromise.get()
|
||||
guard let sharedAccountContext = sharedAccountContext else {
|
||||
return
|
||||
}
|
||||
|
||||
self.applyDisposable.set((sharedAccountContext.activeAccounts
|
||||
|> map { _, accounts, _ -> Account? in
|
||||
return accounts[AccountRecordId(rawValue: accountIdValue)]
|
||||
}
|
||||
|> filter { account in
|
||||
return account != nil
|
||||
}
|
||||
|> take(1)
|
||||
|> mapToSignal { account -> Signal<(Account, ImageMediaReference?), NoError> in
|
||||
guard let account = account else {
|
||||
return .complete()
|
||||
}
|
||||
return account.postbox.messageAtId(messageId)
|
||||
|> take(1)
|
||||
|> map { message in
|
||||
var imageReference: ImageMediaReference?
|
||||
if let message = message {
|
||||
if let message = message, false {
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
imageReference = .message(message: MessageReference(message), media: image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let thumbnailFileLocation = thumbnailInfo["fileLocation"] as? [AnyHashable: Any], let thumbnailResource = parseFileLocationResource(thumbnailFileLocation), let fileLocation = fullSizeInfo["fileLocation"] as? [AnyHashable: Any], let resource = parseFileLocationResource(fileLocation) {
|
||||
imageReference = .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.CloudImage, id: 1), representations: [TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(width), height: CGFloat(height)).fitted(CGSize(width: 320.0, height: 320.0)), resource: thumbnailResource), TelegramMediaImageRepresentation(dimensions: CGSize(width: CGFloat(width), height: CGFloat(height)), resource: resource)], immediateThumbnailData: nil, reference: nil, partialReference: nil))
|
||||
}
|
||||
}
|
||||
return (account, imageReference)
|
||||
}
|
||||
|
|
|
|||
118
NotificationService/AccountData.swift
Normal file
118
NotificationService/AccountData.swift
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
import Foundation
|
||||
import CommonCrypto
|
||||
|
||||
struct MasterNotificationKey: Codable {
|
||||
let id: Data
|
||||
let data: Data
|
||||
}
|
||||
|
||||
struct AccountDatacenterKey: Codable {
|
||||
let id: Int64
|
||||
let data: Data
|
||||
}
|
||||
|
||||
struct AccountDatacenterInfo: Codable {
|
||||
let masterKey: AccountDatacenterKey
|
||||
}
|
||||
|
||||
struct StoredAccountInfo: Codable {
|
||||
let primaryId: Int32
|
||||
let isTestingEnvironment: Bool
|
||||
let datacenters: [Int32: AccountDatacenterInfo]
|
||||
}
|
||||
|
||||
struct AccountData {
|
||||
let id: Int64
|
||||
let isTestingEnvironment: Bool
|
||||
let basePath: String
|
||||
let datacenterId: Int32
|
||||
let datacenters: [Int32: AccountDatacenterInfo]
|
||||
let notificationKey: MasterNotificationKey?
|
||||
}
|
||||
|
||||
func loadAccountsData(rootPath: String) -> [Int64: AccountData] {
|
||||
var result: [Int64: AccountData] = [:]
|
||||
if let contents = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath), includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) {
|
||||
for url in contents {
|
||||
let directoryName = url.lastPathComponent
|
||||
if directoryName.hasPrefix("account-"), let id = UInt64(directoryName[directoryName.index(directoryName.startIndex, offsetBy: "account-".count)...]) {
|
||||
var notificationKey: MasterNotificationKey?
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: url.path + "/notificationsKey")), let value = try? JSONDecoder().decode(MasterNotificationKey.self, from: data) {
|
||||
notificationKey = value
|
||||
}
|
||||
var storedInfo: StoredAccountInfo?
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: url.path + "/storedInfo")), let value = try? JSONDecoder().decode(StoredAccountInfo.self, from: data) {
|
||||
storedInfo = value
|
||||
}
|
||||
if let storedInfo = storedInfo {
|
||||
result[Int64(bitPattern: id)] = AccountData(id: Int64(bitPattern: id), isTestingEnvironment: storedInfo.isTestingEnvironment, basePath: url.path, datacenterId: storedInfo.primaryId, datacenters: storedInfo.datacenters, notificationKey: notificationKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private func sha256Digest(_ data: Data) -> Data {
|
||||
let length = data.count
|
||||
return data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Data in
|
||||
var result = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
|
||||
result.withUnsafeMutableBytes { (destBytes: UnsafeMutablePointer<UInt8>) -> Void in
|
||||
CC_SHA256(bytes, UInt32(length), destBytes)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
func decryptedNotificationPayload(accounts: [Int64: AccountData], data: Data) -> (AccountData, [AnyHashable: Any])? {
|
||||
if data.count < 8 + 16 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for (_, account) in accounts {
|
||||
guard let notificationKey = account.notificationKey else {
|
||||
continue
|
||||
}
|
||||
if data.subdata(in: 0 ..< 8) != notificationKey.id {
|
||||
continue
|
||||
}
|
||||
|
||||
let x = 8
|
||||
let msgKey = data.subdata(in: 8 ..< (8 + 16))
|
||||
let rawData = data.subdata(in: (8 + 16) ..< data.count)
|
||||
let sha256_a = sha256Digest(msgKey + notificationKey.data.subdata(in: x ..< (x + 36)))
|
||||
let sha256_b = sha256Digest(notificationKey.data.subdata(in: (40 + x) ..< (40 + x + 36)) + msgKey)
|
||||
let aesKey = sha256_a.subdata(in: 0 ..< 8) + sha256_b.subdata(in: 8 ..< (8 + 16)) + sha256_a.subdata(in: 24 ..< (24 + 8))
|
||||
let aesIv = sha256_b.subdata(in: 0 ..< 8) + sha256_a.subdata(in: 8 ..< (8 + 16)) + sha256_b.subdata(in: 24 ..< (24 + 8))
|
||||
|
||||
guard let data = MTAesDecrypt(rawData, aesKey, aesIv), data.count > 4 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var dataLength: Int32 = 0
|
||||
data.withUnsafeBytes { (bytes: UnsafePointer<Int8>) -> Void in
|
||||
memcpy(&dataLength, bytes, 4)
|
||||
}
|
||||
|
||||
if dataLength < 0 || dataLength > data.count - 4 {
|
||||
return nil
|
||||
}
|
||||
|
||||
let checkMsgKeyLarge = sha256Digest(notificationKey.data.subdata(in: (88 + x) ..< (88 + x + 32)) + data)
|
||||
let checkMsgKey = checkMsgKeyLarge.subdata(in: 8 ..< (8 + 16))
|
||||
|
||||
if checkMsgKey != msgKey {
|
||||
return nil
|
||||
}
|
||||
|
||||
let contentData = data.subdata(in: 4 ..< (4 + Int(dataLength)))
|
||||
guard let result = try? JSONSerialization.jsonObject(with: contentData, options: []) else {
|
||||
return nil
|
||||
}
|
||||
guard let dict = result as? [AnyHashable: Any] else {
|
||||
return nil
|
||||
}
|
||||
return (account, dict)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
7
NotificationService/Crypto.h
Normal file
7
NotificationService/Crypto.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
73
NotificationService/Crypto.m
Normal file
73
NotificationService/Crypto.m
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#import "Crypto.h"
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
|
||||
typedef struct {
|
||||
unsigned long data[N_WORDS];
|
||||
} aes_block_t;
|
||||
|
||||
static void MyAesIgeDecrypt(const void *inBytes, int length, void *outBytes, const void *key, int keyLength, void *iv) {
|
||||
unsigned char aesIv[AES_BLOCK_SIZE];
|
||||
memcpy(aesIv, iv, AES_BLOCK_SIZE);
|
||||
unsigned char ccIv[AES_BLOCK_SIZE];
|
||||
memcpy(ccIv, iv + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
|
||||
|
||||
assert(((size_t)inBytes | (size_t)outBytes | (size_t)aesIv | (size_t)ccIv) % sizeof(long) ==
|
||||
0);
|
||||
|
||||
CCCryptorRef decryptor = NULL;
|
||||
CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES128, kCCOptionECBMode, key, keyLength, nil, &decryptor);
|
||||
if (decryptor != NULL) {
|
||||
int len;
|
||||
size_t n;
|
||||
|
||||
len = length / AES_BLOCK_SIZE;
|
||||
|
||||
aes_block_t *ivp = (aes_block_t *)(aesIv);
|
||||
aes_block_t *iv2p = (aes_block_t *)(ccIv);
|
||||
|
||||
while (len) {
|
||||
aes_block_t tmp;
|
||||
aes_block_t *inp = (aes_block_t *)inBytes;
|
||||
aes_block_t *outp = (aes_block_t *)outBytes;
|
||||
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
|
||||
|
||||
size_t dataOutMoved = 0;
|
||||
CCCryptorStatus result = CCCryptorUpdate(decryptor, &tmp, AES_BLOCK_SIZE, outBytes, AES_BLOCK_SIZE, &dataOutMoved);
|
||||
assert(result == kCCSuccess);
|
||||
assert(dataOutMoved == AES_BLOCK_SIZE);
|
||||
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
outp->data[n] ^= ivp->data[n];
|
||||
|
||||
ivp = inp;
|
||||
iv2p = outp;
|
||||
|
||||
inBytes += AES_BLOCK_SIZE;
|
||||
outBytes += AES_BLOCK_SIZE;
|
||||
|
||||
--len;
|
||||
}
|
||||
|
||||
memcpy(iv, ivp->data, AES_BLOCK_SIZE);
|
||||
memcpy(iv + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
||||
|
||||
CCCryptorRelease(decryptor);
|
||||
}
|
||||
}
|
||||
|
||||
NSData *MTAesDecrypt(NSData *data, NSData *key, NSData *iv) {
|
||||
assert(key != nil && iv != nil);
|
||||
|
||||
NSMutableData *resultData = [[NSMutableData alloc] initWithLength:data.length];
|
||||
|
||||
unsigned char aesIv[16 * 2];
|
||||
memcpy(aesIv, iv.bytes, iv.length);
|
||||
MyAesIgeDecrypt(data.bytes, (int)data.length, resultData.mutableBytes, key.bytes, (int)key.length, aesIv);
|
||||
|
||||
return resultData;
|
||||
}
|
||||
31
NotificationService/Data.swift
Normal file
31
NotificationService/Data.swift
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import Foundation
|
||||
|
||||
enum Namespaces {
|
||||
struct Peer {
|
||||
static let CloudUser: PeerId.Namespace = 0
|
||||
static let CloudGroup: PeerId.Namespace = 1
|
||||
static let CloudChannel: PeerId.Namespace = 2
|
||||
}
|
||||
}
|
||||
|
||||
struct PeerId {
|
||||
typealias Namespace = Int32
|
||||
typealias Id = Int32
|
||||
|
||||
public let namespace: Namespace
|
||||
public let id: Id
|
||||
|
||||
public init(namespace: Namespace, id: Id) {
|
||||
self.namespace = namespace
|
||||
self.id = id
|
||||
}
|
||||
|
||||
public init(_ n: Int64) {
|
||||
self.namespace = Int32((n >> 32) & 0x7fffffff)
|
||||
self.id = Int32(bitPattern: UInt32(n & 0xffffffff))
|
||||
}
|
||||
|
||||
public func toInt64() -> Int64 {
|
||||
return (Int64(self.namespace) << 32) | Int64(bitPattern: UInt64(UInt32(bitPattern: self.id)))
|
||||
}
|
||||
}
|
||||
421
NotificationService/ImageData.swift
Normal file
421
NotificationService/ImageData.swift
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
import Foundation
|
||||
import MtProtoKitDynamic
|
||||
|
||||
struct ImageResource {
|
||||
let datacenterId: Int
|
||||
let volumeId: Int64
|
||||
let localId: Int32
|
||||
let secret: Int64
|
||||
let fileReference: Data?
|
||||
|
||||
var resourceId: String {
|
||||
return "telegram-cloud-file-\(self.datacenterId)-\(self.volumeId)-\(self.localId)-\(self.secret)"
|
||||
}
|
||||
}
|
||||
|
||||
private final class Buffer {
|
||||
var data: UnsafeMutableRawPointer?
|
||||
var _size: UInt = 0
|
||||
private var capacity: UInt = 0
|
||||
private let freeWhenDone: Bool
|
||||
|
||||
var size: Int {
|
||||
return Int(self._size)
|
||||
}
|
||||
|
||||
deinit {
|
||||
if self.freeWhenDone {
|
||||
free(self.data)
|
||||
}
|
||||
}
|
||||
|
||||
init(memory: UnsafeMutableRawPointer?, size: Int, capacity: Int, freeWhenDone: Bool) {
|
||||
self.data = memory
|
||||
self._size = UInt(size)
|
||||
self.capacity = UInt(capacity)
|
||||
self.freeWhenDone = freeWhenDone
|
||||
}
|
||||
|
||||
init() {
|
||||
self.data = nil
|
||||
self._size = 0
|
||||
self.capacity = 0
|
||||
self.freeWhenDone = true
|
||||
}
|
||||
|
||||
convenience init(data: Data?) {
|
||||
self.init()
|
||||
|
||||
if let data = data {
|
||||
data.withUnsafeBytes { bytes in
|
||||
self.appendBytes(bytes, length: UInt(data.count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeData() -> Data {
|
||||
return self.withUnsafeMutablePointer { pointer, size -> Data in
|
||||
if let pointer = pointer {
|
||||
return Data(bytes: pointer.assumingMemoryBound(to: UInt8.self), count: Int(size))
|
||||
} else {
|
||||
return Data()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
get {
|
||||
var string = ""
|
||||
if let data = self.data {
|
||||
var i: UInt = 0
|
||||
let bytes = data.assumingMemoryBound(to: UInt8.self)
|
||||
while i < _size && i < 8 {
|
||||
string += String(format: "%02x", Int(bytes.advanced(by: Int(i)).pointee))
|
||||
i += 1
|
||||
}
|
||||
if i < _size {
|
||||
string += "...\(_size)b"
|
||||
}
|
||||
} else {
|
||||
string += "<null>"
|
||||
}
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
||||
func appendBytes(_ bytes: UnsafeRawPointer, length: UInt) {
|
||||
if self.capacity < self._size + length {
|
||||
self.capacity = self._size + length + 128
|
||||
if self.data == nil {
|
||||
self.data = malloc(Int(self.capacity))!
|
||||
}
|
||||
else {
|
||||
self.data = realloc(self.data, Int(self.capacity))!
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(self.data?.advanced(by: Int(self._size)), bytes, Int(length))
|
||||
self._size += length
|
||||
}
|
||||
|
||||
func appendBuffer(_ buffer: Buffer) {
|
||||
if self.capacity < self._size + buffer._size {
|
||||
self.capacity = self._size + buffer._size + 128
|
||||
if self.data == nil {
|
||||
self.data = malloc(Int(self.capacity))!
|
||||
}
|
||||
else {
|
||||
self.data = realloc(self.data, Int(self.capacity))!
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(self.data?.advanced(by: Int(self._size)), buffer.data, Int(buffer._size))
|
||||
}
|
||||
|
||||
func appendInt32(_ value: Int32) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 4)
|
||||
}
|
||||
|
||||
func appendInt64(_ value: Int64) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 8)
|
||||
}
|
||||
|
||||
func appendDouble(_ value: Double) {
|
||||
var v = value
|
||||
self.appendBytes(&v, length: 8)
|
||||
}
|
||||
|
||||
func withUnsafeMutablePointer<R>(_ f: (UnsafeMutableRawPointer?, UInt) -> R) -> R {
|
||||
return f(self.data, self._size)
|
||||
}
|
||||
}
|
||||
|
||||
private class BufferReader {
|
||||
private let buffer: Buffer
|
||||
private(set) var offset: UInt = 0
|
||||
|
||||
init(_ buffer: Buffer) {
|
||||
self.buffer = buffer
|
||||
}
|
||||
|
||||
func reset() {
|
||||
self.offset = 0
|
||||
}
|
||||
|
||||
func skip(_ count: Int) {
|
||||
self.offset = min(self.buffer._size, self.offset + UInt(count))
|
||||
}
|
||||
|
||||
func readInt32() -> Int32? {
|
||||
if self.offset + 4 <= self.buffer._size {
|
||||
let value: Int32 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int32.self).pointee
|
||||
self.offset += 4
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readInt64() -> Int64? {
|
||||
if self.offset + 8 <= self.buffer._size {
|
||||
let value: Int64 = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Int64.self).pointee
|
||||
self.offset += 8
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readDouble() -> Double? {
|
||||
if self.offset + 8 <= self.buffer._size {
|
||||
let value: Double = buffer.data!.advanced(by: Int(self.offset)).assumingMemoryBound(to: Double.self).pointee
|
||||
self.offset += 8
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readBytesAsInt32(_ count: Int) -> Int32? {
|
||||
if count == 0 {
|
||||
return 0
|
||||
}
|
||||
else if count > 0 && count <= 4 || self.offset + UInt(count) <= self.buffer._size {
|
||||
var value: Int32 = 0
|
||||
memcpy(&value, self.buffer.data?.advanced(by: Int(self.offset)), count)
|
||||
self.offset += UInt(count)
|
||||
return value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readBuffer(_ count: Int) -> Buffer? {
|
||||
if count >= 0 && self.offset + UInt(count) <= self.buffer._size {
|
||||
let buffer = Buffer()
|
||||
buffer.appendBytes((self.buffer.data?.advanced(by: Int(self.offset)))!, length: UInt(count))
|
||||
self.offset += UInt(count)
|
||||
return buffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func serializeBytes(_ value: Buffer, buffer: Buffer, boxed: Bool) {
|
||||
if boxed {
|
||||
buffer.appendInt32(-1255641564)
|
||||
}
|
||||
|
||||
var length: Int32 = Int32(value.size)
|
||||
var padding: Int32 = 0
|
||||
if (length >= 254)
|
||||
{
|
||||
var tmp: UInt8 = 254
|
||||
buffer.appendBytes(&tmp, length: 1)
|
||||
buffer.appendBytes(&length, length: 3)
|
||||
padding = (((length % 4) == 0 ? length : (length + 4 - (length % 4)))) - length;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.appendBytes(&length, length: 1)
|
||||
|
||||
let e1 = (((length + 1) % 4) == 0 ? (length + 1) : ((length + 1) + 4 - ((length + 1) % 4)))
|
||||
padding = (e1) - (length + 1)
|
||||
}
|
||||
|
||||
if value.size != 0 {
|
||||
buffer.appendBytes(value.data!, length: UInt(length))
|
||||
}
|
||||
|
||||
var i: Int32 = 0
|
||||
var tmp: UInt8 = 0
|
||||
while i < padding {
|
||||
buffer.appendBytes(&tmp, length: 1)
|
||||
i += 1
|
||||
}
|
||||
}
|
||||
|
||||
private func roundUp(_ numToRound: Int, multiple: Int) -> Int {
|
||||
if multiple == 0 {
|
||||
return numToRound
|
||||
}
|
||||
|
||||
let remainder = numToRound % multiple
|
||||
if remainder == 0 {
|
||||
return numToRound
|
||||
}
|
||||
|
||||
return numToRound + multiple - remainder
|
||||
}
|
||||
|
||||
private func parseBytes(_ reader: BufferReader) -> Buffer? {
|
||||
if let tmp = reader.readBytesAsInt32(1) {
|
||||
var paddingBytes: Int = 0
|
||||
var length: Int = 0
|
||||
if tmp == 254 {
|
||||
if let len = reader.readBytesAsInt32(3) {
|
||||
length = Int(len)
|
||||
paddingBytes = roundUp(length, multiple: 4) - length
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
else {
|
||||
length = Int(tmp)
|
||||
paddingBytes = roundUp(length + 1, multiple: 4) - (length + 1)
|
||||
}
|
||||
|
||||
let buffer = reader.readBuffer(length)
|
||||
reader.skip(paddingBytes)
|
||||
return buffer
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private class Keychain: NSObject, MTKeychain {
|
||||
var dict: [String: Data] = [:]
|
||||
|
||||
func setObject(_ object: Any!, forKey aKey: String!, group: String!) {
|
||||
let data = NSKeyedArchiver.archivedData(withRootObject: object)
|
||||
self.dict[group + ":" + aKey] = data
|
||||
}
|
||||
|
||||
func object(forKey aKey: String!, group: String!) -> Any! {
|
||||
if let data = self.dict[group + ":" + aKey] {
|
||||
return NSKeyedUnarchiver.unarchiveObject(with: data as Data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeObject(forKey aKey: String!, group: String!) {
|
||||
self.dict.removeValue(forKey: group + ":" + aKey)
|
||||
}
|
||||
|
||||
func dropGroup(_ group: String!) {
|
||||
}
|
||||
}
|
||||
|
||||
private final class ParsedFile: NSObject {
|
||||
let data: Data?
|
||||
|
||||
init(data: Data?) {
|
||||
self.data = data
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
func fetchImageWithAccount(account: AccountData, resource: ImageResource, completion: @escaping (Data?) -> Void) -> () -> Void {
|
||||
MTLogSetEnabled(true)
|
||||
MTLogSetLoggingFunction({ str, args in
|
||||
//let string = NSString(format: str! as NSString, args!)
|
||||
print("MT: \(str!)")
|
||||
})
|
||||
|
||||
let serialization = Serialization()
|
||||
|
||||
var apiEnvironment = MTApiEnvironment()
|
||||
|
||||
apiEnvironment.apiId = BuildConfig.shared().apiId
|
||||
apiEnvironment.langPack = "ios"
|
||||
apiEnvironment.layer = NSNumber(value: Int(serialization.currentLayer()))
|
||||
apiEnvironment.disableUpdates = true
|
||||
apiEnvironment = apiEnvironment.withUpdatedLangPackCode("en")
|
||||
|
||||
let context = MTContext(serialization: serialization, apiEnvironment: apiEnvironment, isTestingEnvironment: account.isTestingEnvironment, useTempAuthKeys: false)!
|
||||
|
||||
let seedAddressList: [Int: [String]]
|
||||
|
||||
if account.isTestingEnvironment {
|
||||
seedAddressList = [
|
||||
1: ["149.154.175.10"],
|
||||
2: ["149.154.167.40"]
|
||||
]
|
||||
} else {
|
||||
seedAddressList = [
|
||||
1: ["149.154.175.50", "2001:b28:f23d:f001::a"],
|
||||
2: ["149.154.167.50", "2001:67c:4e8:f002::a"],
|
||||
3: ["149.154.175.100", "2001:b28:f23d:f003::a"],
|
||||
4: ["149.154.167.91", "2001:67c:4e8:f004::a"],
|
||||
5: ["149.154.171.5", "2001:b28:f23f:f005::a"]
|
||||
]
|
||||
}
|
||||
|
||||
for (id, ips) in seedAddressList {
|
||||
context.setSeedAddressSetForDatacenterWithId(id, seedAddressSet: MTDatacenterAddressSet(addressList: ips.map { MTDatacenterAddress(ip: $0, port: 443, preferForMedia: false, restrictToTcp: false, cdn: false, preferForProxy: false, secret: nil) }))
|
||||
}
|
||||
|
||||
let keychain = Keychain()
|
||||
context.keychain = keychain
|
||||
|
||||
for (id, info) in account.datacenters {
|
||||
context.updateAuthInfoForDatacenter(withId: Int(id), authInfo: MTDatacenterAuthInfo(authKey: info.masterKey.data, authKeyId: info.masterKey.id, saltSet: [], authKeyAttributes: [:], mainTempAuthKey: nil, mediaTempAuthKey: nil))
|
||||
}
|
||||
|
||||
let mtProto = MTProto(context: context, datacenterId: resource.datacenterId, usageCalculationInfo: nil)!
|
||||
mtProto.useTempAuthKeys = context.useTempAuthKeys
|
||||
mtProto.checkForProxyConnectionIssues = false
|
||||
|
||||
let requestService = MTRequestMessageService(context: context)!
|
||||
mtProto.add(requestService)
|
||||
|
||||
let request = MTRequest()
|
||||
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-475607115) //upload.getFile
|
||||
|
||||
buffer.appendInt32(-539317279) //InputFileLocation.inputFileLocation
|
||||
buffer.appendInt64(resource.volumeId)
|
||||
buffer.appendInt32(resource.localId)
|
||||
buffer.appendInt64(resource.secret)
|
||||
|
||||
serializeBytes(Buffer(data: resource.fileReference), buffer: buffer, boxed: false)
|
||||
|
||||
buffer.appendInt32(0)
|
||||
buffer.appendInt32(32 * 1024)
|
||||
|
||||
request.setPayload(buffer.makeData(), metadata: "getFile", responseParser: { response in
|
||||
let reader = BufferReader(Buffer(data: response))
|
||||
guard let signature = reader.readInt32() else {
|
||||
return ParsedFile(data: nil)
|
||||
}
|
||||
guard signature == 157948117 else {
|
||||
return ParsedFile(data: nil)
|
||||
}
|
||||
reader.skip(4) //type
|
||||
reader.skip(4) //mtime
|
||||
guard let bytes = parseBytes(reader) else {
|
||||
return ParsedFile(data: nil)
|
||||
}
|
||||
return ParsedFile(data: bytes.makeData())
|
||||
})
|
||||
|
||||
request.dependsOnPasswordEntry = false
|
||||
request.shouldContinueExecutionWithErrorContext = { errorContext in
|
||||
guard let _ = errorContext else {
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
request.completed = { (boxedResponse, timestamp, error) -> () in
|
||||
if let _ = error {
|
||||
completion(nil)
|
||||
} else {
|
||||
if let result = boxedResponse as? ParsedFile {
|
||||
completion(result.data)
|
||||
} else {
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
requestService.add(request)
|
||||
mtProto.resume()
|
||||
|
||||
let internalId = request.internalId
|
||||
return {
|
||||
requestService.removeRequest(byInternalId: internalId)
|
||||
context.performBatchUpdates({})
|
||||
mtProto.stop()
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,9 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>XPC!</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>5.2</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>${BUILD_NUMBER}</string>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef NotificationService_BridgingHeader_h
|
||||
#define NotificationService_BridgingHeader_h
|
||||
|
||||
#import "../Telegram-iOS/BuildConfig.h"
|
||||
#import "Crypto.h"
|
||||
|
||||
#endif
|
||||
|
|
@ -1,26 +1,280 @@
|
|||
import Foundation
|
||||
import UserNotifications
|
||||
|
||||
private func dataWithHexString(_ string: String) -> Data {
|
||||
var hex = string
|
||||
if hex.count % 2 != 0 {
|
||||
return Data()
|
||||
}
|
||||
var data = Data()
|
||||
while hex.count > 0 {
|
||||
let subIndex = hex.index(hex.startIndex, offsetBy: 2)
|
||||
let c = String(hex[..<subIndex])
|
||||
hex = String(hex[subIndex...])
|
||||
var ch: UInt32 = 0
|
||||
if !Scanner(string: c).scanHexInt32(&ch) {
|
||||
return Data()
|
||||
}
|
||||
var char = UInt8(ch)
|
||||
data.append(&char, count: 1)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
private func parseInt64(_ value: Any?) -> Int64? {
|
||||
if let value = value as? String {
|
||||
return Int64(value)
|
||||
} else if let value = value as? Int64 {
|
||||
return value
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func parseInt32(_ value: Any?) -> Int32? {
|
||||
if let value = value as? String {
|
||||
return Int32(value)
|
||||
} else if let value = value as? Int32 {
|
||||
return value
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
private func parseImageLocation(_ dict: [AnyHashable: Any]) -> (size: (width: Int32, height: Int32)?, resource: ImageResource)? {
|
||||
guard let datacenterId = parseInt32(dict["dc_id"]) else {
|
||||
return nil
|
||||
}
|
||||
guard let volumeId = parseInt64(dict["volume_id"]) else {
|
||||
return nil
|
||||
}
|
||||
guard let localId = parseInt32(dict["local_id"]) else {
|
||||
return nil
|
||||
}
|
||||
guard let secret = parseInt64(dict["secret"]) else {
|
||||
return nil
|
||||
}
|
||||
var fileReference: Data?
|
||||
if let fileReferenceString = dict["file_reference"] as? String {
|
||||
fileReference = Data(base64Encoded: fileReferenceString)
|
||||
}
|
||||
var size: (Int32, Int32)?
|
||||
if let width = parseInt32(dict["w"]), let height = parseInt32(dict["h"]) {
|
||||
size = (width, height)
|
||||
}
|
||||
return (size, ImageResource(datacenterId: Int(datacenterId), volumeId: volumeId, localId: localId, secret: secret, fileReference: fileReference))
|
||||
}
|
||||
|
||||
private func hexString(_ data: Data) -> String {
|
||||
let hexString = NSMutableString()
|
||||
data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Void in
|
||||
for i in 0 ..< data.count {
|
||||
hexString.appendFormat("%02x", UInt(bytes.advanced(by: i).pointee))
|
||||
}
|
||||
}
|
||||
|
||||
return hexString as String
|
||||
}
|
||||
|
||||
private func serializeImageLocation(_ resource: ImageResource) -> [AnyHashable: Any] {
|
||||
var result: [AnyHashable: Any] = [:]
|
||||
result["datacenterId"] = Int32(resource.datacenterId)
|
||||
result["volumeId"] = resource.volumeId
|
||||
result["localId"] = resource.localId
|
||||
result["secret"] = resource.secret
|
||||
if let fileReference = resource.fileReference {
|
||||
result["fileReference"] = hexString(fileReference)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class NotificationService: UNNotificationServiceExtension {
|
||||
private let rootPath: String?
|
||||
|
||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||
var bestAttemptContent: UNMutableNotificationContent?
|
||||
|
||||
var cancelFetch: (() -> Void)?
|
||||
|
||||
override init() {
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
if let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) {
|
||||
let appGroupName = "group.\(appBundleIdentifier[..<lastDotRange.lowerBound])"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
if let appGroupUrl = maybeAppGroupUrl {
|
||||
self.rootPath = appGroupUrl.path + "/telegram-data"
|
||||
} else {
|
||||
self.rootPath = nil
|
||||
}
|
||||
} else {
|
||||
self.rootPath = nil
|
||||
}
|
||||
|
||||
super.init()
|
||||
}
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
let accountsData = self.rootPath.flatMap({ rootPath in
|
||||
loadAccountsData(rootPath: rootPath)
|
||||
}) ?? [:]
|
||||
|
||||
self.contentHandler = contentHandler
|
||||
self.bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
|
||||
|
||||
if let bestAttemptContent = self.bestAttemptContent {
|
||||
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
|
||||
contentHandler(bestAttemptContent)
|
||||
var encryptedData: Data?
|
||||
if var encryptedPayload = request.content.userInfo["p"] as? String {
|
||||
encryptedPayload = encryptedPayload.replacingOccurrences(of: "-", with: "+")
|
||||
encryptedPayload = encryptedPayload.replacingOccurrences(of: "_", with: "/")
|
||||
while encryptedPayload.count % 4 != 0 {
|
||||
encryptedPayload.append("=")
|
||||
}
|
||||
encryptedData = Data(base64Encoded: encryptedPayload)
|
||||
}
|
||||
|
||||
if let (account, dict) = encryptedData.flatMap({ decryptedNotificationPayload(accounts: accountsData, data: $0) }) {
|
||||
var userInfo = self.bestAttemptContent?.userInfo ?? [:]
|
||||
userInfo["accountId"] = account.id
|
||||
|
||||
var peerId: PeerId?
|
||||
var messageId: Int32?
|
||||
|
||||
if let msgId = dict["msg_id"] as? String {
|
||||
userInfo["msg_id"] = msgId
|
||||
messageId = Int32(msgId)
|
||||
}
|
||||
if let fromId = dict["from_id"] as? String {
|
||||
userInfo["from_id"] = fromId
|
||||
if let id = Int32(fromId) {
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
|
||||
}
|
||||
}
|
||||
if let chatId = dict["chat_id"] as? String {
|
||||
userInfo["chat_id"] = chatId
|
||||
if let id = Int32(chatId) {
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: id)
|
||||
}
|
||||
}
|
||||
if let channelId = dict["channel_id"] as? String {
|
||||
userInfo["channel_id"] = channelId
|
||||
if let id = Int32(channelId) {
|
||||
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)
|
||||
}
|
||||
}
|
||||
|
||||
var thumbnailImage: ImageResource?
|
||||
var fullSizeImage: (size: (width: Int32, height: Int32)?, resource: ImageResource)?
|
||||
if let thumbLoc = dict["media_loc"] as? [AnyHashable: Any] {
|
||||
thumbnailImage = (thumbLoc["thumb"] as? [AnyHashable: Any]).flatMap(parseImageLocation)?.resource
|
||||
fullSizeImage = (thumbLoc["full"] as? [AnyHashable: Any]).flatMap(parseImageLocation)
|
||||
}
|
||||
|
||||
let imagesPath = NSTemporaryDirectory() + "aps-data"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: imagesPath, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
let mediaBoxPath = account.basePath + "/postbox/media"
|
||||
|
||||
let tempImagePath = thumbnailImage.flatMap({ imagesPath + "/\($0.resourceId).jpg" })
|
||||
let mediaBoxThumbnailImagePath = thumbnailImage.flatMap({ mediaBoxPath + "/\($0.resourceId)" })
|
||||
let mediaBoxFullSizeImagePath = fullSizeImage.flatMap({ mediaBoxPath + "/\($0.resource.resourceId)" })
|
||||
|
||||
if let aps = dict["aps"] as? [AnyHashable: Any] {
|
||||
if let alert = aps["alert"] as? String {
|
||||
self.bestAttemptContent?.title = ""
|
||||
self.bestAttemptContent?.body = alert
|
||||
} else if let alert = aps["alert"] as? [AnyHashable: Any] {
|
||||
self.bestAttemptContent?.title = alert["title"] as? String ?? ""
|
||||
self.bestAttemptContent?.subtitle = alert["subtitle"] as? String ?? ""
|
||||
self.bestAttemptContent?.body = alert["body"] as? String ?? ""
|
||||
}
|
||||
|
||||
if let threadId = aps["thread-id"] as? String {
|
||||
self.bestAttemptContent?.threadIdentifier = threadId
|
||||
}
|
||||
if let sound = aps["sound"] as? String {
|
||||
self.bestAttemptContent?.sound = UNNotificationSound(named: UNNotificationSoundName(sound))
|
||||
}
|
||||
if let category = aps["category"] as? String {
|
||||
self.bestAttemptContent?.categoryIdentifier = category
|
||||
if let peerId = peerId, let messageId = messageId, let thumbnailResource = thumbnailImage, let (maybeSize, resource) = fullSizeImage, let size = maybeSize {
|
||||
userInfo["peerId"] = peerId.toInt64()
|
||||
userInfo["messageId.namespace"] = 0 as Int32
|
||||
userInfo["messageId.id"] = messageId
|
||||
|
||||
var imageInfo: [String: Any] = [:]
|
||||
imageInfo["width"] = Int(size.width)
|
||||
imageInfo["height"] = Int(size.height)
|
||||
|
||||
var thumbnail: [String: Any] = [:]
|
||||
if let mediaBoxThumbnailImagePath = mediaBoxThumbnailImagePath {
|
||||
thumbnail["path"] = mediaBoxThumbnailImagePath
|
||||
}
|
||||
thumbnail["fileLocation"] = serializeImageLocation(thumbnailResource)
|
||||
|
||||
var fullSize: [String: Any] = [:]
|
||||
if let mediaBoxFullSizeImagePath = mediaBoxFullSizeImagePath {
|
||||
fullSize["path"] = mediaBoxFullSizeImagePath
|
||||
}
|
||||
fullSize["fileLocation"] = serializeImageLocation(resource)
|
||||
|
||||
imageInfo["thumbnail"] = thumbnail
|
||||
imageInfo["fullSize"] = fullSize
|
||||
|
||||
userInfo["mediaInfo"] = ["image": imageInfo]
|
||||
|
||||
if category == "r" {
|
||||
self.bestAttemptContent?.categoryIdentifier = "withReplyMedia"
|
||||
} else if category == "m" {
|
||||
self.bestAttemptContent?.categoryIdentifier = "withMuteMedia"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.bestAttemptContent?.userInfo = userInfo
|
||||
|
||||
self.cancelFetch?()
|
||||
if let mediaBoxThumbnailImagePath = mediaBoxThumbnailImagePath, let tempImagePath = tempImagePath, let thumbnailImage = thumbnailImage {
|
||||
self.cancelFetch = fetchImageWithAccount(account: account, resource: thumbnailImage, completion: { [weak self] data in
|
||||
DispatchQueue.main.async {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.cancelFetch?()
|
||||
strongSelf.cancelFetch = nil
|
||||
if let data = data {
|
||||
let _ = try? data.write(to: URL(fileURLWithPath: mediaBoxThumbnailImagePath))
|
||||
if let _ = try? data.write(to: URL(fileURLWithPath: tempImagePath)) {
|
||||
if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempImagePath)) {
|
||||
strongSelf.bestAttemptContent?.attachments = [attachment]
|
||||
}
|
||||
}
|
||||
}
|
||||
if let bestAttemptContent = strongSelf.bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if let bestAttemptContent = self.bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if let bestAttemptContent = self.bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func serviceExtensionTimeWillExpire() {
|
||||
if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
|
||||
self.cancelFetch?()
|
||||
self.cancelFetch = nil
|
||||
|
||||
if let contentHandler = self.contentHandler, let bestAttemptContent = self.bestAttemptContent {
|
||||
contentHandler(bestAttemptContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
42
NotificationService/Serialization.swift
Normal file
42
NotificationService/Serialization.swift
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import Foundation
|
||||
import MtProtoKitDynamic
|
||||
|
||||
public class BoxedMessage: NSObject {
|
||||
public let body: Any
|
||||
public init(_ body: Any) {
|
||||
self.body = body
|
||||
}
|
||||
}
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 93
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
return nil
|
||||
}
|
||||
|
||||
public func exportAuthorization(_ datacenterId: Int32, data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTExportAuthorizationResponseParser!
|
||||
{
|
||||
return { data -> MTExportedAuthorizationData? in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func importAuthorization(_ authId: Int32, bytes: Data!) -> Data! {
|
||||
return Data()
|
||||
}
|
||||
|
||||
public func requestDatacenterAddress(with data: AutoreleasingUnsafeMutablePointer<NSData?>) -> MTRequestDatacenterAddressListParser! {
|
||||
return { response -> MTDatacenterAddressListData? in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func requestNoop(_ data: AutoreleasingUnsafeMutablePointer<NSData?>!) -> MTRequestNoopParser! {
|
||||
return { response -> AnyObject? in
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -143,14 +143,11 @@ class ShareRootController: UIViewController {
|
|||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
initializeAccountManagement()
|
||||
account = accountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|> take(1)
|
||||
|> mapToSignal { accountManager -> Signal<(SharedAccountContext, LoggingSettings), NoError> in
|
||||
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), rootPath: rootPath, apsNotificationToken: .never(), voipNotificationToken: .never())
|
||||
|
||||
return accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
|
||||
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
|
||||
}
|
||||
account = accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
|
||||
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
|
||||
}
|
||||
|> introduceError(ShareAuthorizationError.self)
|
||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContext, Account), ShareAuthorizationError> in
|
||||
|
|
@ -181,19 +178,18 @@ class ShareRootController: UIViewController {
|
|||
|> take(1)
|
||||
}
|
||||
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([ApplicationSpecificPreferencesKeys.presentationPasscodeSettings]))
|
||||
|
||||
let shouldBeMaster = self.shouldBeMaster
|
||||
let applicationInterface = account
|
||||
|> mapToSignal { sharedContext, account -> Signal<(AccountContext, PostboxAccessChallengeData), ShareAuthorizationError> in
|
||||
return combineLatest(currentPresentationDataAndSettings(postbox: account.postbox), account.postbox.combinedView(keys: [.accessChallengeData, preferencesKey]) |> take(1))
|
||||
return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox), sharedContext.accountManager.accessChallengeData())
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
|> introduceError(ShareAuthorizationError.self)
|
||||
|> map { dataAndSettings, data -> (AccountContext, PostboxAccessChallengeData) in
|
||||
|> map { sharedData, dataAndSettings, data -> (AccountContext, PostboxAccessChallengeData) in
|
||||
accountCache = (sharedContext, account)
|
||||
updateLegacyLocalization(strings: dataAndSettings.presentationData.strings)
|
||||
let context = AccountContext(sharedContext: sharedContext, account: account, initialPresentationDataAndSettings: dataAndSettings)
|
||||
return (context, (data.views[.accessChallengeData] as! AccessChallengeDataView).data)
|
||||
return (context, data.data)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|
|
|
|||
|
|
@ -82,32 +82,30 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
|||
account = .single(accountCache)
|
||||
} else {
|
||||
initializeAccountManagement()
|
||||
account = accountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|> take(1)
|
||||
|> mapToSignal { accountManager -> Signal<Account, NoError> in
|
||||
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods)
|
||||
|> mapToSignal { account -> Signal<Account, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
return applicationSettings(accountManager: accountManager)
|
||||
|> deliverOnMainQueue
|
||||
|> map { settings -> Account in
|
||||
accountCache = account
|
||||
Logger.shared.logToFile = settings.logging.logToFile
|
||||
Logger.shared.logToConsole = settings.logging.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
|
||||
return account
|
||||
}
|
||||
case .unauthorized:
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|
||||
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods)
|
||||
|> mapToSignal { account -> Signal<Account, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
return applicationSettings(accountManager: accountManager)
|
||||
|> deliverOnMainQueue
|
||||
|> map { settings -> Account in
|
||||
accountCache = account
|
||||
Logger.shared.logToFile = settings.logging.logToFile
|
||||
Logger.shared.logToConsole = settings.logging.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
|
||||
return account
|
||||
}
|
||||
case .unauthorized:
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@
|
|||
09D304382174344900C00567 /* TGBridgeWebPageMediaAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 09C572F52172953500BDF00F /* TGBridgeWebPageMediaAttachment.m */; };
|
||||
09D304392174344900C00567 /* TGBridgeMessageEntities.m in Sources */ = {isa = PBXBuildFile; fileRef = 09C572F42172953500BDF00F /* TGBridgeMessageEntities.m */; };
|
||||
09FDAEE62140477F00BF856F /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09FDAEE52140477F00BF856F /* MtProtoKitDynamic.framework */; };
|
||||
D000CACB21FB6E380011B15D /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D000CACA21FB6E380011B15D /* NotificationService.swift */; };
|
||||
D000CACF21FB6E380011B15D /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D000CAC821FB6E370011B15D /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
D001D5AA1F878DA300DF975A /* PhoneCountries.txt in Resources */ = {isa = PBXBuildFile; fileRef = D001D5A91F878DA300DF975A /* PhoneCountries.txt */; };
|
||||
D006CF9F21A8D11B00FDCD32 /* ModernProto.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D006CF9E21A8D11B00FDCD32 /* ModernProto.framework */; };
|
||||
|
|
@ -300,6 +299,8 @@
|
|||
D06706611D51185400DED3E3 /* TelegramCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D06706601D51185400DED3E3 /* TelegramCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
D06706621D5118F500DED3E3 /* TelegramCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06706601D51185400DED3E3 /* TelegramCore.framework */; };
|
||||
D06E4C2F21347D9200088087 /* UIImage+ImageEffects.m in Sources */ = {isa = PBXBuildFile; fileRef = D06E4C2E21347D9200088087 /* UIImage+ImageEffects.m */; };
|
||||
D073E52021FF7CE900742DDD /* Crypto.m in Sources */ = {isa = PBXBuildFile; fileRef = D073E51F21FF7CE900742DDD /* Crypto.m */; };
|
||||
D073E52222003E1E00742DDD /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073E52122003E1E00742DDD /* Data.swift */; };
|
||||
D084023220E1883500065674 /* ApplicationShortcutItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D084023120E1883500065674 /* ApplicationShortcutItem.swift */; };
|
||||
D08410451FABDC5D008FFE92 /* TGItemProviderSignals.m in Sources */ = {isa = PBXBuildFile; fileRef = D08410441FABDC5C008FFE92 /* TGItemProviderSignals.m */; };
|
||||
D08410481FABDCF2008FFE92 /* LegacyComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D08410491FABDCF2008FFE92 /* LegacyComponents.framework */; };
|
||||
|
|
@ -419,6 +420,12 @@
|
|||
D0ECCB7F1FE9C38500609802 /* Telegram_iOS_UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB7E1FE9C38500609802 /* Telegram_iOS_UITests.swift */; };
|
||||
D0ECCB8A1FE9C4AC00609802 /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB891FE9C4AC00609802 /* SnapshotHelper.swift */; };
|
||||
D0ECCB8D1FE9CE3F00609802 /* SnapshotChatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ECCB8C1FE9CE3F00609802 /* SnapshotChatList.swift */; };
|
||||
D0ED633821FF3E1E001D4648 /* MtProtoKitDynamic.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0CAF2F21D75FFAB0011F558 /* MtProtoKitDynamic.framework */; };
|
||||
D0ED633A21FF3EDF001D4648 /* AccountData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED633921FF3EDF001D4648 /* AccountData.swift */; };
|
||||
D0ED633B21FF3EFD001D4648 /* BuildConfig.m in Sources */ = {isa = PBXBuildFile; fileRef = D09250011FE52D2A003F693F /* BuildConfig.m */; };
|
||||
D0ED633D21FF4580001D4648 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0400EE41D5B912E007931CE /* NotificationService.swift */; };
|
||||
D0ED633F21FF46E4001D4648 /* ImageData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED633E21FF46E4001D4648 /* ImageData.swift */; };
|
||||
D0ED634121FF4786001D4648 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0ED634021FF4786001D4648 /* Serialization.swift */; };
|
||||
D0F575132083B96B00F1C1E1 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0F575122083B96B00F1C1E1 /* CloudKit.framework */; };
|
||||
D0FC1948201D2DA800FEDBB2 /* SFCompactRounded-Semibold.otf in Resources */ = {isa = PBXBuildFile; fileRef = D0FC1947201D2DA700FEDBB2 /* SFCompactRounded-Semibold.otf */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
|
@ -899,8 +906,6 @@
|
|||
D000CAC221FB6E170011B15D /* NotificationService-AppStore.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NotificationService-AppStore.entitlements"; sourceTree = "<group>"; };
|
||||
D000CAC321FB6E170011B15D /* NotificationService-AppStoreLLC.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "NotificationService-AppStoreLLC.entitlements"; sourceTree = "<group>"; };
|
||||
D000CAC821FB6E370011B15D /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D000CACA21FB6E380011B15D /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||
D000CACC21FB6E380011B15D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D001D5A91F878DA300DF975A /* PhoneCountries.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PhoneCountries.txt; path = "Telegram-iOS/Resources/PhoneCountries.txt"; sourceTree = "<group>"; };
|
||||
D006CF9E21A8D11B00FDCD32 /* ModernProto.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ModernProto.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D006CFA121A8D12600FDCD32 /* ModernProto.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ModernProto.framework; path = "../../../Library/Developer/Xcode/DerivedData/Telegram-iOS-ffbqcdyqpehxdvcwhyaorlehrrdc/Build/Products/Debug Hockeyapp-iphoneos/ModernProto.framework"; sourceTree = "<group>"; };
|
||||
|
|
@ -1031,6 +1036,9 @@
|
|||
D06706601D51185400DED3E3 /* TelegramCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = TelegramCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D06E4C2D21347D9200088087 /* UIImage+ImageEffects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+ImageEffects.h"; sourceTree = "<group>"; };
|
||||
D06E4C2E21347D9200088087 /* UIImage+ImageEffects.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+ImageEffects.m"; sourceTree = "<group>"; };
|
||||
D073E51E21FF7CE900742DDD /* Crypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Crypto.h; sourceTree = "<group>"; };
|
||||
D073E51F21FF7CE900742DDD /* Crypto.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Crypto.m; sourceTree = "<group>"; };
|
||||
D073E52122003E1E00742DDD /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
|
||||
D079FD001F06BBD10038FADE /* Telegram-iOS-AppStore.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "Telegram-iOS-AppStore.entitlements"; sourceTree = "<group>"; };
|
||||
D079FD011F06BBD60038FADE /* Config-Hockeyapp.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Config-Hockeyapp.xcconfig"; sourceTree = "<group>"; };
|
||||
D079FD021F06BBD60038FADE /* Config-AppStore.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Config-AppStore.xcconfig"; sourceTree = "<group>"; };
|
||||
|
|
@ -1166,6 +1174,10 @@
|
|||
D0ECCB801FE9C38500609802 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D0ECCB891FE9C4AC00609802 /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; };
|
||||
D0ECCB8C1FE9CE3F00609802 /* SnapshotChatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnapshotChatList.swift; sourceTree = "<group>"; };
|
||||
D0ED633921FF3EDF001D4648 /* AccountData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountData.swift; sourceTree = "<group>"; };
|
||||
D0ED633C21FF3F28001D4648 /* NotificationService-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NotificationService-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
D0ED633E21FF46E4001D4648 /* ImageData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageData.swift; sourceTree = "<group>"; };
|
||||
D0ED634021FF4786001D4648 /* Serialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = "<group>"; };
|
||||
D0F575122083B96B00F1C1E1 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
|
||||
D0FC1947201D2DA700FEDBB2 /* SFCompactRounded-Semibold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "SFCompactRounded-Semibold.otf"; path = "Telegram-iOS/Resources/SFCompactRounded-Semibold.otf"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
|
@ -1185,6 +1197,7 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0ED633821FF3E1E001D4648 /* MtProtoKitDynamic.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -1899,15 +1912,6 @@
|
|||
name = Media;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D000CAC921FB6E380011B15D /* NotificationService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D000CACA21FB6E380011B15D /* NotificationService.swift */,
|
||||
D000CACC21FB6E380011B15D /* Info.plist */,
|
||||
);
|
||||
path = NotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D00859931B28189D00EAF753 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -1919,7 +1923,6 @@
|
|||
D0D268821D79A70A00C422DA /* SiriIntentsUI */,
|
||||
D02CF5FF215D9ABF00E0F56A /* NotificationContent */,
|
||||
09C56F8C2172797200BDF00F /* Watch */,
|
||||
D000CAC921FB6E380011B15D /* NotificationService */,
|
||||
D00859C21B281E0000EAF753 /* Frameworks */,
|
||||
D008599E1B28189D00EAF753 /* Telegram-iOS */,
|
||||
D0400EE31D5B912E007931CE /* NotificationService */,
|
||||
|
|
@ -2151,7 +2154,14 @@
|
|||
D000CAC121FB6E160011B15D /* NotificationService-Fork.entitlements */,
|
||||
D000CAC021FB6E160011B15D /* NotificationService-HockeyApp.entitlements */,
|
||||
D0400EE41D5B912E007931CE /* NotificationService.swift */,
|
||||
D0ED633921FF3EDF001D4648 /* AccountData.swift */,
|
||||
D0ED633E21FF46E4001D4648 /* ImageData.swift */,
|
||||
D0400EE61D5B912E007931CE /* Info.plist */,
|
||||
D0ED633C21FF3F28001D4648 /* NotificationService-Bridging-Header.h */,
|
||||
D0ED634021FF4786001D4648 /* Serialization.swift */,
|
||||
D073E51E21FF7CE900742DDD /* Crypto.h */,
|
||||
D073E51F21FF7CE900742DDD /* Crypto.m */,
|
||||
D073E52122003E1E00742DDD /* Data.swift */,
|
||||
);
|
||||
path = NotificationService;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -3172,7 +3182,13 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D000CACB21FB6E380011B15D /* NotificationService.swift in Sources */,
|
||||
D073E52222003E1E00742DDD /* Data.swift in Sources */,
|
||||
D0ED633B21FF3EFD001D4648 /* BuildConfig.m in Sources */,
|
||||
D0ED633D21FF4580001D4648 /* NotificationService.swift in Sources */,
|
||||
D0ED633A21FF3EDF001D4648 /* AccountData.swift in Sources */,
|
||||
D0ED634121FF4786001D4648 /* Serialization.swift in Sources */,
|
||||
D073E52021FF7CE900742DDD /* Crypto.m in Sources */,
|
||||
D0ED633F21FF46E4001D4648 /* ImageData.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -4702,6 +4718,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -4765,6 +4782,7 @@
|
|||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -4775,6 +4793,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -4838,6 +4857,7 @@
|
|||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -4848,6 +4868,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -4911,6 +4932,7 @@
|
|||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -4921,6 +4943,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -4984,6 +5007,7 @@
|
|||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -4994,6 +5018,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -5049,6 +5074,7 @@
|
|||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore org.telegram.TelegramHD.NotificationService";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -5060,6 +5086,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -5115,6 +5142,7 @@
|
|||
PROVISIONING_PROFILE_SPECIFIER = "match AppStore ph.telegra.Telegraph.NotificationService";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -5126,6 +5154,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -5181,6 +5210,7 @@
|
|||
PROVISIONING_PROFILE_SPECIFIER = "match InHouse org.telegram.Telegram-iOS.NotificationService";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
@ -5192,6 +5222,7 @@
|
|||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
BUILD_NUMBER = 99999;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
|
|
@ -5247,6 +5278,7 @@
|
|||
PROVISIONING_PROFILE_SPECIFIER = "match InHouse org.telegram.Telegram-iOS.NotificationService";
|
||||
SDKROOT = iphoneos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "NotificationService/NotificationService-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.2;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug Hockeyapp"
|
||||
buildConfiguration = "DebugHockeyapp"
|
||||
selectedDebuggerIdentifier = ""
|
||||
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
|
||||
launchStyle = "0"
|
||||
|
|
@ -68,9 +68,9 @@
|
|||
allowLocationSimulation = "YES"
|
||||
launchAutomaticallySubstyle = "2">
|
||||
<RemoteRunnable
|
||||
runnableDebuggingMode = "0"
|
||||
BundleIdentifier = "org.telegram.Telegram-iOS"
|
||||
RemotePath = "/var/containers/Bundle/Application/40124EF3-F9E6-4274-8750-77DC100D9950/Telegram X.app">
|
||||
runnableDebuggingMode = "1"
|
||||
BundleIdentifier = "com.apple.mobilesafari"
|
||||
RemotePath = "/Applications/MobileSafari.app">
|
||||
</RemoteRunnable>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
|
|
|
|||
|
|
@ -583,13 +583,12 @@ private enum QueuedWakeup: Int32 {
|
|||
self.window?.rootViewController?.dismiss(animated: true, completion: nil)
|
||||
})
|
||||
|
||||
self.sharedContextPromise.set(accountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { accountManager -> Signal<(SharedAccountContext, LoggingSettings), NoError> in
|
||||
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: networkArguments, rootPath: rootPath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init))
|
||||
return accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
|
||||
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
|
||||
}
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
let sharedContext = SharedAccountContext(accountManager: accountManager, applicationBindings: applicationBindings, networkArguments: networkArguments, rootPath: rootPath, apsNotificationToken: self.notificationTokenPromise.get() |> map(Optional.init), voipNotificationToken: self.voipTokenPromise.get() |> map(Optional.init))
|
||||
|
||||
self.sharedContextPromise.set(
|
||||
accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
|
||||
return (sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
|
||||
}
|
||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<SharedAccountContext, NoError> in
|
||||
Logger.shared.logToFile = loggingSettings.logToFile
|
||||
|
|
@ -686,12 +685,12 @@ private enum QueuedWakeup: Int32 {
|
|||
})
|
||||
|> mapToSignal { account, hasOther -> Signal<(AnyObject, InitialPresentationDataAndSettings, Bool)?, NoError> in
|
||||
if let account = account as? Account {
|
||||
return currentPresentationDataAndSettings(postbox: account.postbox)
|
||||
return currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox)
|
||||
|> map { initialSettings in
|
||||
return (account, initialSettings, hasOther)
|
||||
}
|
||||
} else if let account = account as? UnauthorizedAccount {
|
||||
return currentPresentationDataAndSettings(postbox: account.postbox)
|
||||
return currentPresentationDataAndSettings(accountManager: sharedContext.accountManager, postbox: account.postbox)
|
||||
|> map { initialSettings in
|
||||
return (account, initialSettings, hasOther)
|
||||
}
|
||||
|
|
@ -1314,14 +1313,6 @@ private enum QueuedWakeup: Int32 {
|
|||
private func openUrl(url: URL) {
|
||||
let _ = (self.context.get()
|
||||
|> flatMap { $0 }
|
||||
|> filter { context in
|
||||
switch context {
|
||||
case .authorized, .unauthorized:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { contextValue in
|
||||
switch contextValue {
|
||||
|
|
@ -1331,7 +1322,7 @@ private enum QueuedWakeup: Int32 {
|
|||
if let proxyData = parseProxyUrl(url) {
|
||||
context.rootController.view.endEditing(true)
|
||||
let strings = context.strings
|
||||
let controller = ProxyServerActionSheetController(theme: defaultPresentationTheme, strings: strings, postbox: context.account.postbox, network: context.account.network, server: proxyData, presentationData: nil)
|
||||
let controller = ProxyServerActionSheetController(theme: defaultPresentationTheme, strings: strings, accountManager: context.sharedContext.accountManager, postbox: context.account.postbox, network: context.account.network, server: proxyData, presentationData: nil)
|
||||
context.rootController.currentWindow?.present(controller, on: PresentationSurfaceLevel.root, blockInteraction: false, completion: {})
|
||||
} else if let secureIdData = parseSecureIdUrl(url) {
|
||||
let strings = context.strings
|
||||
|
|
@ -1401,16 +1392,30 @@ private enum QueuedWakeup: Int32 {
|
|||
case .camera:
|
||||
context.openRootCamera()
|
||||
case .savedMessages:
|
||||
self.openChatWhenReady(peerId: context.context.account.peerId)
|
||||
self.openChatWhenReady(accountId: nil, peerId: context.context.account.peerId)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func openChatWhenReady(peerId: PeerId, messageId: MessageId? = nil) {
|
||||
self.openChatWhenReadyDisposable.set((self.authorizedContext()
|
||||
private func openChatWhenReady(accountId: AccountRecordId?, peerId: PeerId, messageId: MessageId? = nil) {
|
||||
let signal = self.sharedContextPromise.get()
|
||||
|> take(1)
|
||||
|> mapToSignal { sharedContext -> Signal<AuthorizedApplicationContext, NoError> in
|
||||
if let accountId = accountId {
|
||||
sharedContext.switchToAccount(id: accountId)
|
||||
return self.authorizedContext()
|
||||
|> filter { context in
|
||||
context.context.account.id == accountId
|
||||
}
|
||||
|> take(1)
|
||||
} else {
|
||||
return self.authorizedContext()
|
||||
|> take(1)
|
||||
}
|
||||
}
|
||||
self.openChatWhenReadyDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { context in
|
||||
context.openChatWithPeerId(peerId: peerId, messageId: messageId)
|
||||
}))
|
||||
|
|
@ -1434,7 +1439,7 @@ private enum QueuedWakeup: Int32 {
|
|||
if response.notification.request.content.categoryIdentifier == "watch" {
|
||||
messageId = messageIdFromNotification(peerId: peerId, notification: response.notification)
|
||||
}
|
||||
self.openChatWhenReady(peerId: peerId, messageId: messageId)
|
||||
self.openChatWhenReady(accountId: accountIdFromNotification(response.notification), peerId: peerId, messageId: messageId)
|
||||
}
|
||||
completionHandler()
|
||||
} else if response.actionIdentifier == "reply", let peerId = peerIdFromNotification(response.notification) {
|
||||
|
|
@ -1507,8 +1512,8 @@ private enum QueuedWakeup: Int32 {
|
|||
|
||||
private func registerForNotifications(context: AccountContext, authorize: Bool = true, completion: @escaping (Bool) -> Void = { _ in }) {
|
||||
let presentationData = context.currentPresentationData.with { $0 }
|
||||
let _ = (context.account.postbox.transaction { transaction -> Bool in
|
||||
let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
|
||||
let _ = (context.sharedContext.accountManager.transaction { transaction -> Bool in
|
||||
let settings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
|
||||
return settings.displayNameOnLockscreen
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { displayNames in
|
||||
|
|
@ -1594,7 +1599,7 @@ private enum QueuedWakeup: Int32 {
|
|||
let queuedMutePolling = self.queuedMutePolling
|
||||
self.queuedMutePolling = false
|
||||
|
||||
let _ = (context.context.account.postbox.transaction(ignoreDisabled: true, { transaction -> PostboxAccessChallengeData in
|
||||
let _ = (context.context.sharedContext.accountManager.transaction(ignoreDisabled: true, { transaction -> PostboxAccessChallengeData in
|
||||
return transaction.getAccessChallengeData()
|
||||
})
|
||||
|> deliverOnMainQueue).start(next: { accessChallengeData in
|
||||
|
|
@ -1726,6 +1731,15 @@ private enum QueuedWakeup: Int32 {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 10.0, *)
|
||||
private func accountIdFromNotification(_ notification: UNNotification) -> AccountRecordId? {
|
||||
if let id = notification.request.content.userInfo["accountId"] as? Int64 {
|
||||
return AccountRecordId(rawValue: id)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 10.0, *)
|
||||
private func peerIdFromNotification(_ notification: UNNotification) -> PeerId? {
|
||||
if let peerId = notification.request.content.userInfo["peerId"] as? Int64 {
|
||||
|
|
|
|||
|
|
@ -7,34 +7,6 @@ import TelegramCore
|
|||
import Display
|
||||
import LegacyComponents
|
||||
|
||||
/*func applicationContext(networkArguments: NetworkInitializationArguments, applicationBindings: TelegramApplicationBindings, replyFromNotificationsActive: Signal<Bool, NoError>, backgroundAudioActive: Signal<Bool, NoError>, watchManagerArguments: Signal<WatchManagerArguments?, NoError>, sharedContext: SharedAccountContext, accountManager: AccountManager, rootPath: String, legacyBasePath: String, mainWindow: Window1, reinitializedNotificationSettings: @escaping () -> Void) -> Signal<ApplicationContext?, NoError> {
|
||||
return currentAccount(allocateIfNotExists: true, networkArguments: networkArguments, supplementary: false, manager: accountManager, rootPath: rootPath, auxiliaryMethods: telegramAccountAuxiliaryMethods)
|
||||
|> filter { $0 != nil }
|
||||
|> deliverOnMainQueue
|
||||
|> mapToSignal { account -> Signal<ApplicationContext?, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
preconditionFailure()
|
||||
case let .unauthorized(account):
|
||||
return currentPresentationDataAndSettings(postbox: account.postbox)
|
||||
|> deliverOnMainQueue
|
||||
|> map { dataAndSettings -> ApplicationContext? in
|
||||
return .unauthorized(UnauthorizedApplicationContext(account: account, applicationBindings: applicationBindings))
|
||||
}
|
||||
case let .authorized(account):
|
||||
return currentPresentationDataAndSettings(postbox: account.postbox)
|
||||
|> deliverOnMainQueue
|
||||
|> map { dataAndSettings -> ApplicationContext? in
|
||||
return .authorized(AuthorizedApplicationContext(mainWindow: mainWindow, replyFromNotificationsActive: replyFromNotificationsActive, backgroundAudioActive: backgroundAudioActive, watchManagerArguments: watchManagerArguments, context: AccountContext(sharedContext: sharedContext, account: account, initialPresentationDataAndSettings: dataAndSettings), accountManager: accountManager, legacyBasePath: legacyBasePath, showCallsTab: dataAndSettings.callListSettings.showTab, reinitializedNotificationSettings: reinitializedNotificationSettings))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
func isAccessLocked(data: PostboxAccessChallengeData, at timestamp: Int32) -> Bool {
|
||||
if data.isLockable, let autolockDeadline = data.autolockDeadline, autolockDeadline <= timestamp {
|
||||
return true
|
||||
|
|
@ -183,7 +155,7 @@ final class AuthorizedApplicationContext {
|
|||
}
|
||||
|
||||
var applicationBadge: Signal<Int32, NoError> {
|
||||
return renderedTotalUnreadCount(postbox: self.context.account.postbox)
|
||||
return renderedTotalUnreadCount(accountManager: self.context.sharedContext.accountManager, postbox: self.context.account.postbox)
|
||||
|> map {
|
||||
$0.0
|
||||
}
|
||||
|
|
@ -225,10 +197,9 @@ final class AuthorizedApplicationContext {
|
|||
|
||||
let runningWatchTasksPromise = Promise<WatchRunningTasks?>(nil)
|
||||
|
||||
let downloadPreferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings]))
|
||||
let runningDownloadTasks = combineLatest(context.account.postbox.combinedView(keys: [downloadPreferencesKey]), context.account.shouldKeepBackgroundDownloadConnections.get())
|
||||
|> map { views, shouldKeepBackgroundDownloadConnections -> Bool in
|
||||
let settings: AutomaticMediaDownloadSettings = (views.views[downloadPreferencesKey] as? PreferencesView)?.values[ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings] as? AutomaticMediaDownloadSettings ?? AutomaticMediaDownloadSettings.defaultSettings
|
||||
let runningDownloadTasks = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]), context.account.shouldKeepBackgroundDownloadConnections.get())
|
||||
|> map { sharedData, shouldKeepBackgroundDownloadConnections -> Bool in
|
||||
let settings: AutomaticMediaDownloadSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? AutomaticMediaDownloadSettings ?? AutomaticMediaDownloadSettings.defaultSettings
|
||||
if !settings.downloadInBackground {
|
||||
return false
|
||||
}
|
||||
|
|
@ -236,7 +207,7 @@ final class AuthorizedApplicationContext {
|
|||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
self.wakeupManager = WakeupManager(inForeground: context.sharedContext.applicationBindings.applicationInForeground, runningServiceTasks: context.account.importantTasksRunning, runningBackgroundLocationTasks: runningBackgroundLocationTasks, runningWatchTasks: runningWatchTasksPromise.get(), runningDownloadTasks: runningDownloadTasks)
|
||||
self.wakeupManager = WakeupManager(accountManager: context.sharedContext.accountManager, inForeground: context.sharedContext.applicationBindings.applicationInForeground, runningServiceTasks: context.account.importantTasksRunning, runningBackgroundLocationTasks: runningBackgroundLocationTasks, runningWatchTasks: runningWatchTasksPromise.get(), runningDownloadTasks: runningDownloadTasks)
|
||||
|
||||
self.showCallsTab = showCallsTab
|
||||
|
||||
|
|
@ -248,7 +219,7 @@ final class AuthorizedApplicationContext {
|
|||
context.attachOverlayMediaController(self.overlayMediaController)
|
||||
var presentImpl: ((ViewController, Any?) -> Void)?
|
||||
var openSettingsImpl: (() -> Void)?
|
||||
let callManager = PresentationCallManager(account: context.account, getDeviceAccessData: {
|
||||
let callManager = PresentationCallManager(accountManager: context.sharedContext.accountManager, account: context.account, getDeviceAccessData: {
|
||||
return (context.currentPresentationData.with { $0 }, { c, a in
|
||||
presentImpl?(c, a)
|
||||
}, {
|
||||
|
|
@ -377,12 +348,10 @@ final class AuthorizedApplicationContext {
|
|||
|
||||
let previousPasscodeState = Atomic<PasscodeState?>(value: nil)
|
||||
|
||||
let preferencesKey: PostboxViewKey = .preferences(keys: Set<ValueBoxKey>([ApplicationSpecificPreferencesKeys.presentationPasscodeSettings]))
|
||||
|
||||
self.passcodeStatusDisposable.set((combineLatest(queue: Queue.mainQueue(), context.account.postbox.combinedView(keys: [.accessChallengeData, preferencesKey]), context.sharedContext.applicationBindings.applicationIsActive)
|
||||
|> map { view, isActive -> (PostboxAccessChallengeData, PresentationPasscodeSettings?, Bool) in
|
||||
let accessChallengeData = (view.views[.accessChallengeData] as? AccessChallengeDataView)?.data ?? PostboxAccessChallengeData.none
|
||||
let passcodeSettings = (view.views[preferencesKey] as! PreferencesView).values[ApplicationSpecificPreferencesKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings
|
||||
self.passcodeStatusDisposable.set((combineLatest(queue: Queue.mainQueue(), context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), context.sharedContext.accountManager.accessChallengeData(), context.sharedContext.applicationBindings.applicationIsActive)
|
||||
|> map { sharedData, accessChallengeDataView, isActive -> (PostboxAccessChallengeData, PresentationPasscodeSettings?, Bool) in
|
||||
let accessChallengeData = accessChallengeDataView.data
|
||||
let passcodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings] as? PresentationPasscodeSettings
|
||||
return (accessChallengeData, passcodeSettings, isActive)
|
||||
}
|
||||
|> map { accessChallengeData, passcodeSettings, isActive -> PasscodeState in
|
||||
|
|
@ -424,7 +393,7 @@ final class AuthorizedApplicationContext {
|
|||
|
||||
if previousState?.isActive != updatedState.isActive || isLocked != strongSelf.isLocked {
|
||||
if updatedAutolockDeadline != previousState?.challengeData.autolockDeadline {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
|
||||
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(updatedAutolockDeadline)
|
||||
transaction.setAccessChallengeData(data)
|
||||
}).start()
|
||||
|
|
@ -457,7 +426,7 @@ final class AuthorizedApplicationContext {
|
|||
return
|
||||
}
|
||||
if value != nil {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
|
||||
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(nil)
|
||||
transaction.setAccessChallengeData(data)
|
||||
}).start()
|
||||
|
|
@ -481,19 +450,19 @@ final class AuthorizedApplicationContext {
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = strongSelf.context.account.postbox.transaction({ transaction -> Void in
|
||||
let _ = strongSelf.context.sharedContext.accountManager.transaction({ transaction -> Void in
|
||||
var attempts: AccessChallengeAttempts?
|
||||
if let attemptData = attemptData {
|
||||
attempts = AccessChallengeAttempts(count: Int32(attemptData.numberOfInvalidAttempts), timestamp: Int32(attemptData.dateOfLastInvalidAttempt))
|
||||
}
|
||||
var data = transaction.getAccessChallengeData()
|
||||
switch data {
|
||||
case .none:
|
||||
break
|
||||
case let .numericalPassword(value, timeout, _):
|
||||
data = .numericalPassword(value: value, timeout: timeout, attempts: attempts)
|
||||
case let .plaintextPassword(value, timeout, _):
|
||||
data = .plaintextPassword(value: value, timeout: timeout, attempts: attempts)
|
||||
case .none:
|
||||
break
|
||||
case let .numericalPassword(value, timeout, _):
|
||||
data = .numericalPassword(value: value, timeout: timeout, attempts: attempts)
|
||||
case let .plaintextPassword(value, timeout, _):
|
||||
data = .plaintextPassword(value: value, timeout: timeout, attempts: attempts)
|
||||
}
|
||||
transaction.setAccessChallengeData(data)
|
||||
}).start()
|
||||
|
|
@ -502,7 +471,7 @@ final class AuthorizedApplicationContext {
|
|||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Void in
|
||||
let _ = (strongSelf.context.sharedContext.accountManager.transaction { transaction -> Void in
|
||||
let data = transaction.getAccessChallengeData().withUpdatedAutolockDeadline(nil)
|
||||
transaction.setAccessChallengeData(data)
|
||||
}).start()
|
||||
|
|
@ -619,16 +588,13 @@ final class AuthorizedApplicationContext {
|
|||
}
|
||||
}))
|
||||
|
||||
let inAppPreferencesKey = PostboxViewKey.preferences(keys: Set([ApplicationSpecificPreferencesKeys.inAppNotificationSettings]))
|
||||
self.inAppNotificationSettingsDisposable.set(((context.account.postbox.combinedView(keys: [inAppPreferencesKey])) |> deliverOnMainQueue).start(next: { [weak self] views in
|
||||
self.inAppNotificationSettingsDisposable.set(((context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.inAppNotificationSettings])) |> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
if let strongSelf = self {
|
||||
if let view = views.views[inAppPreferencesKey] as? PreferencesView {
|
||||
if let settings = view.values[ApplicationSpecificPreferencesKeys.inAppNotificationSettings] as? InAppNotificationSettings {
|
||||
let previousSettings = strongSelf.inAppNotificationSettings
|
||||
strongSelf.inAppNotificationSettings = settings
|
||||
if let previousSettings = previousSettings, previousSettings.displayNameOnLockscreen != settings.displayNameOnLockscreen {
|
||||
reinitializedNotificationSettings()
|
||||
}
|
||||
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.inAppNotificationSettings] as? InAppNotificationSettings {
|
||||
let previousSettings = strongSelf.inAppNotificationSettings
|
||||
strongSelf.inAppNotificationSettings = settings
|
||||
if let previousSettings = previousSettings, previousSettings.displayNameOnLockscreen != settings.displayNameOnLockscreen {
|
||||
reinitializedNotificationSettings()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1038,10 +1004,10 @@ final class AuthorizedApplicationContext {
|
|||
}
|
||||
})
|
||||
|
||||
let showCallsTabSignal = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.callListSettings])
|
||||
|> map { view -> Bool in
|
||||
let showCallsTabSignal = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings])
|
||||
|> map { sharedData -> Bool in
|
||||
var value = true
|
||||
if let settings = view.values[ApplicationSpecificPreferencesKeys.callListSettings] as? CallListSettings {
|
||||
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings] as? CallListSettings {
|
||||
value = settings.showTab
|
||||
}
|
||||
return value
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ enum AccountImportProgressType {
|
|||
case media
|
||||
}
|
||||
|
||||
private func importedAccountData(basePath: String, documentsPath: String, account: TemporaryAccount, database: SqliteInterface) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
private func importedAccountData(basePath: String, documentsPath: String, accountManager: AccountManager, account: TemporaryAccount, database: SqliteInterface) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
let keychain = MTFileBasedKeychain(name: "Telegram", documentsPath: documentsPath)
|
||||
guard let masterDatacenterId = keychain.object(forKey: "defaultDatacenterId", group: "persistent") as? Int else {
|
||||
|
|
@ -33,7 +33,7 @@ private func importedAccountData(basePath: String, documentsPath: String, accoun
|
|||
|
||||
let importData = importPreferencesData(documentsPath: documentsPath, masterDatacenterId: Int32(masterDatacenterId), account: account, database: database)
|
||||
|> mapToSignal { accountUserId -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
return importDatabaseData(account: account, basePath: basePath, database: database, accountUserId: accountUserId)
|
||||
return importDatabaseData(accountManager: accountManager, account: account, basePath: basePath, database: database, accountUserId: accountUserId)
|
||||
}
|
||||
|
||||
return importKeychain
|
||||
|
|
@ -67,7 +67,7 @@ private func importPreferencesData(documentsPath: String, masterDatacenterId: In
|
|||
}
|
||||
}
|
||||
|
||||
private func importDatabaseData(account: TemporaryAccount, basePath: String, database: SqliteInterface, accountUserId: Int32) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
private func importDatabaseData(accountManager: AccountManager, account: TemporaryAccount, basePath: String, database: SqliteInterface, accountUserId: Int32) -> Signal<(AccountImportProgressType, Float), AccountImportError> {
|
||||
return deferred { () -> Signal<(AccountImportProgressType, Float), AccountImportError> in
|
||||
var importedAccountUser: Signal<Never, AccountImportError> = .complete()
|
||||
if let (user, presence) = loadLegacyUser(database: database, id: accountUserId) {
|
||||
|
|
@ -85,7 +85,7 @@ private func importDatabaseData(account: TemporaryAccount, basePath: String, dat
|
|||
/*let importedFiles = loadLegacyFiles(account: account, basePath: basePath, accountPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: accountUserId), database: database)
|
||||
|> introduceError(AccountImportError.self)*/
|
||||
|
||||
let importedLegacyPreferences = importLegacyPreferences(account: account, documentsPath: basePath + "/Documents", database: database)
|
||||
let importedLegacyPreferences = importLegacyPreferences(accountManager: accountManager, account: account, documentsPath: basePath + "/Documents", database: database)
|
||||
|> introduceError(AccountImportError.self)
|
||||
|
||||
return importedAccountUser
|
||||
|
|
@ -221,7 +221,7 @@ func importedLegacyAccount(basePath: String, accountManager: AccountManager, pre
|
|||
return temporaryAccount(manager: accountManager, rootPath: rootPathForBasePath(basePath))
|
||||
|> introduceError(AccountImportError.self)
|
||||
|> mapToSignal { account -> Signal<ImportedLegacyAccountEvent, AccountImportError> in
|
||||
let actions = importedAccountData(basePath: basePath, documentsPath: documentsPath, account: account, database: database)
|
||||
let actions = importedAccountData(basePath: basePath, documentsPath: documentsPath, accountManager: accountManager, account: account, database: database)
|
||||
var result = actions
|
||||
|> map { typeAndProgress -> ImportedLegacyAccountEvent in
|
||||
return .progress(typeAndProgress.0, typeAndProgress.1)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ private func convertLegacyProxyPort(_ value: Int) -> Int32 {
|
|||
}
|
||||
}
|
||||
|
||||
func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, database: SqliteInterface) -> Signal<Never, NoError> {
|
||||
func importLegacyPreferences(accountManager: AccountManager, account: TemporaryAccount, documentsPath: String, database: SqliteInterface) -> Signal<Never, NoError> {
|
||||
return deferred { () -> Signal<Never, NoError> in
|
||||
var presentationState: TGPresentationState?
|
||||
if let value = NSKeyedUnarchiver.unarchiveObject(withFile: documentsPath + "/presentation.dat") as? TGPresentationState {
|
||||
|
|
@ -172,8 +172,8 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
localization = NSKeyedUnarchiver.unarchiveObject(withFile: nativeDocumentsPath + "/localization") as? TGLocalization
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.presentationThemeSettings, { current in
|
||||
return accountManager.transaction { transaction -> Signal<Void, NoError> in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationThemeSettings, { current in
|
||||
var settings = (current as? PresentationThemeSettings) ?? PresentationThemeSettings.defaultSettings
|
||||
if let presentationState = presentationState {
|
||||
switch presentationState.pallete {
|
||||
|
|
@ -249,7 +249,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.automaticMediaDownloadSettings, { current in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings, { current in
|
||||
var settings: AutomaticMediaDownloadSettings = current as? AutomaticMediaDownloadSettings ?? .defaultSettings
|
||||
|
||||
if let preferences = autoDownloadPreferences, !preferences.isDefaultPreferences() {
|
||||
|
|
@ -285,7 +285,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.inAppNotificationSettings, { current in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings, { current in
|
||||
var settings: InAppNotificationSettings = current as? InAppNotificationSettings ?? .defaultSettings
|
||||
if let soundEnabled = soundEnabled {
|
||||
settings.playSounds = soundEnabled
|
||||
|
|
@ -299,7 +299,7 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.voiceCallSettings, { current in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.voiceCallSettings, { current in
|
||||
var settings: VoiceCallSettings = current as? VoiceCallSettings ?? .defaultSettings
|
||||
if let callsDataUsageMode = callsDataUsageMode {
|
||||
switch callsDataUsageMode {
|
||||
|
|
@ -320,7 +320,119 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.proxySettings, { current in
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.callListSettings, { current in
|
||||
var settings: CallListSettings = current as? CallListSettings ?? .defaultSettings
|
||||
if let showCallsTab = showCallsTab {
|
||||
settings.showTab = showCallsTab
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.presentationPasscodeSettings, { current in
|
||||
var settings: PresentationPasscodeSettings = current as? PresentationPasscodeSettings ?? .defaultSettings
|
||||
if let passcodeChallenge = passcodeChallenge {
|
||||
transaction.setAccessChallengeData(passcodeChallenge)
|
||||
switch passcodeChallenge {
|
||||
case .none:
|
||||
break
|
||||
case let .numericalPassword(_, timeout, _):
|
||||
settings.autolockTimeout = timeout
|
||||
case let .plaintextPassword(_, timeout, _):
|
||||
settings.autolockTimeout = timeout
|
||||
}
|
||||
settings.enableBiometrics = passcodeEnableBiometrics
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.stickerSettings, { current in
|
||||
var settings: StickerSettings = current as? StickerSettings ?? .defaultSettings
|
||||
if let stickersSuggestMode = stickersSuggestMode {
|
||||
switch stickersSuggestMode {
|
||||
case 1:
|
||||
settings.emojiStickerSuggestionMode = .installed
|
||||
case 2:
|
||||
settings.emojiStickerSuggestionMode = .none
|
||||
default:
|
||||
settings.emojiStickerSuggestionMode = .all
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.musicPlaybackSettings, { current in
|
||||
var settings: MusicPlaybackSettings = current as? MusicPlaybackSettings ?? .defaultSettings
|
||||
if let musicPlayerOrderType = musicPlayerOrderType {
|
||||
switch musicPlayerOrderType {
|
||||
case 1:
|
||||
settings.order = .reversed
|
||||
case 2:
|
||||
settings.order = .random
|
||||
default:
|
||||
settings.order = .regular
|
||||
}
|
||||
}
|
||||
if let musicPlayerRepeatType = musicPlayerRepeatType {
|
||||
switch musicPlayerRepeatType {
|
||||
case 1:
|
||||
settings.looping = .all
|
||||
case 2:
|
||||
settings.looping = .item
|
||||
default:
|
||||
settings.looping = .none
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.instantPagePresentationSettings, { current in
|
||||
var settings: InstantPagePresentationSettings = current as? InstantPagePresentationSettings ?? .defaultSettings
|
||||
if let instantPageFontSize = instantPageFontSize {
|
||||
switch instantPageFontSize {
|
||||
case 0.85:
|
||||
settings.fontSize = .small
|
||||
case 1.15:
|
||||
settings.fontSize = .large
|
||||
case 1.30:
|
||||
settings.fontSize = .xlarge
|
||||
case 1.50:
|
||||
settings.fontSize = .xxlarge
|
||||
default:
|
||||
settings.fontSize = .standard
|
||||
}
|
||||
}
|
||||
if let instantPageFontSerif = instantPageFontSerif {
|
||||
settings.forceSerif = instantPageFontSerif == 1
|
||||
}
|
||||
if let instantPageTheme = instantPageTheme {
|
||||
switch instantPageTheme {
|
||||
case 1:
|
||||
settings.themeType = .sepia
|
||||
case 2:
|
||||
settings.themeType = .gray
|
||||
case 3:
|
||||
settings.themeType = .dark
|
||||
default:
|
||||
settings.themeType = .light
|
||||
}
|
||||
}
|
||||
if let instantPageAutoNightMode = instantPageAutoNightMode {
|
||||
settings.autoNightMode = instantPageAutoNightMode == 1
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
if let localization = localization {
|
||||
transaction.updateSharedData(SharedDataKeys.localizationSettings, { _ in
|
||||
var entries: [LocalizationEntry] = []
|
||||
for (key, value) in localization.dict() {
|
||||
entries.append(LocalizationEntry.string(key: key, value: value))
|
||||
}
|
||||
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: localization.code, localizedName: "", localization: Localization(version: 0, entries: entries), customPluralizationCode: nil), secondaryComponent: nil)
|
||||
})
|
||||
}
|
||||
|
||||
transaction.updateSharedData(SharedDataKeys.proxySettings, { current in
|
||||
var settings: ProxySettings = current as? ProxySettings ?? .defaultSettings
|
||||
if let callsUseProxy = callsUseProxy {
|
||||
settings.useForCalls = callsUseProxy
|
||||
|
|
@ -364,134 +476,25 @@ func importLegacyPreferences(account: TemporaryAccount, documentsPath: String, d
|
|||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.stickerSettings, { current in
|
||||
var settings: StickerSettings = current as? StickerSettings ?? .defaultSettings
|
||||
if let stickersSuggestMode = stickersSuggestMode {
|
||||
switch stickersSuggestMode {
|
||||
case 1:
|
||||
settings.emojiStickerSuggestionMode = .installed
|
||||
case 2:
|
||||
settings.emojiStickerSuggestionMode = .none
|
||||
default:
|
||||
settings.emojiStickerSuggestionMode = .all
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.contactSynchronizationSettings, { current in
|
||||
var settings: ContactSynchronizationSettings = current as? ContactSynchronizationSettings ?? .defaultSettings
|
||||
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
|
||||
settings.synchronizeDeviceContacts = false
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.contactSynchronizationSettings, { current in
|
||||
var settings: ContactSynchronizationSettings = current as? ContactSynchronizationSettings ?? .defaultSettings
|
||||
if let contactsInhibitSync = contactsInhibitSync, contactsInhibitSync {
|
||||
settings.synchronizeDeviceContacts = false
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.callListSettings, { current in
|
||||
var settings: CallListSettings = current as? CallListSettings ?? .defaultSettings
|
||||
if let showCallsTab = showCallsTab {
|
||||
settings.showTab = showCallsTab
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.presentationPasscodeSettings, { current in
|
||||
var settings: PresentationPasscodeSettings = current as? PresentationPasscodeSettings ?? .defaultSettings
|
||||
if let passcodeChallenge = passcodeChallenge {
|
||||
transaction.setAccessChallengeData(passcodeChallenge)
|
||||
switch passcodeChallenge {
|
||||
case .none:
|
||||
break
|
||||
case let .numericalPassword(_, timeout, _):
|
||||
settings.autolockTimeout = timeout
|
||||
case let .plaintextPassword(_, timeout, _):
|
||||
settings.autolockTimeout = timeout
|
||||
}
|
||||
settings.enableBiometrics = passcodeEnableBiometrics
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
if let localization = localization {
|
||||
transaction.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
|
||||
var entries: [LocalizationEntry] = []
|
||||
for (key, value) in localization.dict() {
|
||||
entries.append(LocalizationEntry.string(key: key, value: value))
|
||||
}
|
||||
return LocalizationSettings(primaryComponent: LocalizationComponent(languageCode: localization.code, localizedName: "", localization: Localization(version: 0, entries: entries), customPluralizationCode: nil), secondaryComponent: nil)
|
||||
return settings
|
||||
})
|
||||
|
||||
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
|
||||
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
|
||||
}
|
||||
|
||||
if let allowSecretWebpagesInitialized = allowSecretWebpagesInitialized, allowSecretWebpagesInitialized, let allowSecretWebpages = allowSecretWebpages {
|
||||
ApplicationSpecificNotice.setSecretChatLinkPreviews(transaction: transaction, value: allowSecretWebpages)
|
||||
}
|
||||
}
|
||||
|
||||
if let secretInlineBotsInitialized = secretInlineBotsInitialized, secretInlineBotsInitialized {
|
||||
ApplicationSpecificNotice.setSecretChatInlineBotUsage(transaction: transaction)
|
||||
}
|
||||
|
||||
if let allowSecretWebpagesInitialized = allowSecretWebpagesInitialized, allowSecretWebpagesInitialized, let allowSecretWebpages = allowSecretWebpages {
|
||||
ApplicationSpecificNotice.setSecretChatLinkPreviews(transaction: transaction, value: allowSecretWebpages)
|
||||
}
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.musicPlaybackSettings, { current in
|
||||
var settings: MusicPlaybackSettings = current as? MusicPlaybackSettings ?? .defaultSettings
|
||||
if let musicPlayerOrderType = musicPlayerOrderType {
|
||||
switch musicPlayerOrderType {
|
||||
case 1:
|
||||
settings.order = .reversed
|
||||
case 2:
|
||||
settings.order = .random
|
||||
default:
|
||||
settings.order = .regular
|
||||
}
|
||||
}
|
||||
if let musicPlayerRepeatType = musicPlayerRepeatType {
|
||||
switch musicPlayerRepeatType {
|
||||
case 1:
|
||||
settings.looping = .all
|
||||
case 2:
|
||||
settings.looping = .item
|
||||
default:
|
||||
settings.looping = .none
|
||||
}
|
||||
}
|
||||
return settings
|
||||
})
|
||||
|
||||
transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.instantPagePresentationSettings, { current in
|
||||
var settings: InstantPagePresentationSettings = current as? InstantPagePresentationSettings ?? .defaultSettings
|
||||
if let instantPageFontSize = instantPageFontSize {
|
||||
switch instantPageFontSize {
|
||||
case 0.85:
|
||||
settings.fontSize = .small
|
||||
case 1.15:
|
||||
settings.fontSize = .large
|
||||
case 1.30:
|
||||
settings.fontSize = .xlarge
|
||||
case 1.50:
|
||||
settings.fontSize = .xxlarge
|
||||
default:
|
||||
settings.fontSize = .standard
|
||||
}
|
||||
}
|
||||
if let instantPageFontSerif = instantPageFontSerif {
|
||||
settings.forceSerif = instantPageFontSerif == 1
|
||||
}
|
||||
if let instantPageTheme = instantPageTheme {
|
||||
switch instantPageTheme {
|
||||
case 1:
|
||||
settings.themeType = .sepia
|
||||
case 2:
|
||||
settings.themeType = .gray
|
||||
case 3:
|
||||
settings.themeType = .dark
|
||||
default:
|
||||
settings.themeType = .light
|
||||
}
|
||||
}
|
||||
if let instantPageAutoNightMode = instantPageAutoNightMode {
|
||||
settings.autoNightMode = instantPageAutoNightMode == 1
|
||||
}
|
||||
return settings
|
||||
})
|
||||
}
|
||||
|> switchToLatest
|
||||
|> ignoreValues
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,9 +242,9 @@ final class NotificationManager {
|
|||
func commitRemoteNotification(context: AccountContext, originalRequestId: NotificationManagedNotificationRequestId?, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
||||
return context.account.postbox.transaction { transaction -> ([(MessageId, [Message], Bool, PeerMessageSound, Bool)], Bool) in
|
||||
var isLocked = false
|
||||
if isAccessLocked(data: transaction.getAccessChallengeData(), at: Int32(CFAbsoluteTimeGetCurrent())) {
|
||||
/*if isAccessLocked(data: transaction.getAccessChallengeData(), at: Int32(CFAbsoluteTimeGetCurrent())) {
|
||||
isLocked = true
|
||||
}
|
||||
}*/
|
||||
|
||||
var results: [(MessageId, [Message], Bool, PeerMessageSound, Bool)] = []
|
||||
var updatedMessageIds = messageIds
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ private struct CombinedRunningImportantTasks: Equatable {
|
|||
}
|
||||
|
||||
final class WakeupManager {
|
||||
private let accountManager: AccountManager
|
||||
private var state = WakeupManagerState()
|
||||
|
||||
private let isProcessingNotificationsValue = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
|
|
@ -68,7 +69,9 @@ final class WakeupManager {
|
|||
|
||||
private var wakeupResultSubscribers: [(Int32, ([MessageId]) -> Signal<Void, NoError>)] = []
|
||||
|
||||
init(inForeground: Signal<Bool, NoError>, runningServiceTasks: Signal<AccountRunningImportantTasks, NoError>, runningBackgroundLocationTasks: Signal<Bool, NoError>, runningWatchTasks: Signal<WatchRunningTasks?, NoError>, runningDownloadTasks: Signal<Bool, NoError>) {
|
||||
init(accountManager: AccountManager, inForeground: Signal<Bool, NoError>, runningServiceTasks: Signal<AccountRunningImportantTasks, NoError>, runningBackgroundLocationTasks: Signal<Bool, NoError>, runningWatchTasks: Signal<WatchRunningTasks?, NoError>, runningDownloadTasks: Signal<Bool, NoError>) {
|
||||
self.accountManager = accountManager
|
||||
|
||||
self.inForegroundDisposable = (inForeground |> distinctUntilChanged |> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
if value {
|
||||
|
|
@ -133,14 +136,20 @@ final class WakeupManager {
|
|||
collectedSignals.append(first.1(messageIds))
|
||||
}
|
||||
}
|
||||
let accountManager = self.accountManager
|
||||
return combineLatest(collectedSignals)
|
||||
|> map { _ -> Void in
|
||||
return Void()
|
||||
} |> mapToSignal { _ -> Signal<Int32?, NoError> in
|
||||
if !messageIds.isEmpty {
|
||||
return account.postbox.transaction { transaction -> Int32? in
|
||||
let (unreadCount, _) = renderedTotalUnreadCount(transaction: transaction)
|
||||
return unreadCount
|
||||
return accountManager.transaction { transaction -> InAppNotificationSettings in
|
||||
return transaction.getSharedData(ApplicationSpecificSharedDataKeys.inAppNotificationSettings) as? InAppNotificationSettings ?? InAppNotificationSettings.defaultSettings
|
||||
}
|
||||
|> mapToSignal { inAppSettings -> Signal<Int32?, NoError> in
|
||||
return account.postbox.transaction { transaction -> Int32? in
|
||||
let (unreadCount, _) = renderedTotalUnreadCount(inAppNotificationSettings: inAppSettings, transaction: transaction)
|
||||
return unreadCount
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
|
|
|
|||
|
|
@ -65,10 +65,9 @@ final class WatchCommunicationManager {
|
|||
strongSelf.server.setMicAccessAllowed(true)
|
||||
strongSelf.server.pushContext()
|
||||
|
||||
let watchPresetSettingsKey = ApplicationSpecificPreferencesKeys.watchPresetSettings
|
||||
strongSelf.presets.set(context.context.account.postbox.preferencesView(keys: [watchPresetSettingsKey])
|
||||
|> map({ preferences -> WatchPresetSettings in
|
||||
return (preferences.values[watchPresetSettingsKey] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings
|
||||
strongSelf.presets.set(context.context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.watchPresetSettings])
|
||||
|> map({ sharedData -> WatchPresetSettings in
|
||||
return (sharedData.entries[ApplicationSpecificSharedDataKeys.watchPresetSettings] as? WatchPresetSettings) ?? WatchPresetSettings.defaultSettings
|
||||
}))
|
||||
} else {
|
||||
strongSelf.accountContext.set(.single(nil))
|
||||
|
|
|
|||
|
|
@ -82,13 +82,11 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
|||
} else {
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
initializeAccountManagement()
|
||||
account = accountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|> take(1)
|
||||
|> mapToSignal { accountManager -> Signal<Account, NoError> in
|
||||
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods)
|
||||
|> mapToSignal { account -> Signal<Account, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods)
|
||||
|> mapToSignal { account -> Signal<Account, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
|
|
@ -96,13 +94,11 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
|||
return .single(account)
|
||||
case .unauthorized:
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
|
||||
let applicationInterface = account |> afterNext { account in
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit d444a36f9875c56902bef4d776098215cb3aa4db
|
||||
Subproject commit 709df1faeffdd6fefc72bb8a1853b65a5e803bdc
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 89531617a0b77014aa69dd8043b67858218e6a1c
|
||||
Subproject commit 67e60e8e8b4ab11daa5b52e732d1a62232b2d31a
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit f811d2a6475398acafae51f8b562b65d486b8bfd
|
||||
Subproject commit 494ba4dc7b8ed5962c64ac1bf3b1efd8b4ec77d7
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 668207ab55d2e58843b0614260f7738c3d6116c4
|
||||
Subproject commit 84231fb6fcbb39f72b50b2812c728cab8c659b52
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 9cd176142e2b34e0062e13f09101ac6364f83b52
|
||||
Subproject commit 3540d5ea002762f50d38ad9cd01ada7f8af2f023
|
||||
Loading…
Add table
Add a link
Reference in a new issue