Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
# Conflicts: # submodules/TelegramPresentationData/Sources/ComponentsThemes.swift # submodules/TelegramUI/TelegramUI/ChatController.swift # submodules/TelegramUI/TelegramUI/NavigateToChatController.swift
@ -1,6 +1,4 @@
|
||||
#ifndef Share_Bridging_Header_h
|
||||
#define Share_Bridging_Header_h
|
||||
|
||||
#import "../Telegram-iOS/BuildConfig.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,297 +1,58 @@
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
import UserNotificationsUI
|
||||
import Display
|
||||
import TelegramCore
|
||||
import TelegramUI
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
private enum NotificationContentAuthorizationError {
|
||||
case unauthorized
|
||||
}
|
||||
|
||||
private var sharedAccountContext: SharedAccountContext?
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
private func setupSharedLogger(_ path: String) {
|
||||
if !installedSharedLogger {
|
||||
installedSharedLogger = true
|
||||
Logger.setSharedLogger(Logger(basePath: path))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
import BuildConfig
|
||||
|
||||
@objc(NotificationViewController)
|
||||
class NotificationViewController: UIViewController, UNNotificationContentExtension {
|
||||
private let imageNode = TransformImageNode()
|
||||
private var imageInfo: (isSticker: Bool, dimensions: CGSize)?
|
||||
|
||||
private let applyDisposable = MetaDisposable()
|
||||
private let fetchedDisposable = MetaDisposable()
|
||||
|
||||
private var accountsPath: String?
|
||||
|
||||
deinit {
|
||||
self.applyDisposable.dispose()
|
||||
self.fetchedDisposable.dispose()
|
||||
}
|
||||
private var impl: NotificationViewControllerImpl?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.view.addSubnode(self.imageNode)
|
||||
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
return
|
||||
}
|
||||
|
||||
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
||||
|
||||
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
|
||||
|
||||
let apiId: Int32 = buildConfig.apiId
|
||||
let languagesCategory = "ios"
|
||||
|
||||
let appGroupName = "group.\(baseAppBundleId)"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
guard let appGroupUrl = maybeAppGroupUrl else {
|
||||
return
|
||||
}
|
||||
|
||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||
performAppGroupUpgrades(appGroupPath: appGroupUrl.path, rootPath: rootPath)
|
||||
|
||||
TempBox.initializeShared(basePath: rootPath, processType: "notification-content", launchSpecificId: arc4random64())
|
||||
|
||||
let logsPath = rootPath + "/notificationcontent-logs"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
setupSharedLogger(logsPath)
|
||||
|
||||
accountsPath = rootPath
|
||||
|
||||
if sharedAccountContext == nil {
|
||||
initializeAccountManagement()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|
||||
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let _ = currentPresentationDataAndSettings(accountManager: accountManager).start(next: { value in
|
||||
initialPresentationDataAndSettings = value
|
||||
semaphore.signal()
|
||||
})
|
||||
semaphore.wait()
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
completion.completion(false)
|
||||
if self.impl == nil {
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
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: {
|
||||
}, getAvailableAlternateIcons: {
|
||||
return []
|
||||
}, getAlternateIconName: {
|
||||
return nil
|
||||
}, requestSetAlternateIconName: { _, f in
|
||||
f(false)
|
||||
})
|
||||
}
|
||||
|
||||
let baseAppBundleId = String(appBundleIdentifier[..<lastDotRange.lowerBound])
|
||||
|
||||
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
|
||||
|
||||
let apiId: Int32 = buildConfig.apiId
|
||||
let languagesCategory = "ios"
|
||||
|
||||
let appGroupName = "group.\(baseAppBundleId)"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
guard let appGroupUrl = maybeAppGroupUrl else {
|
||||
return
|
||||
}
|
||||
|
||||
let rootPath = appGroupUrl.path + "/telegram-data"
|
||||
|
||||
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
|
||||
let encryptionParameters: (Data, Data) = (deviceSpecificEncryptionParameters.key, deviceSpecificEncryptionParameters.salt)
|
||||
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
|
||||
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
|
||||
|
||||
sharedAccountContext = SharedAccountContext(mainWindow: nil, basePath: rootPath, encryptionParameters: encryptionParameters, accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: buildConfig.bundleData), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
||||
self.impl = NotificationViewControllerImpl(initializationData: NotificationViewControllerInitializationData(appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData), setPreferredContentSize: { [weak self] size in
|
||||
self?.preferredContentSize = size
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
self.impl?.viewDidLoad(view: self.view)
|
||||
}
|
||||
|
||||
func didReceive(_ notification: UNNotification) {
|
||||
guard let accountsPath = self.accountsPath else {
|
||||
return
|
||||
}
|
||||
|
||||
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 mediaDataString = notification.request.content.userInfo["media"] as? String, let mediaData = Data(base64Encoded: mediaDataString), let media = parseMediaData(data: mediaData) {
|
||||
let messageId = MessageId(peerId: PeerId(peerIdValue), namespace: messageIdNamespace, id: messageIdId)
|
||||
|
||||
if let image = media as? TelegramMediaImage, let thumbnailRepresentation = imageRepresentationLargerThan(image.representations, size: CGSize(width: 120.0, height: 120.0)), let largestRepresentation = largestImageRepresentation(image.representations) {
|
||||
let dimensions = largestRepresentation.dimensions
|
||||
let fittedSize = dimensions.fitted(CGSize(width: self.view.bounds.width, height: 1000.0))
|
||||
self.view.frame = CGRect(origin: self.view.frame.origin, size: fittedSize)
|
||||
self.preferredContentSize = fittedSize
|
||||
|
||||
self.imageInfo = (false, dimensions)
|
||||
self.updateImageLayout(boundingSize: self.view.bounds.size)
|
||||
|
||||
let mediaBoxPath = accountsPath + "/" + accountRecordIdPathName(AccountRecordId(rawValue: accountIdValue)) + "/postbox/media"
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: mediaBoxPath + "/\(largestRepresentation.resource.id.uniqueId)"), options: .mappedRead) {
|
||||
self.imageNode.setSignal(chatMessagePhotoInternal(photoData: .single((nil, data, true)))
|
||||
|> map { $0.1 })
|
||||
return
|
||||
}
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: mediaBoxPath + "/\(thumbnailRepresentation.resource.id.uniqueId)"), options: .mappedRead) {
|
||||
self.imageNode.setSignal(chatMessagePhotoInternal(photoData: .single((data, nil, false)))
|
||||
|> map { $0.1 })
|
||||
}
|
||||
|
||||
guard let sharedAccountContext = sharedAccountContext else {
|
||||
return
|
||||
}
|
||||
|
||||
self.applyDisposable.set((sharedAccountContext.activeAccounts
|
||||
|> map { _, accounts, _ -> Account? in
|
||||
return accounts.first(where: { $0.0 == AccountRecordId(rawValue: accountIdValue) })?.1
|
||||
}
|
||||
|> 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 {
|
||||
for media in message.media {
|
||||
if let image = media as? TelegramMediaImage {
|
||||
imageReference = .message(message: MessageReference(message), media: image)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
imageReference = .standalone(media: image)
|
||||
}
|
||||
return (account, imageReference)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] accountAndImage in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let imageReference = accountAndImage.1 {
|
||||
strongSelf.imageNode.setSignal(chatMessagePhoto(postbox: accountAndImage.0.postbox, photoReference: imageReference))
|
||||
|
||||
accountAndImage.0.network.shouldExplicitelyKeepWorkerConnections.set(.single(true))
|
||||
strongSelf.fetchedDisposable.set(standaloneChatMessagePhotoInteractiveFetched(account: accountAndImage.0, photoReference: imageReference).start())
|
||||
}
|
||||
}))
|
||||
} else if let file = media as? TelegramMediaFile, let dimensions = file.dimensions {
|
||||
guard let sharedAccountContext = sharedAccountContext else {
|
||||
return
|
||||
}
|
||||
|
||||
let fittedSize = dimensions.fitted(CGSize(width: min(256.0, self.view.bounds.width), height: 256.0))
|
||||
self.view.frame = CGRect(origin: self.view.frame.origin, size: fittedSize)
|
||||
self.preferredContentSize = fittedSize
|
||||
|
||||
self.imageInfo = (true, dimensions)
|
||||
self.updateImageLayout(boundingSize: self.view.bounds.size)
|
||||
|
||||
self.applyDisposable.set((sharedAccountContext.activeAccounts
|
||||
|> map { _, accounts, _ -> Account? in
|
||||
return accounts.first(where: { $0.0 == AccountRecordId(rawValue: accountIdValue) })?.1
|
||||
}
|
||||
|> filter { account in
|
||||
return account != nil
|
||||
}
|
||||
|> take(1)
|
||||
|> mapToSignal { account -> Signal<(Account, FileMediaReference?), NoError> in
|
||||
guard let account = account else {
|
||||
return .complete()
|
||||
}
|
||||
return account.postbox.messageAtId(messageId)
|
||||
|> take(1)
|
||||
|> map { message in
|
||||
var fileReference: FileMediaReference?
|
||||
if let message = message {
|
||||
for media in message.media {
|
||||
if let file = media as? TelegramMediaFile {
|
||||
fileReference = .message(message: MessageReference(message), media: file)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fileReference = .standalone(media: file)
|
||||
}
|
||||
return (account, fileReference)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] accountAndImage in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let fileReference = accountAndImage.1 {
|
||||
if file.isSticker {
|
||||
strongSelf.imageNode.setSignal(chatMessageSticker(account: accountAndImage.0, file: file, small: false))
|
||||
|
||||
accountAndImage.0.network.shouldExplicitelyKeepWorkerConnections.set(.single(true))
|
||||
strongSelf.fetchedDisposable.set(freeMediaFileInteractiveFetched(account: accountAndImage.0, fileReference: fileReference).start())
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
self.impl?.didReceive(notification, view: self.view)
|
||||
}
|
||||
|
||||
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
|
||||
super.viewWillTransition(to: size, with: coordinator)
|
||||
|
||||
self.updateImageLayout(boundingSize: size)
|
||||
}
|
||||
|
||||
private func updateImageLayout(boundingSize: CGSize) {
|
||||
if let (isSticker, dimensions) = self.imageInfo {
|
||||
let makeLayout = self.imageNode.asyncLayout()
|
||||
let fittedSize: CGSize
|
||||
if isSticker {
|
||||
fittedSize = dimensions.fitted(CGSize(width: min(256.0, boundingSize.width), height: 256.0))
|
||||
} else {
|
||||
fittedSize = dimensions.fitted(CGSize(width: boundingSize.width, height: 1000.0))
|
||||
}
|
||||
let apply = makeLayout(TransformImageArguments(corners: ImageCorners(radius: 0.0), imageSize: fittedSize, boundingSize: fittedSize, intrinsicInsets: UIEdgeInsets()))
|
||||
apply()
|
||||
let displaySize = isSticker ? fittedSize : boundingSize
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: floor((boundingSize.width - displaySize.width) / 2.0), y: 0.0), size: displaySize)
|
||||
}
|
||||
self.impl?.viewWillTransition(to: size)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
import CommonCrypto
|
||||
import LightweightAccountData
|
||||
|
||||
private func sha256Digest(_ data: Data) -> Data {
|
||||
let length = data.count
|
||||
|
||||
@ -5,6 +5,9 @@ import MtProtoKit
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
|
||||
import BuildConfig
|
||||
import LightweightAccountData
|
||||
|
||||
struct ImageResource {
|
||||
let datacenterId: Int
|
||||
let volumeId: Int64
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#ifndef NotificationService_BridgingHeader_h
|
||||
#define NotificationService_BridgingHeader_h
|
||||
|
||||
#import "../Telegram-iOS/BuildConfig.h"
|
||||
#import "Crypto.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,6 +6,8 @@ import MtProtoKit
|
||||
import MtProtoKitDynamic
|
||||
#endif
|
||||
import WebP
|
||||
import BuildConfig
|
||||
import LightweightAccountData
|
||||
|
||||
private var sharedLogger: Logger?
|
||||
|
||||
|
||||
@ -1,10 +1,4 @@
|
||||
#ifndef Share_Bridging_Header_h
|
||||
#define Share_Bridging_Header_h
|
||||
|
||||
#import "TGContactModel.h"
|
||||
#import "TGItemProviderSignals.h"
|
||||
#import "TGShareLocationSignals.h"
|
||||
|
||||
#import "../Telegram-iOS/BuildConfig.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,104 +1,15 @@
|
||||
import UIKit
|
||||
import Display
|
||||
import TelegramCore
|
||||
import TelegramUI
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
|
||||
private let inForeground = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
|
||||
private final class SharedExtensionContext {
|
||||
let sharedContext: SharedAccountContext
|
||||
let wakeupManager: SharedWakeupManager
|
||||
|
||||
init(sharedContext: SharedAccountContext) {
|
||||
self.sharedContext = sharedContext
|
||||
self.wakeupManager = SharedWakeupManager(beginBackgroundTask: { _, _ in nil }, endBackgroundTask: { _ in }, backgroundTimeRemaining: { 0.0 }, activeAccounts: sharedContext.activeAccounts |> map { ($0.0, $0.1.map { ($0.0, $0.1) }) }, liveLocationPolling: .single(nil), watchTasks: .single(nil), inForeground: inForeground.get(), hasActiveAudioSession: .single(false), notificationManager: nil, mediaManager: sharedContext.mediaManager, callManager: sharedContext.callManager, accountUserInterfaceInUse: { id in
|
||||
return sharedContext.accountUserInterfaceInUse(id)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private var globalSharedExtensionContext: SharedExtensionContext?
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
private func setupSharedLogger(_ path: String) {
|
||||
if !installedSharedLogger {
|
||||
installedSharedLogger = true
|
||||
Logger.setSharedLogger(Logger(basePath: path))
|
||||
}
|
||||
}
|
||||
|
||||
private enum ShareAuthorizationError {
|
||||
case unauthorized
|
||||
}
|
||||
import BuildConfig
|
||||
|
||||
@objc(ShareRootController)
|
||||
class ShareRootController: UIViewController {
|
||||
private var mainWindow: Window1?
|
||||
private var currentShareController: ShareController?
|
||||
private var currentPasscodeController: ViewController?
|
||||
|
||||
private var shouldBeMaster = Promise<Bool>()
|
||||
private let disposable = MetaDisposable()
|
||||
private var observer1: AnyObject?
|
||||
private var observer2: AnyObject?
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.shouldBeMaster.set(.single(false))
|
||||
if let observer = self.observer1 {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
if let observer = self.observer2 {
|
||||
NotificationCenter.default.removeObserver(observer)
|
||||
}
|
||||
}
|
||||
private var impl: ShareRootControllerImpl?
|
||||
|
||||
override func loadView() {
|
||||
telegramUIDeclareEncodables()
|
||||
|
||||
super.loadView()
|
||||
|
||||
self.view.backgroundColor = nil
|
||||
self.view.isOpaque = false
|
||||
|
||||
if #available(iOSApplicationExtension 8.2, *) {
|
||||
self.observer1 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSExtensionHostDidBecomeActive, object: nil, queue: nil, using: { _ in
|
||||
inForeground.set(true)
|
||||
})
|
||||
|
||||
self.observer2 = NotificationCenter.default.addObserver(forName: NSNotification.Name.NSExtensionHostWillResignActive, object: nil, queue: nil, using: { _ in
|
||||
inForeground.set(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
inForeground.set(true)
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
self.disposable.dispose()
|
||||
inForeground.set(false)
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
|
||||
if self.mainWindow == nil {
|
||||
let mainWindow = Window1(hostView: childWindowHostView(parent: self.view), statusBarHost: nil)
|
||||
mainWindow.hostView.eventView.backgroundColor = UIColor.clear
|
||||
mainWindow.hostView.eventView.isHidden = false
|
||||
self.mainWindow = mainWindow
|
||||
|
||||
self.view.addSubview(mainWindow.hostView.containerView)
|
||||
mainWindow.hostView.containerView.frame = self.view.bounds
|
||||
|
||||
if self.impl == nil {
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
return
|
||||
@ -118,234 +29,33 @@ class ShareRootController: UIViewController {
|
||||
return
|
||||
}
|
||||
|
||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||
performAppGroupUpgrades(appGroupPath: appGroupUrl.path, rootPath: rootPath)
|
||||
let rootPath = appGroupUrl.path + "/telegram-data"
|
||||
|
||||
TempBox.initializeShared(basePath: rootPath, processType: "share", launchSpecificId: arc4random64())
|
||||
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
|
||||
let encryptionParameters: (Data, Data) = (deviceSpecificEncryptionParameters.key, deviceSpecificEncryptionParameters.salt)
|
||||
|
||||
let logsPath = rootPath + "/share-logs"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
setupSharedLogger(logsPath)
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.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: {
|
||||
}, getAvailableAlternateIcons: {
|
||||
return []
|
||||
}, getAlternateIconName: {
|
||||
return nil
|
||||
}, requestSetAlternateIconName: { _, f in
|
||||
f(false)
|
||||
self.impl = ShareRootControllerImpl(initializationData: ShareRootControllerInitializationData(appGroupPath: appGroupUrl.path, apiId: buildConfig.apiId, languagesCategory: languagesCategory, encryptionParameters: encryptionParameters, appVersion: appVersion, bundleData: buildConfig.bundleData), getExtensionContext: { [weak self] in
|
||||
return self?.extensionContext
|
||||
})
|
||||
|
||||
let sharedExtensionContext: SharedExtensionContext
|
||||
|
||||
if let globalSharedExtensionContext = globalSharedExtensionContext {
|
||||
sharedExtensionContext = globalSharedExtensionContext
|
||||
} else {
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
initializeAccountManagement()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
var initialPresentationDataAndSettings: InitialPresentationDataAndSettings?
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let _ = currentPresentationDataAndSettings(accountManager: accountManager).start(next: { value in
|
||||
initialPresentationDataAndSettings = value
|
||||
semaphore.signal()
|
||||
})
|
||||
semaphore.wait()
|
||||
|
||||
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
|
||||
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
|
||||
|
||||
let sharedContext = SharedAccountContext(mainWindow: nil, basePath: rootPath, encryptionParameters: encryptionParameters, accountManager: accountManager, applicationBindings: applicationBindings, initialPresentationDataAndSettings: initialPresentationDataAndSettings!, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: buildConfig.bundleData), rootPath: rootPath, legacyBasePath: nil, legacyCache: nil, apsNotificationToken: .never(), voipNotificationToken: .never(), setNotificationCall: { _ in }, navigateToChat: { _, _, _ in })
|
||||
sharedExtensionContext = SharedExtensionContext(sharedContext: sharedContext)
|
||||
globalSharedExtensionContext = sharedExtensionContext
|
||||
}
|
||||
|
||||
let account: Signal<(SharedAccountContext, Account, [AccountWithInfo]), ShareAuthorizationError> = sharedExtensionContext.sharedContext.accountManager.transaction { transaction -> (SharedAccountContext, LoggingSettings) in
|
||||
return (sharedExtensionContext.sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
|
||||
}
|
||||
|> introduceError(ShareAuthorizationError.self)
|
||||
|> mapToSignal { sharedContext, loggingSettings -> Signal<(SharedAccountContext, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
Logger.shared.logToFile = loggingSettings.logToFile
|
||||
Logger.shared.logToConsole = loggingSettings.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
|
||||
|
||||
return sharedContext.activeAccountsWithInfo
|
||||
|> introduceError(ShareAuthorizationError.self)
|
||||
|> take(1)
|
||||
|> mapToSignal { primary, accounts -> Signal<(SharedAccountContext, Account, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
guard let primary = primary else {
|
||||
return .fail(.unauthorized)
|
||||
}
|
||||
guard let info = accounts.first(where: { $0.account.id == primary }) else {
|
||||
return .fail(.unauthorized)
|
||||
}
|
||||
return .single((sharedContext, info.account, Array(accounts)))
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
|
||||
let applicationInterface = account
|
||||
|> mapToSignal { sharedContext, account, otherAccounts -> Signal<(AccountContext, PostboxAccessChallengeData, [AccountWithInfo]), ShareAuthorizationError> in
|
||||
let limitsConfiguration = account.postbox.transaction { transaction -> LimitsConfiguration in
|
||||
return transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration) as? LimitsConfiguration ?? LimitsConfiguration.defaultValue
|
||||
}
|
||||
return combineLatest(sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), limitsConfiguration, sharedContext.accountManager.accessChallengeData())
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue
|
||||
|> introduceError(ShareAuthorizationError.self)
|
||||
|> map { sharedData, limitsConfiguration, data -> (AccountContext, PostboxAccessChallengeData, [AccountWithInfo]) in
|
||||
updateLegacyLocalization(strings: sharedContext.currentPresentationData.with({ $0 }).strings)
|
||||
let context = AccountContext(sharedContext: sharedContext, account: account, limitsConfiguration: limitsConfiguration)
|
||||
return (context, data.data, otherAccounts)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue
|
||||
|> afterNext { [weak self] context, accessChallengeData, otherAccounts in
|
||||
setupLegacyComponents(context: context)
|
||||
initializeLegacyComponents(application: nil, currentSizeClassGetter: { return .compact }, currentHorizontalClassGetter: { return .compact }, documentsPath: "", currentApplicationBounds: { return CGRect() }, canOpenUrl: { _ in return false}, openUrl: { _ in })
|
||||
|
||||
let displayShare: () -> Void = {
|
||||
var cancelImpl: (() -> Void)?
|
||||
|
||||
let requestUserInteraction: ([UnpreparedShareItemContent]) -> Signal<[PreparedShareItemContent], NoError> = { content in
|
||||
return Signal { [weak self] subscriber in
|
||||
switch content[0] {
|
||||
case let .contact(data):
|
||||
let controller = deviceContactInfoController(context: context, subject: .filter(peer: nil, contactId: nil, contactData: data, completion: { peer, contactData in
|
||||
let phone = contactData.basicData.phoneNumbers[0].value
|
||||
if let vCardData = contactData.serializedVCard() {
|
||||
subscriber.putNext([.media(.media(.standalone(media: TelegramMediaContact(firstName: contactData.basicData.firstName, lastName: contactData.basicData.lastName, phoneNumber: phone, peerId: nil, vCardData: vCardData))))])
|
||||
}
|
||||
subscriber.putCompletion()
|
||||
}), cancelled: {
|
||||
cancelImpl?()
|
||||
})
|
||||
|
||||
if let strongSelf = self, let window = strongSelf.mainWindow {
|
||||
controller.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet)
|
||||
window.present(controller, on: .root)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return ActionDisposable {
|
||||
}
|
||||
} |> runOn(Queue.mainQueue())
|
||||
}
|
||||
|
||||
let sentItems: ([PeerId], [PreparedShareItemContent], Account) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, contents, account in
|
||||
let sentItems = sentShareItems(account: account, to: peerIds, items: contents)
|
||||
|> `catch` { _ -> Signal<
|
||||
Float, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
return sentItems
|
||||
|> map { value -> ShareControllerExternalStatus in
|
||||
return .progress(value)
|
||||
}
|
||||
|> then(.single(.done))
|
||||
}
|
||||
|
||||
let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account in
|
||||
if let strongSelf = self, let inputItems = strongSelf.extensionContext?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty {
|
||||
let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)!
|
||||
return preparedShareItems(account: account, to: peerIds[0], dataItems: rawSignals, additionalText: additionalText)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<PreparedShareItems?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { state -> Signal<ShareControllerExternalStatus, NoError> in
|
||||
guard let state = state else {
|
||||
return .single(.done)
|
||||
}
|
||||
switch state {
|
||||
case .preparing:
|
||||
return .single(.preparing)
|
||||
case let .progress(value):
|
||||
return .single(.progress(value))
|
||||
case let .userInteractionRequired(value):
|
||||
return requestUserInteraction(value)
|
||||
|> mapToSignal { contents -> Signal<ShareControllerExternalStatus, NoError> in
|
||||
return sentItems(peerIds, contents, account)
|
||||
}
|
||||
case let .done(contents):
|
||||
return sentItems(peerIds, contents, account)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return .single(.done)
|
||||
}
|
||||
}), externalShare: false, switchableAccounts: otherAccounts)
|
||||
shareController.presentationArguments = ViewControllerPresentationArguments(presentationAnimation: .modalSheet)
|
||||
shareController.dismissed = { _ in
|
||||
self?.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
}
|
||||
|
||||
cancelImpl = { [weak shareController] in
|
||||
shareController?.dismiss()
|
||||
}
|
||||
|
||||
if let strongSelf = self {
|
||||
if let currentShareController = strongSelf.currentShareController {
|
||||
currentShareController.dismiss()
|
||||
}
|
||||
strongSelf.currentShareController = shareController
|
||||
strongSelf.mainWindow?.present(shareController, on: .root)
|
||||
}
|
||||
|
||||
context.account.resetStateManagement()
|
||||
}
|
||||
|
||||
let _ = passcodeEntryController(context: context, animateIn: true, completion: { value in
|
||||
if value {
|
||||
displayShare()
|
||||
} else {
|
||||
Queue.mainQueue().after(0.5, {
|
||||
self?.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
})
|
||||
}
|
||||
}).start(next: { controller in
|
||||
guard let strongSelf = self, let controller = controller else {
|
||||
return
|
||||
}
|
||||
|
||||
if let currentPasscodeController = strongSelf.currentPasscodeController {
|
||||
currentPasscodeController.dismiss()
|
||||
}
|
||||
strongSelf.currentPasscodeController = controller
|
||||
strongSelf.mainWindow?.present(controller, on: .root)
|
||||
})
|
||||
}
|
||||
|
||||
self.disposable.set(applicationInterface.start(next: { _, _, _ in }, error: { [weak self] error in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let presentationData = sharedExtensionContext.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Share_AuthTitle, text: presentationData.strings.Share_AuthDescription, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
self?.extensionContext?.completeRequest(returningItems: nil, completionHandler: nil)
|
||||
})])
|
||||
strongSelf.mainWindow?.present(controller, on: .root)
|
||||
}, completed: {}))
|
||||
}
|
||||
|
||||
self.impl?.loadView()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.impl?.viewWillAppear()
|
||||
}
|
||||
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
self.impl?.viewWillDisappear()
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
super.viewDidLayoutSubviews()
|
||||
self.impl?.viewDidLayoutSubviews(view: self.view)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface TGMimeTypeMap : NSObject
|
||||
|
||||
+ (NSString *)mimeTypeForExtension:(NSString *)extension;
|
||||
+ (NSString *)extensionForMimeType:(NSString *)mimeType;
|
||||
|
||||
@end
|
||||
@ -1,347 +0,0 @@
|
||||
#import "TGMimeTypeMap.h"
|
||||
|
||||
static NSDictionary *mimeToExtensionMap = nil;
|
||||
static NSDictionary *extensionToMimeMap = nil;
|
||||
|
||||
static void initializeMapping()
|
||||
{
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
NSMutableDictionary *mimeToExtension = [[NSMutableDictionary alloc] init];
|
||||
NSMutableDictionary *extensionToMime = [[NSMutableDictionary alloc] init];
|
||||
|
||||
mimeToExtension[@"application/andrew-inset"] = @"ez"; extensionToMime[@"ez"] = @"application/andrew-inset";
|
||||
mimeToExtension[@"application/dsptype"] = @"tsp"; extensionToMime[@"tsp"] = @"application/dsptype";
|
||||
mimeToExtension[@"application/futuresplash"] = @"spl"; extensionToMime[@"spl"] = @"application/futuresplash";
|
||||
mimeToExtension[@"application/hta"] = @"hta"; extensionToMime[@"hta"] = @"application/hta";
|
||||
mimeToExtension[@"application/mac-binhex40"] = @"hqx"; extensionToMime[@"hqx"] = @"application/mac-binhex40";
|
||||
mimeToExtension[@"application/mac-compactpro"] = @"cpt"; extensionToMime[@"cpt"] = @"application/mac-compactpro";
|
||||
mimeToExtension[@"application/mathematica"] = @"nb"; extensionToMime[@"nb"] = @"application/mathematica";
|
||||
mimeToExtension[@"application/msaccess"] = @"mdb"; extensionToMime[@"mdb"] = @"application/msaccess";
|
||||
mimeToExtension[@"application/oda"] = @"oda"; extensionToMime[@"oda"] = @"application/oda";
|
||||
mimeToExtension[@"application/ogg"] = @"ogg"; extensionToMime[@"ogg"] = @"application/ogg";
|
||||
mimeToExtension[@"application/pdf"] = @"pdf"; extensionToMime[@"pdf"] = @"application/pdf";
|
||||
mimeToExtension[@"application/com.adobe.pdf"] = @"pdf";
|
||||
mimeToExtension[@"application/pgp-keys"] = @"key"; extensionToMime[@"key"] = @"application/pgp-keys";
|
||||
mimeToExtension[@"application/pgp-signature"] = @"pgp"; extensionToMime[@"pgp"] = @"application/pgp-signature";
|
||||
mimeToExtension[@"application/pics-rules"] = @"prf"; extensionToMime[@"prf"] = @"application/pics-rules";
|
||||
mimeToExtension[@"application/rar"] = @"rar"; extensionToMime[@"rar"] = @"application/rar";
|
||||
mimeToExtension[@"application/rdf+xml"] = @"rdf"; extensionToMime[@"rdf"] = @"application/rdf+xml";
|
||||
mimeToExtension[@"application/rss+xml"] = @"rss"; extensionToMime[@"rss"] = @"application/rss+xml";
|
||||
mimeToExtension[@"application/zip"] = @"zip"; extensionToMime[@"zip"] = @"application/zip";
|
||||
mimeToExtension[@"application/vnd.android.package-archive"] = @"apk"; extensionToMime[@"apk"] = @"application/vnd.android.package-archive";
|
||||
mimeToExtension[@"application/vnd.cinderella"] = @"cdy"; extensionToMime[@"cdy"] = @"application/vnd.cinderella";
|
||||
mimeToExtension[@"application/vnd.ms-pki.stl"] = @"stl"; extensionToMime[@"stl"] = @"application/vnd.ms-pki.stl";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.database"] = @"odb"; extensionToMime[@"odb"] = @"application/vnd.oasis.opendocument.database";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.formula"] = @"odf"; extensionToMime[@"odf"] = @"application/vnd.oasis.opendocument.formula";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.graphics"] = @"odg"; extensionToMime[@"odg"] = @"application/vnd.oasis.opendocument.graphics";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.graphics-template"] = @"otg"; extensionToMime[@"otg"] = @"application/vnd.oasis.opendocument.graphics-template";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.image"] = @"odi"; extensionToMime[@"odi"] = @"application/vnd.oasis.opendocument.image";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.spreadsheet"] = @"ods"; extensionToMime[@"ods"] = @"application/vnd.oasis.opendocument.spreadsheet";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.spreadsheet-template"] = @"ots"; extensionToMime[@"ots"] = @"application/vnd.oasis.opendocument.spreadsheet-template";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.text"] = @"odt"; extensionToMime[@"odt"] = @"application/vnd.oasis.opendocument.text";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.text-master"] = @"odm"; extensionToMime[@"odm"] = @"application/vnd.oasis.opendocument.text-master";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.text-template"] = @"ott"; extensionToMime[@"ott"] = @"application/vnd.oasis.opendocument.text-template";
|
||||
mimeToExtension[@"application/vnd.oasis.opendocument.text-web"] = @"oth"; extensionToMime[@"oth"] = @"application/vnd.oasis.opendocument.text-web";
|
||||
mimeToExtension[@"application/msword"] = @"doc"; extensionToMime[@"doc"] = @"application/msword";
|
||||
mimeToExtension[@"application/msword"] = @"dot"; extensionToMime[@"dot"] = @"application/msword";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = @"docx"; extensionToMime[@"docx"] = @"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.wordprocessingml.template"] = @"dotx"; extensionToMime[@"dotx"] = @"application/vnd.openxmlformats-officedocument.wordprocessingml.template";
|
||||
mimeToExtension[@"application/vnd.ms-excel"] = @"xls"; extensionToMime[@"xls"] = @"application/vnd.ms-excel";
|
||||
mimeToExtension[@"application/vnd.ms-excel"] = @"xlt"; extensionToMime[@"xlt"] = @"application/vnd.ms-excel";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = @"xlsx"; extensionToMime[@"xlsx"] = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.spreadsheetml.template"] = @"xltx"; extensionToMime[@"xltx"] = @"application/vnd.openxmlformats-officedocument.spreadsheetml.template";
|
||||
mimeToExtension[@"application/vnd.ms-powerpoint"] = @"ppt"; extensionToMime[@"ppt"] = @"application/vnd.ms-powerpoint";
|
||||
mimeToExtension[@"application/vnd.ms-powerpoint"] = @"pot"; extensionToMime[@"pot"] = @"application/vnd.ms-powerpoint";
|
||||
mimeToExtension[@"application/vnd.ms-powerpoint"] = @"pps"; extensionToMime[@"pps"] = @"application/vnd.ms-powerpoint";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.presentationml.presentation"] = @"pptx"; extensionToMime[@"pptx"] = @"application/vnd.openxmlformats-officedocument.presentationml.presentation";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.presentationml.template"] = @"potx"; extensionToMime[@"potx"] = @"application/vnd.openxmlformats-officedocument.presentationml.template";
|
||||
mimeToExtension[@"application/vnd.openxmlformats-officedocument.presentationml.slideshow"] = @"ppsx"; extensionToMime[@"ppsx"] = @"application/vnd.openxmlformats-officedocument.presentationml.slideshow";
|
||||
mimeToExtension[@"application/vnd.rim.cod"] = @"cod"; extensionToMime[@"cod"] = @"application/vnd.rim.cod";
|
||||
mimeToExtension[@"application/vnd.smaf"] = @"mmf"; extensionToMime[@"mmf"] = @"application/vnd.smaf";
|
||||
mimeToExtension[@"application/vnd.stardivision.calc"] = @"sdc"; extensionToMime[@"sdc"] = @"application/vnd.stardivision.calc";
|
||||
mimeToExtension[@"application/vnd.stardivision.draw"] = @"sda"; extensionToMime[@"sda"] = @"application/vnd.stardivision.draw";
|
||||
mimeToExtension[@"application/vnd.stardivision.impress"] = @"sdd"; extensionToMime[@"sdd"] = @"application/vnd.stardivision.impress";
|
||||
mimeToExtension[@"application/vnd.stardivision.impress"] = @"sdp"; extensionToMime[@"sdp"] = @"application/vnd.stardivision.impress";
|
||||
mimeToExtension[@"application/vnd.stardivision.math"] = @"smf"; extensionToMime[@"smf"] = @"application/vnd.stardivision.math";
|
||||
mimeToExtension[@"application/vnd.stardivision.writer"] = @"sdw"; extensionToMime[@"sdw"] = @"application/vnd.stardivision.writer";
|
||||
mimeToExtension[@"application/vnd.stardivision.writer"] = @"vor"; extensionToMime[@"vor"] = @"application/vnd.stardivision.writer";
|
||||
mimeToExtension[@"application/vnd.stardivision.writer-global"] = @"sgl"; extensionToMime[@"sgl"] = @"application/vnd.stardivision.writer-global";
|
||||
mimeToExtension[@"application/vnd.sun.xml.calc"] = @"sxc"; extensionToMime[@"sxc"] = @"application/vnd.sun.xml.calc";
|
||||
mimeToExtension[@"application/vnd.sun.xml.calc.template"] = @"stc"; extensionToMime[@"stc"] = @"application/vnd.sun.xml.calc.template";
|
||||
mimeToExtension[@"application/vnd.sun.xml.draw"] = @"sxd"; extensionToMime[@"sxd"] = @"application/vnd.sun.xml.draw";
|
||||
mimeToExtension[@"application/vnd.sun.xml.draw.template"] = @"std"; extensionToMime[@"std"] = @"application/vnd.sun.xml.draw.template";
|
||||
mimeToExtension[@"application/vnd.sun.xml.impress"] = @"sxi"; extensionToMime[@"sxi"] = @"application/vnd.sun.xml.impress";
|
||||
mimeToExtension[@"application/vnd.sun.xml.impress.template"] = @"sti"; extensionToMime[@"sti"] = @"application/vnd.sun.xml.impress.template";
|
||||
mimeToExtension[@"application/vnd.sun.xml.math"] = @"sxm"; extensionToMime[@"sxm"] = @"application/vnd.sun.xml.math";
|
||||
mimeToExtension[@"application/vnd.sun.xml.writer"] = @"sxw"; extensionToMime[@"sxw"] = @"application/vnd.sun.xml.writer";
|
||||
mimeToExtension[@"application/vnd.sun.xml.writer.global"] = @"sxg"; extensionToMime[@"sxg"] = @"application/vnd.sun.xml.writer.global";
|
||||
mimeToExtension[@"application/vnd.sun.xml.writer.template"] = @"stw"; extensionToMime[@"stw"] = @"application/vnd.sun.xml.writer.template";
|
||||
mimeToExtension[@"application/vnd.visio"] = @"vsd"; extensionToMime[@"vsd"] = @"application/vnd.visio";
|
||||
mimeToExtension[@"application/x-abiword"] = @"abw"; extensionToMime[@"abw"] = @"application/x-abiword";
|
||||
mimeToExtension[@"application/x-apple-diskimage"] = @"dmg"; extensionToMime[@"dmg"] = @"application/x-apple-diskimage";
|
||||
mimeToExtension[@"application/x-bcpio"] = @"bcpio"; extensionToMime[@"bcpio"] = @"application/x-bcpio";
|
||||
mimeToExtension[@"application/x-bittorrent"] = @"torrent"; extensionToMime[@"torrent"] = @"application/x-bittorrent";
|
||||
mimeToExtension[@"application/x-cdf"] = @"cdf"; extensionToMime[@"cdf"] = @"application/x-cdf";
|
||||
mimeToExtension[@"application/x-cdlink"] = @"vcd"; extensionToMime[@"vcd"] = @"application/x-cdlink";
|
||||
mimeToExtension[@"application/x-chess-pgn"] = @"pgn"; extensionToMime[@"pgn"] = @"application/x-chess-pgn";
|
||||
mimeToExtension[@"application/x-cpio"] = @"cpio"; extensionToMime[@"cpio"] = @"application/x-cpio";
|
||||
mimeToExtension[@"application/x-debian-package"] = @"deb"; extensionToMime[@"deb"] = @"application/x-debian-package";
|
||||
mimeToExtension[@"application/x-debian-package"] = @"udeb"; extensionToMime[@"udeb"] = @"application/x-debian-package";
|
||||
mimeToExtension[@"application/x-director"] = @"dcr"; extensionToMime[@"dcr"] = @"application/x-director";
|
||||
mimeToExtension[@"application/x-director"] = @"dir"; extensionToMime[@"dir"] = @"application/x-director";
|
||||
mimeToExtension[@"application/x-director"] = @"dxr"; extensionToMime[@"dxr"] = @"application/x-director";
|
||||
mimeToExtension[@"application/x-dms"] = @"dms"; extensionToMime[@"dms"] = @"application/x-dms";
|
||||
mimeToExtension[@"application/x-doom"] = @"wad"; extensionToMime[@"wad"] = @"application/x-doom";
|
||||
mimeToExtension[@"application/x-dvi"] = @"dvi"; extensionToMime[@"dvi"] = @"application/x-dvi";
|
||||
mimeToExtension[@"application/x-flac"] = @"flac"; extensionToMime[@"flac"] = @"application/x-flac";
|
||||
mimeToExtension[@"application/x-font"] = @"pfa"; extensionToMime[@"pfa"] = @"application/x-font";
|
||||
mimeToExtension[@"application/x-font"] = @"pfb"; extensionToMime[@"pfb"] = @"application/x-font";
|
||||
mimeToExtension[@"application/x-font"] = @"gsf"; extensionToMime[@"gsf"] = @"application/x-font";
|
||||
mimeToExtension[@"application/x-font"] = @"pcf"; extensionToMime[@"pcf"] = @"application/x-font";
|
||||
mimeToExtension[@"application/x-font"] = @"pcf.Z"; extensionToMime[@"pcf.Z"] = @"application/x-font";
|
||||
mimeToExtension[@"application/x-freemind"] = @"mm"; extensionToMime[@"mm"] = @"application/x-freemind";
|
||||
mimeToExtension[@"application/x-futuresplash"] = @"spl"; extensionToMime[@"spl"] = @"application/x-futuresplash";
|
||||
mimeToExtension[@"application/x-gnumeric"] = @"gnumeric"; extensionToMime[@"gnumeric"] = @"application/x-gnumeric";
|
||||
mimeToExtension[@"application/x-go-sgf"] = @"sgf"; extensionToMime[@"sgf"] = @"application/x-go-sgf";
|
||||
mimeToExtension[@"application/x-graphing-calculator"] = @"gcf"; extensionToMime[@"gcf"] = @"application/x-graphing-calculator";
|
||||
mimeToExtension[@"application/x-gtar"] = @"gtar"; extensionToMime[@"gtar"] = @"application/x-gtar";
|
||||
mimeToExtension[@"application/x-gtar"] = @"tgz"; extensionToMime[@"tgz"] = @"application/x-gtar";
|
||||
mimeToExtension[@"application/x-gtar"] = @"taz"; extensionToMime[@"taz"] = @"application/x-gtar";
|
||||
mimeToExtension[@"application/x-hdf"] = @"hdf"; extensionToMime[@"hdf"] = @"application/x-hdf";
|
||||
mimeToExtension[@"application/x-ica"] = @"ica"; extensionToMime[@"ica"] = @"application/x-ica";
|
||||
mimeToExtension[@"application/x-internet-signup"] = @"ins"; extensionToMime[@"ins"] = @"application/x-internet-signup";
|
||||
mimeToExtension[@"application/x-internet-signup"] = @"isp"; extensionToMime[@"isp"] = @"application/x-internet-signup";
|
||||
mimeToExtension[@"application/x-iphone"] = @"iii"; extensionToMime[@"iii"] = @"application/x-iphone";
|
||||
mimeToExtension[@"application/x-iso9660-image"] = @"iso"; extensionToMime[@"iso"] = @"application/x-iso9660-image";
|
||||
mimeToExtension[@"application/x-jmol"] = @"jmz"; extensionToMime[@"jmz"] = @"application/x-jmol";
|
||||
mimeToExtension[@"application/x-kchart"] = @"chrt"; extensionToMime[@"chrt"] = @"application/x-kchart";
|
||||
mimeToExtension[@"application/x-killustrator"] = @"kil"; extensionToMime[@"kil"] = @"application/x-killustrator";
|
||||
mimeToExtension[@"application/x-koan"] = @"skp"; extensionToMime[@"skp"] = @"application/x-koan";
|
||||
mimeToExtension[@"application/x-koan"] = @"skd"; extensionToMime[@"skd"] = @"application/x-koan";
|
||||
mimeToExtension[@"application/x-koan"] = @"skt"; extensionToMime[@"skt"] = @"application/x-koan";
|
||||
mimeToExtension[@"application/x-koan"] = @"skm"; extensionToMime[@"skm"] = @"application/x-koan";
|
||||
mimeToExtension[@"application/x-kpresenter"] = @"kpr"; extensionToMime[@"kpr"] = @"application/x-kpresenter";
|
||||
mimeToExtension[@"application/x-kpresenter"] = @"kpt"; extensionToMime[@"kpt"] = @"application/x-kpresenter";
|
||||
mimeToExtension[@"application/x-kspread"] = @"ksp"; extensionToMime[@"ksp"] = @"application/x-kspread";
|
||||
mimeToExtension[@"application/x-kword"] = @"kwd"; extensionToMime[@"kwd"] = @"application/x-kword";
|
||||
mimeToExtension[@"application/x-kword"] = @"kwt"; extensionToMime[@"kwt"] = @"application/x-kword";
|
||||
mimeToExtension[@"application/x-latex"] = @"latex"; extensionToMime[@"latex"] = @"application/x-latex";
|
||||
mimeToExtension[@"application/x-lha"] = @"lha"; extensionToMime[@"lha"] = @"application/x-lha";
|
||||
mimeToExtension[@"application/x-lzh"] = @"lzh"; extensionToMime[@"lzh"] = @"application/x-lzh";
|
||||
mimeToExtension[@"application/x-lzx"] = @"lzx"; extensionToMime[@"lzx"] = @"application/x-lzx";
|
||||
mimeToExtension[@"application/x-maker"] = @"frm"; extensionToMime[@"frm"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-maker"] = @"maker"; extensionToMime[@"maker"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-maker"] = @"frame"; extensionToMime[@"frame"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-maker"] = @"fb"; extensionToMime[@"fb"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-maker"] = @"book"; extensionToMime[@"book"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-maker"] = @"fbdoc"; extensionToMime[@"fbdoc"] = @"application/x-maker";
|
||||
mimeToExtension[@"application/x-mif"] = @"mif"; extensionToMime[@"mif"] = @"application/x-mif";
|
||||
mimeToExtension[@"application/x-ms-wmd"] = @"wmd"; extensionToMime[@"wmd"] = @"application/x-ms-wmd";
|
||||
mimeToExtension[@"application/x-ms-wmz"] = @"wmz"; extensionToMime[@"wmz"] = @"application/x-ms-wmz";
|
||||
mimeToExtension[@"application/x-msi"] = @"msi"; extensionToMime[@"msi"] = @"application/x-msi";
|
||||
mimeToExtension[@"application/x-ns-proxy-autoconfig"] = @"pac"; extensionToMime[@"pac"] = @"application/x-ns-proxy-autoconfig";
|
||||
mimeToExtension[@"application/x-nwc"] = @"nwc"; extensionToMime[@"nwc"] = @"application/x-nwc";
|
||||
mimeToExtension[@"application/x-object"] = @"o"; extensionToMime[@"o"] = @"application/x-object";
|
||||
mimeToExtension[@"application/x-oz-application"] = @"oza"; extensionToMime[@"oza"] = @"application/x-oz-application";
|
||||
mimeToExtension[@"application/x-pkcs12"] = @"p12"; extensionToMime[@"p12"] = @"application/x-pkcs12";
|
||||
mimeToExtension[@"application/x-pkcs7-certreqresp"] = @"p7r"; extensionToMime[@"p7r"] = @"application/x-pkcs7-certreqresp";
|
||||
mimeToExtension[@"application/x-pkcs7-crl"] = @"crl"; extensionToMime[@"crl"] = @"application/x-pkcs7-crl";
|
||||
mimeToExtension[@"application/x-quicktimeplayer"] = @"qtl"; extensionToMime[@"qtl"] = @"application/x-quicktimeplayer";
|
||||
mimeToExtension[@"application/x-shar"] = @"shar"; extensionToMime[@"shar"] = @"application/x-shar";
|
||||
mimeToExtension[@"application/x-shockwave-flash"] = @"swf"; extensionToMime[@"swf"] = @"application/x-shockwave-flash";
|
||||
mimeToExtension[@"application/x-stuffit"] = @"sit"; extensionToMime[@"sit"] = @"application/x-stuffit";
|
||||
mimeToExtension[@"application/x-sv4cpio"] = @"sv4cpio"; extensionToMime[@"sv4cpio"] = @"application/x-sv4cpio";
|
||||
mimeToExtension[@"application/x-sv4crc"] = @"sv4crc"; extensionToMime[@"sv4crc"] = @"application/x-sv4crc";
|
||||
mimeToExtension[@"application/x-tar"] = @"tar"; extensionToMime[@"tar"] = @"application/x-tar";
|
||||
mimeToExtension[@"application/x-texinfo"] = @"texinfo"; extensionToMime[@"texinfo"] = @"application/x-texinfo";
|
||||
mimeToExtension[@"application/x-texinfo"] = @"texi"; extensionToMime[@"texi"] = @"application/x-texinfo";
|
||||
mimeToExtension[@"application/x-troff"] = @"t"; extensionToMime[@"t"] = @"application/x-troff";
|
||||
mimeToExtension[@"application/x-troff"] = @"roff"; extensionToMime[@"roff"] = @"application/x-troff";
|
||||
mimeToExtension[@"application/x-troff-man"] = @"man"; extensionToMime[@"man"] = @"application/x-troff-man";
|
||||
mimeToExtension[@"application/x-ustar"] = @"ustar"; extensionToMime[@"ustar"] = @"application/x-ustar";
|
||||
mimeToExtension[@"application/x-wais-source"] = @"src"; extensionToMime[@"src"] = @"application/x-wais-source";
|
||||
mimeToExtension[@"application/x-wingz"] = @"wz"; extensionToMime[@"wz"] = @"application/x-wingz";
|
||||
mimeToExtension[@"application/x-webarchive"] = @"webarchive"; extensionToMime[@"webarchive"] = @"application/x-webarchive";
|
||||
mimeToExtension[@"application/x-x509-ca-cert"] = @"crt"; extensionToMime[@"crt"] = @"application/x-x509-ca-cert";
|
||||
mimeToExtension[@"application/x-x509-user-cert"] = @"crt"; extensionToMime[@"crt"] = @"application/x-x509-user-cert";
|
||||
mimeToExtension[@"application/x-xcf"] = @"xcf"; extensionToMime[@"xcf"] = @"application/x-xcf";
|
||||
mimeToExtension[@"application/x-xfig"] = @"fig"; extensionToMime[@"fig"] = @"application/x-xfig";
|
||||
mimeToExtension[@"application/xhtml+xml"] = @"xhtml"; extensionToMime[@"xhtml"] = @"application/xhtml+xml";
|
||||
mimeToExtension[@"audio/3gpp"] = @"3gpp"; extensionToMime[@"3gpp"] = @"audio/3gpp";
|
||||
mimeToExtension[@"audio/basic"] = @"snd"; extensionToMime[@"snd"] = @"audio/basic";
|
||||
mimeToExtension[@"audio/midi"] = @"mid"; extensionToMime[@"mid"] = @"audio/midi";
|
||||
mimeToExtension[@"audio/midi"] = @"midi"; extensionToMime[@"midi"] = @"audio/midi";
|
||||
mimeToExtension[@"audio/midi"] = @"kar"; extensionToMime[@"kar"] = @"audio/midi";
|
||||
mimeToExtension[@"audio/mpeg"] = @"mpga"; extensionToMime[@"mpga"] = @"audio/mpeg";
|
||||
mimeToExtension[@"audio/mpeg"] = @"mpega"; extensionToMime[@"mpega"] = @"audio/mpeg";
|
||||
mimeToExtension[@"audio/mpeg"] = @"mp2"; extensionToMime[@"mp2"] = @"audio/mpeg";
|
||||
mimeToExtension[@"audio/mpeg"] = @"mp3"; extensionToMime[@"mp3"] = @"audio/mpeg";
|
||||
mimeToExtension[@"audio/mpeg"] = @"m4a"; extensionToMime[@"m4a"] = @"audio/mpeg";
|
||||
mimeToExtension[@"audio/mpegurl"] = @"m3u"; extensionToMime[@"m3u"] = @"audio/mpegurl";
|
||||
mimeToExtension[@"audio/prs.sid"] = @"sid"; extensionToMime[@"sid"] = @"audio/prs.sid";
|
||||
mimeToExtension[@"audio/x-aiff"] = @"aif"; extensionToMime[@"aif"] = @"audio/x-aiff";
|
||||
mimeToExtension[@"audio/x-aiff"] = @"aiff"; extensionToMime[@"aiff"] = @"audio/x-aiff";
|
||||
mimeToExtension[@"audio/x-aiff"] = @"aifc"; extensionToMime[@"aifc"] = @"audio/x-aiff";
|
||||
mimeToExtension[@"audio/x-gsm"] = @"gsm"; extensionToMime[@"gsm"] = @"audio/x-gsm";
|
||||
mimeToExtension[@"audio/x-mpegurl"] = @"m3u"; extensionToMime[@"m3u"] = @"audio/x-mpegurl";
|
||||
mimeToExtension[@"audio/x-ms-wma"] = @"wma"; extensionToMime[@"wma"] = @"audio/x-ms-wma";
|
||||
mimeToExtension[@"audio/x-ms-wax"] = @"wax"; extensionToMime[@"wax"] = @"audio/x-ms-wax";
|
||||
mimeToExtension[@"audio/x-pn-realaudio"] = @"ra"; extensionToMime[@"ra"] = @"audio/x-pn-realaudio";
|
||||
mimeToExtension[@"audio/x-pn-realaudio"] = @"rm"; extensionToMime[@"rm"] = @"audio/x-pn-realaudio";
|
||||
mimeToExtension[@"audio/x-pn-realaudio"] = @"ram"; extensionToMime[@"ram"] = @"audio/x-pn-realaudio";
|
||||
mimeToExtension[@"audio/x-realaudio"] = @"ra"; extensionToMime[@"ra"] = @"audio/x-realaudio";
|
||||
mimeToExtension[@"audio/x-scpls"] = @"pls"; extensionToMime[@"pls"] = @"audio/x-scpls";
|
||||
mimeToExtension[@"audio/x-sd2"] = @"sd2"; extensionToMime[@"sd2"] = @"audio/x-sd2";
|
||||
mimeToExtension[@"audio/x-wav"] = @"wav"; extensionToMime[@"wav"] = @"audio/x-wav";
|
||||
mimeToExtension[@"image/bmp"] = @"bmp"; extensionToMime[@"bmp"] = @"image/bmp";
|
||||
mimeToExtension[@"image/gif"] = @"gif"; extensionToMime[@"gif"] = @"image/gif";
|
||||
mimeToExtension[@"image/ico"] = @"cur"; extensionToMime[@"cur"] = @"image/ico";
|
||||
mimeToExtension[@"image/ico"] = @"ico"; extensionToMime[@"ico"] = @"image/ico";
|
||||
mimeToExtension[@"image/ief"] = @"ief"; extensionToMime[@"ief"] = @"image/ief";
|
||||
mimeToExtension[@"image/jpeg"] = @"jpeg"; extensionToMime[@"jpeg"] = @"image/jpeg";
|
||||
mimeToExtension[@"image/jpeg"] = @"jpg"; extensionToMime[@"jpg"] = @"image/jpeg";
|
||||
mimeToExtension[@"image/jpeg"] = @"jpe"; extensionToMime[@"jpe"] = @"image/jpeg";
|
||||
mimeToExtension[@"image/pcx"] = @"pcx"; extensionToMime[@"pcx"] = @"image/pcx";
|
||||
mimeToExtension[@"image/png"] = @"png"; extensionToMime[@"png"] = @"image/png";
|
||||
mimeToExtension[@"image/svg+xml"] = @"svg"; extensionToMime[@"svg"] = @"image/svg+xml";
|
||||
mimeToExtension[@"image/svg+xml"] = @"svgz"; extensionToMime[@"svgz"] = @"image/svg+xml";
|
||||
mimeToExtension[@"image/tiff"] = @"tiff"; extensionToMime[@"tiff"] = @"image/tiff";
|
||||
mimeToExtension[@"image/tiff"] = @"tif"; extensionToMime[@"tif"] = @"image/tiff";
|
||||
mimeToExtension[@"image/vnd.djvu"] = @"djvu"; extensionToMime[@"djvu"] = @"image/vnd.djvu";
|
||||
mimeToExtension[@"image/vnd.djvu"] = @"djv"; extensionToMime[@"djv"] = @"image/vnd.djvu";
|
||||
mimeToExtension[@"image/vnd.wap.wbmp"] = @"wbmp"; extensionToMime[@"wbmp"] = @"image/vnd.wap.wbmp";
|
||||
mimeToExtension[@"image/x-cmu-raster"] = @"ras"; extensionToMime[@"ras"] = @"image/x-cmu-raster";
|
||||
mimeToExtension[@"image/x-coreldraw"] = @"cdr"; extensionToMime[@"cdr"] = @"image/x-coreldraw";
|
||||
mimeToExtension[@"image/x-coreldrawpattern"] = @"pat"; extensionToMime[@"pat"] = @"image/x-coreldrawpattern";
|
||||
mimeToExtension[@"image/x-coreldrawtemplate"] = @"cdt"; extensionToMime[@"cdt"] = @"image/x-coreldrawtemplate";
|
||||
mimeToExtension[@"image/x-corelphotopaint"] = @"cpt"; extensionToMime[@"cpt"] = @"image/x-corelphotopaint";
|
||||
mimeToExtension[@"image/x-icon"] = @"ico"; extensionToMime[@"ico"] = @"image/x-icon";
|
||||
mimeToExtension[@"image/x-jg"] = @"art"; extensionToMime[@"art"] = @"image/x-jg";
|
||||
mimeToExtension[@"image/x-jng"] = @"jng"; extensionToMime[@"jng"] = @"image/x-jng";
|
||||
mimeToExtension[@"image/x-ms-bmp"] = @"bmp"; extensionToMime[@"bmp"] = @"image/x-ms-bmp";
|
||||
mimeToExtension[@"image/x-photoshop"] = @"psd"; extensionToMime[@"psd"] = @"image/x-photoshop";
|
||||
mimeToExtension[@"image/x-portable-anymap"] = @"pnm"; extensionToMime[@"pnm"] = @"image/x-portable-anymap";
|
||||
mimeToExtension[@"image/x-portable-bitmap"] = @"pbm"; extensionToMime[@"pbm"] = @"image/x-portable-bitmap";
|
||||
mimeToExtension[@"image/x-portable-graymap"] = @"pgm"; extensionToMime[@"pgm"] = @"image/x-portable-graymap";
|
||||
mimeToExtension[@"image/x-portable-pixmap"] = @"ppm"; extensionToMime[@"ppm"] = @"image/x-portable-pixmap";
|
||||
mimeToExtension[@"image/x-rgb"] = @"rgb"; extensionToMime[@"rgb"] = @"image/x-rgb";
|
||||
mimeToExtension[@"image/x-xbitmap"] = @"xbm"; extensionToMime[@"xbm"] = @"image/x-xbitmap";
|
||||
mimeToExtension[@"image/x-xpixmap"] = @"xpm"; extensionToMime[@"xpm"] = @"image/x-xpixmap";
|
||||
mimeToExtension[@"image/x-xwindowdump"] = @"xwd"; extensionToMime[@"xwd"] = @"image/x-xwindowdump";
|
||||
mimeToExtension[@"model/iges"] = @"igs"; extensionToMime[@"igs"] = @"model/iges";
|
||||
mimeToExtension[@"model/iges"] = @"iges"; extensionToMime[@"iges"] = @"model/iges";
|
||||
mimeToExtension[@"model/mesh"] = @"msh"; extensionToMime[@"msh"] = @"model/mesh";
|
||||
mimeToExtension[@"model/mesh"] = @"mesh"; extensionToMime[@"mesh"] = @"model/mesh";
|
||||
mimeToExtension[@"model/mesh"] = @"silo"; extensionToMime[@"silo"] = @"model/mesh";
|
||||
mimeToExtension[@"text/calendar"] = @"ics"; extensionToMime[@"ics"] = @"text/calendar";
|
||||
mimeToExtension[@"text/calendar"] = @"icz"; extensionToMime[@"icz"] = @"text/calendar";
|
||||
mimeToExtension[@"text/comma-separated-values"] = @"csv"; extensionToMime[@"csv"] = @"text/comma-separated-values";
|
||||
mimeToExtension[@"text/css"] = @"css"; extensionToMime[@"css"] = @"text/css";
|
||||
mimeToExtension[@"text/html"] = @"htm"; extensionToMime[@"htm"] = @"text/html";
|
||||
mimeToExtension[@"text/html"] = @"html"; extensionToMime[@"html"] = @"text/html";
|
||||
mimeToExtension[@"text/h323"] = @"323"; extensionToMime[@"323"] = @"text/h323";
|
||||
mimeToExtension[@"text/iuls"] = @"uls"; extensionToMime[@"uls"] = @"text/iuls";
|
||||
mimeToExtension[@"text/mathml"] = @"mml"; extensionToMime[@"mml"] = @"text/mathml";
|
||||
// add it first so it will be the default for ExtensionFromMimeType
|
||||
mimeToExtension[@"text/plain"] = @"txt"; extensionToMime[@"txt"] = @"text/plain";
|
||||
mimeToExtension[@"text/plain"] = @"asc"; extensionToMime[@"asc"] = @"text/plain";
|
||||
mimeToExtension[@"text/plain"] = @"text"; extensionToMime[@"text"] = @"text/plain";
|
||||
mimeToExtension[@"text/plain"] = @"diff"; extensionToMime[@"diff"] = @"text/plain";
|
||||
mimeToExtension[@"text/plain"] = @"po"; extensionToMime[@"po"] = @"text/plain"; // reserve "pot" for vnd.ms-powerpoint
|
||||
mimeToExtension[@"text/richtext"] = @"rtx"; extensionToMime[@"rtx"] = @"text/richtext";
|
||||
mimeToExtension[@"text/rtf"] = @"rtf"; extensionToMime[@"rtf"] = @"text/rtf";
|
||||
mimeToExtension[@"text/texmacs"] = @"ts"; extensionToMime[@"ts"] = @"text/texmacs";
|
||||
mimeToExtension[@"text/text"] = @"phps"; extensionToMime[@"phps"] = @"text/text";
|
||||
mimeToExtension[@"text/tab-separated-values"] = @"tsv"; extensionToMime[@"tsv"] = @"text/tab-separated-values";
|
||||
mimeToExtension[@"text/xml"] = @"xml"; extensionToMime[@"xml"] = @"text/xml";
|
||||
mimeToExtension[@"text/x-bibtex"] = @"bib"; extensionToMime[@"bib"] = @"text/x-bibtex";
|
||||
mimeToExtension[@"text/x-boo"] = @"boo"; extensionToMime[@"boo"] = @"text/x-boo";
|
||||
mimeToExtension[@"text/x-c++hdr"] = @"h++"; extensionToMime[@"h++"] = @"text/x-c++hdr";
|
||||
mimeToExtension[@"text/x-c++hdr"] = @"hpp"; extensionToMime[@"hpp"] = @"text/x-c++hdr";
|
||||
mimeToExtension[@"text/x-c++hdr"] = @"hxx"; extensionToMime[@"hxx"] = @"text/x-c++hdr";
|
||||
mimeToExtension[@"text/x-c++hdr"] = @"hh"; extensionToMime[@"hh"] = @"text/x-c++hdr";
|
||||
mimeToExtension[@"text/x-c++src"] = @"c++"; extensionToMime[@"c++"] = @"text/x-c++src";
|
||||
mimeToExtension[@"text/x-c++src"] = @"cpp"; extensionToMime[@"cpp"] = @"text/x-c++src";
|
||||
mimeToExtension[@"text/x-c++src"] = @"cxx"; extensionToMime[@"cxx"] = @"text/x-c++src";
|
||||
mimeToExtension[@"text/x-chdr"] = @"h"; extensionToMime[@"h"] = @"text/x-chdr";
|
||||
mimeToExtension[@"text/x-component"] = @"htc"; extensionToMime[@"htc"] = @"text/x-component";
|
||||
mimeToExtension[@"text/x-csh"] = @"csh"; extensionToMime[@"csh"] = @"text/x-csh";
|
||||
mimeToExtension[@"text/x-csrc"] = @"c"; extensionToMime[@"c"] = @"text/x-csrc";
|
||||
mimeToExtension[@"text/x-dsrc"] = @"d"; extensionToMime[@"d"] = @"text/x-dsrc";
|
||||
mimeToExtension[@"text/x-haskell"] = @"hs"; extensionToMime[@"hs"] = @"text/x-haskell";
|
||||
mimeToExtension[@"text/x-java"] = @"java"; extensionToMime[@"java"] = @"text/x-java";
|
||||
mimeToExtension[@"text/x-literate-haskell"] = @"lhs"; extensionToMime[@"lhs"] = @"text/x-literate-haskell";
|
||||
mimeToExtension[@"text/x-moc"] = @"moc"; extensionToMime[@"moc"] = @"text/x-moc";
|
||||
mimeToExtension[@"text/x-pascal"] = @"p"; extensionToMime[@"p"] = @"text/x-pascal";
|
||||
mimeToExtension[@"text/x-pascal"] = @"pas"; extensionToMime[@"pas"] = @"text/x-pascal";
|
||||
mimeToExtension[@"text/x-pcs-gcd"] = @"gcd"; extensionToMime[@"gcd"] = @"text/x-pcs-gcd";
|
||||
mimeToExtension[@"text/x-setext"] = @"etx"; extensionToMime[@"etx"] = @"text/x-setext";
|
||||
mimeToExtension[@"text/x-tcl"] = @"tcl"; extensionToMime[@"tcl"] = @"text/x-tcl";
|
||||
mimeToExtension[@"text/x-tex"] = @"tex"; extensionToMime[@"tex"] = @"text/x-tex";
|
||||
mimeToExtension[@"text/x-tex"] = @"ltx"; extensionToMime[@"ltx"] = @"text/x-tex";
|
||||
mimeToExtension[@"text/x-tex"] = @"sty"; extensionToMime[@"sty"] = @"text/x-tex";
|
||||
mimeToExtension[@"text/x-tex"] = @"cls"; extensionToMime[@"cls"] = @"text/x-tex";
|
||||
mimeToExtension[@"text/x-vcalendar"] = @"vcs"; extensionToMime[@"vcs"] = @"text/x-vcalendar";
|
||||
mimeToExtension[@"text/x-vcard"] = @"vcf"; extensionToMime[@"vcf"] = @"text/x-vcard";
|
||||
mimeToExtension[@"video/3gpp"] = @"3gpp"; extensionToMime[@"3gpp"] = @"video/3gpp";
|
||||
mimeToExtension[@"video/3gpp"] = @"3gp"; extensionToMime[@"3gp"] = @"video/3gpp";
|
||||
mimeToExtension[@"video/3gpp"] = @"3g2"; extensionToMime[@"3g2"] = @"video/3gpp";
|
||||
mimeToExtension[@"video/dl"] = @"dl"; extensionToMime[@"dl"] = @"video/dl";
|
||||
mimeToExtension[@"video/dv"] = @"dif"; extensionToMime[@"dif"] = @"video/dv";
|
||||
mimeToExtension[@"video/dv"] = @"dv"; extensionToMime[@"dv"] = @"video/dv";
|
||||
mimeToExtension[@"video/fli"] = @"fli"; extensionToMime[@"fli"] = @"video/fli";
|
||||
mimeToExtension[@"video/m4v"] = @"m4v"; extensionToMime[@"m4v"] = @"video/m4v";
|
||||
mimeToExtension[@"video/mpeg"] = @"mpeg"; extensionToMime[@"mpeg"] = @"video/mpeg";
|
||||
mimeToExtension[@"video/mpeg"] = @"mpg"; extensionToMime[@"mpg"] = @"video/mpeg";
|
||||
mimeToExtension[@"video/mpeg"] = @"mpe"; extensionToMime[@"mpe"] = @"video/mpeg";
|
||||
mimeToExtension[@"video/mp4"] = @"mp4"; extensionToMime[@"mp4"] = @"video/mp4";
|
||||
mimeToExtension[@"video/mpeg"] = @"VOB"; extensionToMime[@"VOB"] = @"video/mpeg";
|
||||
mimeToExtension[@"video/quicktime"] = @"qt"; extensionToMime[@"qt"] = @"video/quicktime";
|
||||
mimeToExtension[@"video/quicktime"] = @"mov"; extensionToMime[@"mov"] = @"video/quicktime";
|
||||
mimeToExtension[@"video/vnd.mpegurl"] = @"mxu"; extensionToMime[@"mxu"] = @"video/vnd.mpegurl";
|
||||
mimeToExtension[@"video/x-la-asf"] = @"lsf"; extensionToMime[@"lsf"] = @"video/x-la-asf";
|
||||
mimeToExtension[@"video/x-la-asf"] = @"lsx"; extensionToMime[@"lsx"] = @"video/x-la-asf";
|
||||
mimeToExtension[@"video/x-mng"] = @"mng"; extensionToMime[@"mng"] = @"video/x-mng";
|
||||
mimeToExtension[@"video/x-ms-asf"] = @"asf"; extensionToMime[@"asf"] = @"video/x-ms-asf";
|
||||
mimeToExtension[@"video/x-ms-asf"] = @"asx"; extensionToMime[@"asx"] = @"video/x-ms-asf";
|
||||
mimeToExtension[@"video/x-ms-wm"] = @"wm"; extensionToMime[@"wm"] = @"video/x-ms-wm";
|
||||
mimeToExtension[@"video/x-ms-wmv"] = @"wmv"; extensionToMime[@"wmv"] = @"video/x-ms-wmv";
|
||||
mimeToExtension[@"video/x-ms-wmx"] = @"wmx"; extensionToMime[@"wmx"] = @"video/x-ms-wmx";
|
||||
mimeToExtension[@"video/x-ms-wvx"] = @"wvx"; extensionToMime[@"wvx"] = @"video/x-ms-wvx";
|
||||
mimeToExtension[@"video/x-msvideo"] = @"avi"; extensionToMime[@"avi"] = @"video/x-msvideo";
|
||||
mimeToExtension[@"video/x-sgi-movie"] = @"movie"; extensionToMime[@"movie"] = @"video/x-sgi-movie";
|
||||
mimeToExtension[@"x-conference/x-cooltalk"] = @"ice"; extensionToMime[@"ice"] = @"x-conference/x-cooltalk";
|
||||
mimeToExtension[@"x-epoc/x-sisx-app"] = @"sisx"; extensionToMime[@"sisx"] = @"x-epoc/x-sisx-app";
|
||||
mimeToExtension[@"application/epub+zip"] = @"epub"; extensionToMime[@"epub"] = @"application/epub+zip";
|
||||
mimeToExtension[@"text/swift"] = @"swift"; extensionToMime[@"swift"] = @"text/swift";
|
||||
|
||||
mimeToExtensionMap = mimeToExtension;
|
||||
extensionToMimeMap = extensionToMime;
|
||||
});
|
||||
}
|
||||
|
||||
@implementation TGMimeTypeMap
|
||||
|
||||
+ (NSString *)mimeTypeForExtension:(NSString *)extension
|
||||
{
|
||||
if (extension == nil)
|
||||
return nil;
|
||||
|
||||
initializeMapping();
|
||||
|
||||
return extensionToMimeMap[extension];
|
||||
}
|
||||
|
||||
+ (NSString *)extensionForMimeType:(NSString *)mimeType
|
||||
{
|
||||
if (mimeType == nil)
|
||||
return nil;
|
||||
|
||||
initializeMapping();
|
||||
|
||||
return mimeToExtensionMap[mimeType];
|
||||
}
|
||||
|
||||
@end
|
||||
@ -3,6 +3,7 @@ import Intents
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import BuildConfig
|
||||
|
||||
private var accountCache: Account?
|
||||
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#ifndef SiriIntents_Bridging_Header_h
|
||||
#define SiriIntents_Bridging_Header_h
|
||||
|
||||
#import "../Telegram-iOS/BuildConfig.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "ReleaseAppStoreLLC"
|
||||
buildConfiguration = "DebugAppStoreLLC"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
|
||||
39
Telegram-iOS.xcworkspace/contents.xcworkspacedata
generated
@ -1,6 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:submodules/LightweightAccountData/LightweightAccountData_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/WatchCommon/WatchCommon_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/BuildConfig/BuildConfig_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/MediaPlayer/UniversalMediaPlayer_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/DeviceAccess/DeviceAccess_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramPresentationData/TelegramPresentationData_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramAudio/TelegramAudio_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramVoip/TelegramVoip_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramUIPreferences/TelegramUIPreferences_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/GZip/GZip_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/RMIntro/RMIntro_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramCallsUI/TelegramCallsUI_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/AsyncDisplayKit/AsyncDisplayKit_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
@ -16,6 +52,9 @@
|
||||
<FileRef
|
||||
location = "group:submodules/SSignalKit/SSignalKit_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramApi/TelegramApi_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/TelegramCore/TelegramCore_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
|
||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 8.1 KiB |
BIN
Telegram-iOS/BlackClassicIconIpad.png
Executable file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
Telegram-iOS/BlackClassicIconIpad@2x.png
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Telegram-iOS/BlackClassicIconLargeIpad@2x.png
Executable file
|
After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
Telegram-iOS/BlackFilledIconIpad@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 7.4 KiB |
0
Telegram-iOS/BlackIconIpad.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
0
Telegram-iOS/BlackIconIpad@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 6.2 KiB |
0
Telegram-iOS/BlackIconLargeIpad@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 6.3 KiB |
BIN
Telegram-iOS/BlueClassicIconIpad.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Telegram-iOS/BlueClassicIconIpad@2x.png
Executable file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Telegram-iOS/BlueClassicIconLargeIpad@2x.png
Executable file
|
After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 5.9 KiB |
BIN
Telegram-iOS/BlueIconIpad.png
Normal file → Executable file
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
Telegram-iOS/BlueIconIpad@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
Telegram-iOS/BlueIconLargeIpad@2x.png
Normal file → Executable file
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
@ -3,109 +3,109 @@
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@40x40-1.png",
|
||||
"filename" : "Simple@40x40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@60x60.png",
|
||||
"filename" : "Simple@60x60.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@58x58.png",
|
||||
"filename" : "Simple@58x58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@87x87.png",
|
||||
"filename" : "Simple@87x87.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@80x80.png",
|
||||
"filename" : "Simple@80x80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@120x120.png",
|
||||
"filename" : "BlueIcon@2x-1.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@120x120-1.png",
|
||||
"filename" : "BlueIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon1@180x180.png",
|
||||
"filename" : "BlueIcon@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@20x20.png",
|
||||
"filename" : "Simple@20x20.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@40x40.png",
|
||||
"filename" : "Simple@40x40-2.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@29x29.png",
|
||||
"filename" : "Simple@29x29.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@58x58-1.png",
|
||||
"filename" : "Simple@58x58-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@40x40-2.png",
|
||||
"filename" : "Simple@40x40-1.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@80x80-1.png",
|
||||
"filename" : "Simple@80x80-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@76x76.png",
|
||||
"filename" : "BlueIconIpad.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@152x152.png",
|
||||
"filename" : "BlueIconIpad@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon1@167x167.png",
|
||||
"filename" : "BlueIconLargeIpad@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon1-iTunesArtwork.png",
|
||||
"filename" : "Simple-iTunesArtwork.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 820 B |
|
Before Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 1022 B |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 800 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
@ -19,8 +19,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackIcon</string>
|
||||
<string>BlackIconIpad</string>
|
||||
<string>BlackIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -30,8 +28,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackClassicIcon</string>
|
||||
<string>BlackClassicIconIpad</string>
|
||||
<string>BlackClassicIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -41,8 +37,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackFilledIcon</string>
|
||||
<string>BlackFilledIconIpad</string>
|
||||
<string>BlackFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -52,8 +46,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueIcon</string>
|
||||
<string>BlueIconIpad</string>
|
||||
<string>BlueIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -63,8 +55,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueClassicIcon</string>
|
||||
<string>BlueClassicIconIpad</string>
|
||||
<string>BlueClassicIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -74,8 +64,6 @@
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueFilledIcon</string>
|
||||
<string>BlueFilledIconIpad</string>
|
||||
<string>BlueFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
@ -98,6 +86,88 @@
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundleIcons~ipad</key>
|
||||
<dict>
|
||||
<key>CFBundleAlternateIcons</key>
|
||||
<dict>
|
||||
<key>Black</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackIconIpad</string>
|
||||
<string>BlackIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackClassicIconIpad</string>
|
||||
<string>BlackClassicIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlackFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlackFilledIconIpad</string>
|
||||
<string>BlackFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>Blue</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueIconIpad</string>
|
||||
<string>BlueIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueClassic</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueClassicIconIpad</string>
|
||||
<string>BlueClassicIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>BlueFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>BlueFilledIconIpad</string>
|
||||
<string>BlueFilledIconLargeIpad</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>WhiteFilled</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>WhiteFilledIcon</string>
|
||||
</array>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundlePrimaryIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIconLLC</string>
|
||||
<key>UIPrerenderedIcon</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
struct AccountNotificationKey: Codable {
|
||||
let id: Data
|
||||
let data: Data
|
||||
}
|
||||
|
||||
struct AccountDatacenterKey: Codable {
|
||||
let id: Int64
|
||||
let data: Data
|
||||
}
|
||||
|
||||
struct AccountDatacenterAddress: Codable {
|
||||
let host: String
|
||||
let port: Int32
|
||||
let isMedia: Bool
|
||||
let secret: Data?
|
||||
}
|
||||
|
||||
struct AccountDatacenterInfo: Codable {
|
||||
let masterKey: AccountDatacenterKey
|
||||
let addressList: [AccountDatacenterAddress]
|
||||
}
|
||||
|
||||
struct AccountProxyConnection: Codable {
|
||||
let host: String
|
||||
let port: Int32
|
||||
let username: String?
|
||||
let password: String?
|
||||
let secret: Data?
|
||||
}
|
||||
|
||||
struct StoredAccountInfo: Codable {
|
||||
let id: Int64
|
||||
let primaryId: Int32
|
||||
let isTestingEnvironment: Bool
|
||||
let peerName: String
|
||||
let datacenters: [Int32: AccountDatacenterInfo]
|
||||
let notificationKey: AccountNotificationKey
|
||||
}
|
||||
|
||||
struct StoredAccountInfos: Codable {
|
||||
let proxy: AccountProxyConnection?
|
||||
let accounts: [StoredAccountInfo]
|
||||
}
|
||||
|
||||
func loadAccountsData(rootPath: String) -> StoredAccountInfos {
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: rootPath + "/accounts-shared-data")) else {
|
||||
return StoredAccountInfos(proxy: nil, accounts: [])
|
||||
}
|
||||
guard let value = try? JSONDecoder().decode(StoredAccountInfos.self, from: data) else {
|
||||
return StoredAccountInfos(proxy: nil, accounts: [])
|
||||
}
|
||||
return value
|
||||
}
|
||||
@ -1,34 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramUI
|
||||
|
||||
func snapshotAppearanceSettings(application: UIApplication, mainWindow: UIWindow, window: Window1, statusBarHost: StatusBarHost) {
|
||||
let (context, accountManager) = snapshotEnvironment(application: application, mainWindow: mainWindow, statusBarHost: statusBarHost, theme: .day)
|
||||
context.account.network.mockConnectionStatus = .online(proxyAddress: nil)
|
||||
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
if let hole = context.account.postbox.seedConfiguration.initializeChatListWithHole.topLevel {
|
||||
transaction.replaceChatListHole(groupId: .root, index: hole.index, hole: nil)
|
||||
}
|
||||
|
||||
let accountPeer = TelegramUser(id: context.account.peerId, accessHash: nil, firstName: "Alena", lastName: "Shy", username: "alenashy", phone: "44321456789", photo: snapshotAvatar(context.account.postbox, 1), botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
transaction.updatePeersInternal([accountPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}).start()
|
||||
|
||||
let rootController = TelegramRootController(context: context)
|
||||
rootController.addRootControllers(showCallsTab: true)
|
||||
window.viewController = rootController
|
||||
rootController.rootTabController!.selectedIndex = 3
|
||||
rootController.pushViewController(themeSettingsController(context: context))
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,155 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramUI
|
||||
|
||||
private enum SnapshotPeerAvatar {
|
||||
case none
|
||||
case id(Int32)
|
||||
}
|
||||
|
||||
private func avatarImages(_ postbox: Postbox, _ value: SnapshotPeerAvatar) -> [TelegramMediaImageRepresentation] {
|
||||
switch value {
|
||||
case .none:
|
||||
return []
|
||||
case let .id(id):
|
||||
return snapshotAvatar(postbox, id)
|
||||
}
|
||||
}
|
||||
|
||||
private enum SnapshotPeer {
|
||||
case user(Int32, SnapshotPeerAvatar, String?, String?)
|
||||
case secretChat(Int32, Int32, SnapshotPeerAvatar, String?, String?)
|
||||
case channel(Int32, SnapshotPeerAvatar, String)
|
||||
|
||||
func additionalPeer(_ postbox: Postbox) -> Peer? {
|
||||
switch self {
|
||||
case .user:
|
||||
return nil
|
||||
case let .secretChat(_, userId, avatar, first, last):
|
||||
return TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), accessHash: nil, firstName: first, lastName: last, username: nil, phone: nil, photo: avatarImages(postbox, avatar), botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
case .channel:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var peerId: PeerId {
|
||||
switch self {
|
||||
case let .user(id, _, _, _):
|
||||
return PeerId(namespace: Namespaces.Peer.CloudUser, id: id)
|
||||
case let .secretChat(id, _, _, _, _):
|
||||
return PeerId(namespace: Namespaces.Peer.SecretChat, id: id)
|
||||
case let .channel(id, _, _):
|
||||
return PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)
|
||||
}
|
||||
}
|
||||
|
||||
func peer(_ postbox: Postbox) -> Peer {
|
||||
switch self {
|
||||
case let .user(id, avatar, first, last):
|
||||
return TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: id), accessHash: nil, firstName: first, lastName: last, username: nil, phone: nil, photo: avatarImages(postbox, avatar), botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
case let .secretChat(id, userId, _, _, _):
|
||||
return TelegramSecretChat(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: id), creationDate: 123, regularPeerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: userId), accessHash: 123, role: .creator, embeddedState: .active, messageAutoremoveTimeout: nil)
|
||||
case let .channel(id, avatar, title):
|
||||
return TelegramChannel(id: PeerId(namespace: Namespaces.Peer.CloudChannel, id: id), accessHash: 123, title: title, username: nil, photo: avatarImages(postbox, avatar), creationDate: 123, version: 0, participationStatus: .member, info: .broadcast(TelegramChannelBroadcastInfo(flags: [])), flags: [], restrictionInfo: nil, adminRights: nil, bannedRights: nil, defaultBannedRights: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct SnapshotMessage {
|
||||
let date: Int32
|
||||
let peer: SnapshotPeer
|
||||
let text: String
|
||||
let outgoing: Bool
|
||||
|
||||
init(_ date: Int32, _ peer: SnapshotPeer, _ text: String, _ outgoing: Bool) {
|
||||
self.date = date
|
||||
self.peer = peer
|
||||
self.text = text
|
||||
self.outgoing = outgoing
|
||||
}
|
||||
|
||||
func storeMessage(_ accountPeerId: PeerId, _ baseDate: Int32) -> StoreMessage {
|
||||
var flags: StoreMessageFlags = []
|
||||
if !self.outgoing {
|
||||
flags.insert(.Incoming)
|
||||
}
|
||||
return StoreMessage(id: MessageId(peerId: self.peer.peerId, namespace: Namespaces.Message.Cloud, id: self.date), globallyUniqueId: nil, groupingKey: nil, timestamp: baseDate + self.date, flags: flags, tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: outgoing ? accountPeerId : self.peer.peerId, text: self.text, attributes: [], media: [])
|
||||
}
|
||||
}
|
||||
|
||||
private struct SnapshotChat {
|
||||
let message: SnapshotMessage
|
||||
let unreadCount: Int32
|
||||
let isPinned: Bool
|
||||
let isMuted: Bool
|
||||
|
||||
init(_ message: SnapshotMessage, unreadCount: Int32 = 0, isPinned: Bool = false, isMuted: Bool = false) {
|
||||
self.message = message
|
||||
self.unreadCount = unreadCount
|
||||
self.isPinned = isPinned
|
||||
self.isMuted = isMuted
|
||||
}
|
||||
}
|
||||
|
||||
private let chatList: [SnapshotChat] = [
|
||||
.init(.init(100, .user(1, .id(7), "Jane", ""), "Well I do help animals. Maybe I'll have a few cats in my new luxury apartment. 😊", false), isPinned: true),
|
||||
.init(.init(90, .user(3, .none, "Tyrion", "Lannister"), "Sometimes posession is an abstract concept. They took my purse, but the gold is still mine.", false), unreadCount: 1),
|
||||
.init(.init(80, .user(2, .id(1), "Alena", "Shy"), "😍 Sticker", true)),
|
||||
.init(.init(70, .secretChat(4, 4, .id(8), "Heisenberg", ""), "Thanks, Telegram helps me a lot. You have my financial support if you need more servers.", false)),
|
||||
.init(.init(60, .user(5, .id(9), "Bender", ""), "I looove new iPhones! In fact, they invited me to a focus group.", false)),
|
||||
.init(.init(50, .channel(6, .id(10), "World News Today"), "LaserBlastSafetyGuide.pdf", false), unreadCount: 1, isMuted: true),
|
||||
.init(.init(40, .user(7, .id(11), "EVE", ""), "LaserBlastSafetyGuide.pdf", true)),
|
||||
.init(.init(30, .user(8, .id(12), "Nick", ""), "It's impossible", false))
|
||||
]
|
||||
|
||||
func snapshotChatList(application: UIApplication, mainWindow: UIWindow, window: Window1, statusBarHost: StatusBarHost) {
|
||||
let (context, _) = snapshotEnvironment(application: application, mainWindow: mainWindow, statusBarHost: statusBarHost, theme: .night)
|
||||
context.account.network.mockConnectionStatus = .online(proxyAddress: nil)
|
||||
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
if let hole = context.account.postbox.seedConfiguration.initializeChatListWithHole.topLevel {
|
||||
transaction.replaceChatListHole(groupId: .root, index: hole.index, hole: nil)
|
||||
}
|
||||
|
||||
let accountPeer = TelegramUser(id: context.account.peerId, accessHash: nil, firstName: "Alena", lastName: "Shy", username: "alenashy", phone: "44321456789", photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
transaction.updatePeersInternal([accountPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
|
||||
let baseDate: Int32 = Int32(Date().timeIntervalSince1970) - 10000
|
||||
for item in chatList {
|
||||
let peer = item.message.peer.peer(context.account.postbox)
|
||||
|
||||
transaction.updatePeersInternal([peer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
if let additionalPeer = item.message.peer.additionalPeer(context.account.postbox) {
|
||||
transaction.updatePeersInternal([additionalPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}
|
||||
transaction.updatePeerChatListInclusion(peer.id, inclusion: .ifHasMessagesOrOneOf(groupId: .root, pinningIndex: nil, minTimestamp: nil))
|
||||
let _ = transaction.addMessages([item.message.storeMessage(context.account.peerId, baseDate)], location: .UpperHistoryBlock)
|
||||
transaction.resetIncomingReadStates([peer.id: [Namespaces.Message.Cloud: .idBased(maxIncomingReadId: Int32.max - 1, maxOutgoingReadId: Int32.max - 1, maxKnownId: Int32.max - 1, count: item.unreadCount, markedUnread: false)]])
|
||||
if item.isMuted {
|
||||
transaction.updateCurrentPeerNotificationSettings([peer.id: TelegramPeerNotificationSettings.defaultSettings.withUpdatedMuteState(.muted(until: Int32.max - 1))])
|
||||
} else {
|
||||
transaction.updateCurrentPeerNotificationSettings([peer.id: TelegramPeerNotificationSettings.defaultSettings])
|
||||
}
|
||||
}
|
||||
transaction.setPinnedItemIds(groupId: .root, itemIds: chatList.filter{ $0.isPinned }.map{ .peer($0.message.peer.peerId) })
|
||||
}).start()
|
||||
|
||||
let rootController = TelegramRootController(context: context)
|
||||
rootController.addRootControllers(showCallsTab: true)
|
||||
window.viewController = rootController
|
||||
rootController.rootTabController!.selectedIndex = 0
|
||||
rootController.rootTabController!.selectedIndex = 2
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,115 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramUI
|
||||
import Display
|
||||
|
||||
enum SnapshotEnvironmentTheme {
|
||||
case night
|
||||
case day
|
||||
}
|
||||
|
||||
func snapshotEnvironment(application: UIApplication, mainWindow: UIWindow, statusBarHost: StatusBarHost, theme: SnapshotEnvironmentTheme) -> (AccountContext, AccountManager) {
|
||||
preconditionFailure()
|
||||
/*var randomId: Int64 = 0
|
||||
arc4random_buf(&randomId, 8)
|
||||
let path = NSTemporaryDirectory() + "\(randomId)"
|
||||
|
||||
Logger.setSharedLogger(Logger(basePath: path + "/logs"))
|
||||
Logger.shared.logToFile = false
|
||||
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
var accountManagerValue: AccountManager?
|
||||
initializeAccountManagement()
|
||||
let _ = accountManager(basePath: path).start(next: { value in
|
||||
accountManagerValue = value
|
||||
semaphore.signal()
|
||||
})
|
||||
semaphore.wait()
|
||||
precondition(accountManagerValue != nil)
|
||||
|
||||
var result: Account?
|
||||
while true {
|
||||
let account = currentAccount(allocateIfNotExists: true, networkArguments: NetworkInitializationArguments(apiId: 0, languagesCategory: "ios", appVersion: "unknown", voipMaxLayer: 0), supplementary: false, manager: accountManagerValue!, rootPath: path, auxiliaryMethods: AccountAuxiliaryMethods(updatePeerChatInputState: { _, _ in return nil }, fetchResource: { _, _, _, _ in
|
||||
return .never()
|
||||
}, fetchResourceMediaReferenceHash: { _ in
|
||||
return .never()
|
||||
}, prepareSecretThumbnailData: { _ in
|
||||
return nil
|
||||
})) |> take(1)
|
||||
let semaphore = DispatchSemaphore(value: 0)
|
||||
let _ = account.start(next: { value in
|
||||
switch value! {
|
||||
case .upgrading:
|
||||
preconditionFailure()
|
||||
case let .unauthorized(account):
|
||||
let _ = account.postbox.transaction({ transaction -> Void in
|
||||
let encoder = PostboxEncoder()
|
||||
encoder.encodeInt32(1, forKey: "masterDatacenterId")
|
||||
encoder.encodeInt64(PeerId(namespace: Namespaces.Peer.CloudUser, id: 1234567).toInt64(), forKey: "peerId")
|
||||
|
||||
transaction.setState(AuthorizedAccountState(decoder: PostboxDecoder(buffer: encoder.readBufferNoCopy())))
|
||||
}).start()
|
||||
case let .authorized(account):
|
||||
result = account
|
||||
}
|
||||
semaphore.signal()
|
||||
})
|
||||
semaphore.wait()
|
||||
if result != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: true, containerPath: path, appSpecificScheme: "tg", openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
completion.completion(false)
|
||||
}, canOpenUrl: { _ in
|
||||
return false
|
||||
}, getTopWindow: {
|
||||
for window in application.windows.reversed() {
|
||||
if window === mainWindow || window === statusBarHost.keyboardWindow {
|
||||
return window
|
||||
}
|
||||
}
|
||||
return application.windows.last
|
||||
}, displayNotification: { _ in
|
||||
}, applicationInForeground: .single(true), applicationIsActive: .single(true), clearMessageNotifications: { _ in
|
||||
}, pushIdleTimerExtension: {
|
||||
return EmptyDisposable
|
||||
}, openSettings: {
|
||||
}, openAppStorePage: {
|
||||
}, registerForNotifications: { _ in
|
||||
}, requestSiriAuthorization: { _ in }, siriAuthorization: { return .notDetermined }, getWindowHost: {
|
||||
return nil
|
||||
}, presentNativeController: { _ in
|
||||
}, dismissNativeController: {
|
||||
})
|
||||
|
||||
let _ = updatePresentationThemeSettingsInteractively(postbox: result!.postbox, { _ in
|
||||
switch theme {
|
||||
case .day:
|
||||
return PresentationThemeSettings(chatWallpaper: .color(0xffffff), theme: .builtin(.day), themeAccentColor: nil, themeSpecificChatWallpapers: [:], fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent), disableAnimations: false)
|
||||
case .night:
|
||||
return PresentationThemeSettings(chatWallpaper: .color(0x000000), theme: .builtin(.nightAccent), themeAccentColor: nil, themeSpecificChatWallpapers: [:], fontSize: .regular, automaticThemeSwitchSetting: AutomaticThemeSwitchSetting(trigger: .none, theme: .nightAccent), disableAnimations: false)
|
||||
}
|
||||
}).start()
|
||||
|
||||
let semaphore1 = DispatchSemaphore(value: 0)
|
||||
var dataAndSettings: InitialPresentationDataAndSettings?
|
||||
let _ = currentPresentationDataAndSettings(postbox: result!.postbox).start(next: { value in
|
||||
dataAndSettings = value
|
||||
semaphore1.signal()
|
||||
})
|
||||
semaphore1.wait()
|
||||
precondition(dataAndSettings != nil)
|
||||
|
||||
let context = AccountContext(sharedContext: SharedAccountContext(applicationBindings: applicationBindings, accountManager: accountManagerValue!), account: result!, initialPresentationDataAndSettings: dataAndSettings!)
|
||||
|
||||
return (context, accountManagerValue!)*/
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,32 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
|
||||
private var dataPath: String?
|
||||
|
||||
func setupSnapshotData(_ path: String) {
|
||||
dataPath = path
|
||||
}
|
||||
|
||||
func snapshotAvatar(_ postbox: Postbox, _ id: Int32) -> [TelegramMediaImageRepresentation] {
|
||||
guard let path = dataPath else {
|
||||
return []
|
||||
}
|
||||
|
||||
guard let data = try? Data(contentsOf: URL(fileURLWithPath: path + "/Bitmap\(id).png")) else {
|
||||
return []
|
||||
}
|
||||
if let image = UIImage(data: data) {
|
||||
let resource = LocalFileMediaResource(fileId: arc4random64(), size: data.count)
|
||||
|
||||
postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
return [TelegramMediaImageRepresentation(dimensions: image.size, resource: resource)]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,75 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramUI
|
||||
|
||||
private enum SnapshotMessage {
|
||||
case text(String, Bool)
|
||||
case timer(Int32, Bool)
|
||||
|
||||
func storeMessage(_ postbox: Postbox, peerId: PeerId, userPeerId: PeerId, accountPeerId: PeerId, _ date: Int32) -> StoreMessage {
|
||||
switch self {
|
||||
case let .text(text, outgoing):
|
||||
var flags: StoreMessageFlags = []
|
||||
if !outgoing {
|
||||
flags.insert(.Incoming)
|
||||
}
|
||||
return StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: date), globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: flags, tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: outgoing ? accountPeerId : userPeerId, text: text, attributes: [], media: [])
|
||||
case let .timer(timeout, outgoing):
|
||||
var flags: StoreMessageFlags = []
|
||||
if !outgoing {
|
||||
flags.insert(.Incoming)
|
||||
}
|
||||
return StoreMessage(id: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: date), globallyUniqueId: nil, groupingKey: nil, timestamp: date, flags: flags, tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: outgoing ? accountPeerId : userPeerId, text: "", attributes: [], media: [TelegramMediaAction(action: .messageAutoremoveTimeoutUpdated(timeout))])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private let messages: [SnapshotMessage] = [
|
||||
.text("Hey Eileen", true),
|
||||
.text("So, why is Telegram cool?", true),
|
||||
.text("Well, look. Telegram is superfast and you can use it on all your devices at the same time — phones, tablets, even desktops.", false),
|
||||
.text("😴", true),
|
||||
.text("And it has secret chats, like this one, with end-to-end encryption!", false),
|
||||
.text("End encryption to what end??", true),
|
||||
.text("Arrgh. Forget it. You can set a timer and send photos that will disappear when the time runs out. Yay!", false),
|
||||
.timer(15, false)
|
||||
]
|
||||
|
||||
func snapshotSecretChat(application: UIApplication, mainWindow: UIWindow, window: Window1, statusBarHost: StatusBarHost) {
|
||||
let (context, _) = snapshotEnvironment(application: application, mainWindow: mainWindow, statusBarHost: statusBarHost, theme: .night)
|
||||
context.account.network.mockConnectionStatus = .online(proxyAddress: nil)
|
||||
|
||||
let accountPeer = TelegramUser(id: context.account.peerId, accessHash: nil, firstName: "Alena", lastName: "Shy", username: "alenashy", phone: "44321456789", photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let userPeer = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 456), accessHash: nil, firstName: "Eileen", lastName: "Lockhard", username: nil, phone: "44321456789", photo: snapshotAvatar(context.account.postbox, 6), botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
let secretPeer = TelegramSecretChat(id: PeerId(namespace: Namespaces.Peer.SecretChat, id: 456), creationDate: 123, regularPeerId: userPeer.id, accessHash: 123, role: .creator, embeddedState: .active, messageAutoremoveTimeout: nil)
|
||||
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
if let hole = context.account.postbox.seedConfiguration.initializeChatListWithHole.topLevel {
|
||||
transaction.replaceChatListHole(groupId: .root, index: hole.index, hole: nil)
|
||||
}
|
||||
|
||||
transaction.updatePeersInternal([accountPeer, userPeer, secretPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
|
||||
transaction.updatePeerPresencesInternal(presences: [userPeer.id: TelegramUserPresence(status: .present(until: Int32.max - 1), lastActivity: 0)], merge: { _, updated in return updated })
|
||||
|
||||
var date: Int32 = Int32(Date().timeIntervalSince1970) - 1000
|
||||
for message in messages {
|
||||
let _ = transaction.addMessages([message.storeMessage(context.account.postbox, peerId: secretPeer.id, userPeerId: userPeer.id, accountPeerId: context.account.peerId, date)], location: .UpperHistoryBlock)
|
||||
date += 10
|
||||
}
|
||||
}).start()
|
||||
|
||||
let rootController = TelegramRootController(context: context)
|
||||
rootController.addRootControllers(showCallsTab: true)
|
||||
window.viewController = rootController
|
||||
navigateToChatController(navigationController: rootController, context: context, chatLocation: .peer(secretPeer.id), animated: false)
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -1,33 +0,0 @@
|
||||
#if DEBUG
|
||||
|
||||
import Foundation
|
||||
import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import Display
|
||||
import TelegramUI
|
||||
|
||||
func snapshotSettings(application: UIApplication, mainWindow: UIWindow, window: Window1, statusBarHost: StatusBarHost) {
|
||||
let (context, accountManager) = snapshotEnvironment(application: application, mainWindow: mainWindow, statusBarHost: statusBarHost, theme: .night)
|
||||
context.account.network.mockConnectionStatus = .online(proxyAddress: nil)
|
||||
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
if let hole = context.account.postbox.seedConfiguration.initializeChatListWithHole.topLevel {
|
||||
transaction.replaceChatListHole(groupId: .root, index: hole.index, hole: nil)
|
||||
}
|
||||
|
||||
let accountPeer = TelegramUser(id: context.account.peerId, accessHash: nil, firstName: "Alena", lastName: "Shy", username: "alenashy", phone: "44321456789", photo: snapshotAvatar(context.account.postbox, 1), botInfo: nil, restrictionInfo: nil, flags: [])
|
||||
transaction.updatePeersInternal([accountPeer], update: { _, updated in
|
||||
return updated
|
||||
})
|
||||
}).start()
|
||||
|
||||
let rootController = TelegramRootController(context: context)
|
||||
rootController.addRootControllers(showCallsTab: true)
|
||||
window.viewController = rootController
|
||||
rootController.rootTabController!.selectedIndex = 3
|
||||
rootController.pushViewController(settingsController(context: context, accountManager: accountManager))
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,17 +1,4 @@
|
||||
#ifndef Telegram_iOS_Telegram_Bridging_Header_h
|
||||
#define Telegram_iOS_Telegram_Bridging_Header_h
|
||||
|
||||
#import "BuildConfig.h"
|
||||
#import "TGAutoDownloadPreferences.h"
|
||||
#import "TGPresentationAutoNightPreferences.h"
|
||||
#import "TGProxyItem.h"
|
||||
#import "UIImage+ImageEffects.h"
|
||||
|
||||
#import "TGBridgeServer.h"
|
||||
#import "TGBridgeCommon.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeChat.h"
|
||||
#import "TGBridgeUser.h"
|
||||
#import "TGBridgeLocationVenue.h"
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, @"Application", @"AppDelegate");
|
||||
}
|
||||
}
|
||||
@ -1,32 +0,0 @@
|
||||
import Foundation
|
||||
import AsyncDisplayKit
|
||||
import MtProtoKit
|
||||
import SwiftSignalKit
|
||||
import SSignalKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import LegacyComponents
|
||||
import HockeySDK
|
||||
import Lottie
|
||||
import WebP
|
||||
import FFMpeg
|
||||
import TelegramUIPrivateModule
|
||||
|
||||
func test() {
|
||||
let _ = ASDisplayNode()
|
||||
let _ = MTProto()
|
||||
let _ = Signal<Never, NoError> { subscriber in
|
||||
return ActionDisposable {
|
||||
}
|
||||
}
|
||||
let _ = SSignal(generator: { subscriber in
|
||||
return SBlockDisposable {
|
||||
}
|
||||
})
|
||||
let _ = ListView()
|
||||
let _ = SqliteValueBox(basePath: "", queue: .mainQueue(), encryptionParameters: nil, upgradeProgress: { _ in }, inMemory: true)
|
||||
initializeAccountManagement()
|
||||
BITHockeyManager.shared().crashManager.crashManagerStatus = .alwaysAsk
|
||||
let _ = LOTComposition(json: [:])
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 4.1 KiB |
@ -1532,7 +1532,7 @@
|
||||
"Forward.ChannelReadOnly" = "Sorry, you can't post to this channel.";
|
||||
|
||||
"Channel.ErrorAccessDenied" = "Sorry, this channel is private.";
|
||||
"Group.ErrorAccessDenied" = "Sorry, this channel is private.";
|
||||
"Group.ErrorAccessDenied" = "Sorry, this group is private.";
|
||||
"Conversation.InputTextBroadcastPlaceholder" = "Broadcast";
|
||||
|
||||
"Channel.NotificationLoading" = "Loading...";
|
||||
@ -1614,7 +1614,10 @@
|
||||
"ShareMenu.Send" = "Send";
|
||||
|
||||
"Conversation.ReportSpam" = "Report Spam";
|
||||
"Conversation.ReportSpamAndLeave" = "Report Spam and Leave";
|
||||
"Conversation.ReportSpamConfirmation" = "Are you sure you want to report spam from this user?";
|
||||
"Conversation.ReportSpamGroupConfirmation" = "Are you sure you want to report spam from this group?";
|
||||
"Conversation.ReportSpamChannelConfirmation" = "Are you sure you want to report spam from this channel?";
|
||||
"SharedMedia.EmptyMusicText" = "All music shared in this chat will appear here.";
|
||||
|
||||
"ChatSettings.AutoPlayAnimations" = "Autoplay GIFs";
|
||||
@ -4348,6 +4351,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Appearance.ThemeCarouselNight" = "Monochrome";
|
||||
|
||||
"Notification.Exceptions.DeleteAll" = "Delete All";
|
||||
"Notification.Exceptions.DeleteAllConfirmation" = "Are you sure you want to delete all exceptions?";
|
||||
"Notification.Exceptions.Add" = "Add";
|
||||
"Exceptions.AddToExceptions" = "ADD TO EXCEPTIONS";
|
||||
|
||||
@ -4358,11 +4362,13 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Conversation.Block" = "Block";
|
||||
"Conversation.BlockUser" = "Block User";
|
||||
"Conversation.ShareMyPhoneNumber" = "Share My Phone Number";
|
||||
"Conversation.ShareMyPhoneNumberConfirmation" = "Are you sure you want to share your phone number %1$@ with %2$@?";
|
||||
"Conversation.AddToContacts" = "Add to Contacts";
|
||||
"Conversation.AddNameToContacts" = "Add %@ to Contacts";
|
||||
|
||||
"AddContact.ContactWillBeSharedNow" = "When you tap **Done**, your phone number will become visible to %@.";
|
||||
"AddContact.ContactWillBeSharedAfterMutual" = "Phone number will be visible once %1$@ adds you as a contact. Your phone number will become visible to %1$@.";
|
||||
"AddContact.ContactWillBeSharedAfterMutual" = "Phone number will be visible once %1$@ adds you as a contact.";
|
||||
"AddContact.SharedContactException" = "Share My Phone Number";
|
||||
"AddContact.SharedContactExceptionInfo" = "You can make your phone visible to %@.";
|
||||
"AddContact.StatusSuccess" = "%@ is now in your contacts list.";
|
||||
"Conversation.ShareMyPhoneNumber.StatusSuccess" = "%@ can now see your phone number.";
|
||||
|
||||
@ -4381,6 +4387,7 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Channel.OwnershipTransfer.ChangeOwner" = "Change Owner";
|
||||
|
||||
"Channel.OwnershipTransfer.ErrorPublicChannelsTooMuch" = "Sorry, the target user has too many public groups or channels already. Please ask them to make one of their existing groups or channels private first.";
|
||||
"Group.OwnershipTransfer.ErrorLocatedGroupsTooMuch" = "Sorry, the target user has too many location-based groups already. Please ask them to delete or transfer one of their existing ones first.";
|
||||
|
||||
"Group.OwnershipTransfer.ErrorAdminsTooMuch" = "Sorry, this group has too many admins and the new owner can't be added. Please remove one of the existing admins first.";
|
||||
"Channel.OwnershipTransfer.ErrorAdminsTooMuch" = "Sorry, this channel has too many admins and the new owner can't be added. Please remove one of the existing admins first.";
|
||||
@ -4397,15 +4404,53 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Contacts.AddPeopleNearby" = "Add People Nearby";
|
||||
|
||||
"PeopleNearby.Title" = "People Nearby";
|
||||
"PeopleNearby.Description" = "Use this section to quickly find people and groups near you.";
|
||||
"PeopleNearby.Users" = "People Around You";
|
||||
"PeopleNearby.UsersEmpty" = "No one else is viewing \"People Nearby\" around you now";
|
||||
"PeopleNearby.Groups" = "Groups Around You";
|
||||
"PeopleNearby.CreateGroup" = "Start a Group Chat Here";
|
||||
"PeopleNearby.Channels" = "Channels Around You";
|
||||
"PeopleNearby.Description" = "Ask your friend nearby to open this page to exchange phone numbers.";
|
||||
"PeopleNearby.Users" = "People Nearby";
|
||||
"PeopleNearby.UsersEmpty" = "Looking for users around you...";
|
||||
"PeopleNearby.Groups" = "Groups Nearby";
|
||||
"PeopleNearby.CreateGroup" = "Create a Group Here";
|
||||
"PeopleNearby.NoMembers" = "no members";
|
||||
|
||||
"Channel.Management.LabelOwner" = "Owner";
|
||||
"Channel.Management.LabelAdministrator" = "Administrator";
|
||||
"ContactInfo.PhoneNumberHidden" = "Hidden";
|
||||
|
||||
"Common.ActionNotAllowedError" = "Sorry, you are not allowed to do this.";
|
||||
|
||||
"Group.Location.Title" = "Location";
|
||||
"Group.Location.ChangeLocation" = "Change Location";
|
||||
"Group.Location.Info" = "People can find your group using People Nearby section.";
|
||||
|
||||
"Channel.AdminLog.MessageTransferedName" = "transferred ownership to %1$@";
|
||||
"Channel.AdminLog.MessageTransferedNameUsername" = "transferred ownership to %1$@ (%2$@)";
|
||||
|
||||
"Channel.AdminLog.MessageChangedGroupGeoLocation" = "changed group location to \"%@\"";
|
||||
|
||||
"Map.SetThisLocation" = "Set This Location";
|
||||
|
||||
"Permissions.PeopleNearbyTitle.v0" = "People Nearby";
|
||||
"Permissions.PeopleNearbyText.v0" = "Use this section to quickly add people near you and discover nearby group chats.\n\nPlease allow location access\nto start using this feature.";
|
||||
"Permissions.PeopleNearbyAllow.v0" = "Allow Access";
|
||||
"Permissions.PeopleNearbyAllowInSettings.v0" = "Allow in Settings";
|
||||
|
||||
"Conversation.ReportGroupLocation" = "Group unrelated to location?";
|
||||
"ReportGroupLocation.Title" = "Report Unrelated Group";
|
||||
"ReportGroupLocation.Text" = "Please tell us if this group is not related to this location.";
|
||||
"ReportGroupLocation.Report" = "Report";
|
||||
|
||||
"LocalGroup.Title" = "Create a Local Group";
|
||||
"LocalGroup.Text" = "Anyone close to this location (neighbors, co-workers, fellow students, event attendees, visitors of a venue) will see your group in the People Nearby section.";
|
||||
"LocalGroup.ButtonTitle" = "Start Group";
|
||||
"LocalGroup.IrrelevantWarning" = "If you start an unrelated group at this location, you may get restricted in creating new location-based groups.";
|
||||
|
||||
"GroupInfo.Location" = "Location";
|
||||
"GroupInfo.PublicLink" = "Public Link";
|
||||
"GroupInfo.PublicLinkAdd" = "Add";
|
||||
|
||||
"Group.PublicLink.Title" = "Public Link";
|
||||
"Group.PublicLink.Placeholder" = "link";
|
||||
"Group.PublicLink.Info" = "People can share this link with others and find your group using Telegram search.\n\nYou can use **a-z**, **0-9** and underscores. Minimum length is **5** characters.";
|
||||
|
||||
"CreateGroup.ErrorLocatedGroupsTooMuch" = "Sorry, you have too many location-based groups already. Please delete one of your existing ones first.";
|
||||
|
||||
"GroupInfo.LabelOwner" = "owner";
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#import "TGBridgeAudioSignals.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeAudioMediaAttachment.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
#import "TGFileCache.h"
|
||||
|
||||
#import "TGBridgeMessage.h"
|
||||
|
||||
#import "TGExtensionDelegate.h"
|
||||
#import <libkern/OSAtomic.h>
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#import "TGBridgeBotSignals.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeUserCache.h"
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
|
||||
#import "TGBridgeUser.h"
|
||||
#import "TGBridgeBotInfo.h"
|
||||
|
||||
@implementation TGBridgeBotSignals
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#import "TGBridgeChat.h"
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "WKInterfaceTable+TGDataDrivenTable.h"
|
||||
|
||||
@interface TGBridgeChat (TGTableItem) <TGTableItem>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#import "TGBridgeChatListSignals.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeChat.h"
|
||||
#import "TGBridgeUser.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
|
||||
@implementation TGBridgeChatListSignals
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#import "TGBridgeChatMessageListSignals.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeMessage.h"
|
||||
#import "TGBridgeUser.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
|
||||
@implementation TGBridgeChatMessageListSignals
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
#import "TGBridgeClient.h"
|
||||
#import "TGBridgeCommon.h"
|
||||
#import "TGBridgeChat.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGWatchCommon.h"
|
||||
|
||||
#import <WatchConnectivity/WatchConnectivity.h>
|
||||
|
||||
#import "TGBridgeContext.h"
|
||||
#import "TGFileCache.h"
|
||||
|
||||
#import "TGBridgeStickersSignals.h"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#import "TGBridgeContactsSignals.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeUser.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
|
||||
@implementation TGBridgeContactsSignals
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#import "TGBridgeConversationSignals.h"
|
||||
#import "TGBridgeSubscriptions.h"
|
||||
#import "TGBridgeChat.h"
|
||||
#import "TGBridgeUser.h"
|
||||
|
||||
#import <WatchCommonWatch/WatchCommonWatch.h>
|
||||
|
||||
#import "TGBridgeClient.h"
|
||||
|
||||
@implementation TGBridgeConversationSignals
|
||||
|
||||