Swiftgram/Widget/TodayViewController.swift
2018-12-18 08:34:14 +03:00

258 lines
9.5 KiB
Swift

import UIKit
import TelegramCore
import SwiftSignalKit
import Postbox
import NotificationCenter
private var accountCache: Account?
private var installedSharedLogger = false
private func setupSharedLogger(_ path: String) {
if !installedSharedLogger {
installedSharedLogger = true
Logger.setSharedLogger(Logger(basePath: path))
}
}
private let auxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { _, _ in
return nil
}, fetchResource: { _, _, _, _ in
return nil
}, fetchResourceMediaReferenceHash: { _ in
return .single(nil)
})
class TodayViewController: UIViewController, NCWidgetProviding {
private var initializedInterface = false
private let disposable = MetaDisposable()
deinit {
self.disposable.dispose()
}
private var snapshotView: UIImageView?
override func viewDidLoad() {
super.viewDidLoad()
self.snapshotView?.removeFromSuperview()
let snapshotView = UIImageView()
if let path = self.getSnapshotPath(), let image = UIImage(contentsOfFile: path) {
snapshotView.image = image
}
self.snapshotView = snapshotView
self.view.addSubview(snapshotView)
if self.initializedInterface {
return
}
self.initializedInterface = true
let appBundleIdentifier = Bundle.main.bundleIdentifier!
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
return
}
let apiId: Int32 = BuildConfig.shared().apiId
let languagesCategory = "ios"
let appGroupName = "group.\(appBundleIdentifier[..<lastDotRange.lowerBound])"
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: "widget", launchSpecificId: arc4random64())
let logsPath = rootPath + "/today-logs"
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
setupSharedLogger(logsPath)
let account: Signal<Account, NoError>
if let accountCache = accountCache {
account = .single(accountCache)
} else {
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
initializeAccountManagement()
account = accountManager(basePath: rootPath + "/accounts-metadata")
|> take(1)
|> mapToSignal { accountManager -> Signal<Account, NoError> in
return currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0), supplementary: true, manager: accountManager, rootPath: rootPath, beginWithTestingEnvironment: false, auxiliaryMethods: auxiliaryMethods)
|> mapToSignal { account -> Signal<Account, NoError> in
if let account = account {
switch account {
case .upgrading:
return .complete()
case let .authorized(account):
accountCache = account
return .single(account)
case .unauthorized:
return .complete()
}
} else {
return .complete()
}
}
}
|> take(1)
}
let applicationInterface = account |> afterNext { account in
setupAccount(account)
} |> deliverOnMainQueue |> afterNext { [weak self] account in
account.resetStateManagement()
let _ = (recentPeers(account: account)
|> deliverOnMainQueue).start(next: { peers in
if let strongSelf = self {
switch peers {
case let .peers(peers):
strongSelf.setPeers(account: account, peers: peers.filter { !$0.isDeleted })
case .disabled:
break
}
}
})
//account.network.shouldKeepConnection.set(shouldBeMaster.get() |> map({ $0 }))
}
self.disposable.set(applicationInterface.start())
}
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
completionHandler(.newData)
}
@available(iOSApplicationExtension 10.0, *)
func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) {
}
private var peers: [Peer]?
private func setPeers(account: Account, peers: [Peer]) {
self.peers = peers
self.peerViews.forEach {
$0.removeFromSuperview()
}
self.peerViews = []
for peer in peers {
let peerView = PeerView(account: account, peer: peer, tapped: { [weak self] in
if let strongSelf = self {
if let url = URL(string: "\(BuildConfig.shared().appSpecificUrlScheme)://localpeer?id=\(peer.id.toInt64())") {
strongSelf.extensionContext?.open(url, completionHandler: nil)
}
}
})
self.view.addSubview(peerView)
self.peerViews.append(peerView)
}
self.validSnapshotSize = nil
if let size = self.validLayout {
self.updateLayout(size: size)
}
}
private var validLayout: CGSize?
private var validSnapshotSize: CGSize?
private var peerViews: [PeerView] = []
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.updateLayout(size: self.view.bounds.size)
}
private func updateLayout(size: CGSize) {
self.validLayout = size
if let image = self.snapshotView?.image {
let scale = UIScreen.main.scale
self.snapshotView?.frame = CGRect(origin: CGPoint(), size: CGSize(width: image.size.width / scale, height: image.size.height / scale))
}
let peerSize = CGSize(width: 70.0, height: 100.0)
var peerFrames: [CGRect] = []
var offset: CGFloat = 0.0
for _ in self.peerViews {
let peerFrame = CGRect(origin: CGPoint(x: offset, y: 10.0), size: peerSize)
offset += peerFrame.size.width
if peerFrame.maxX > size.width {
break
}
peerFrames.append(peerFrame)
}
var totalSize: CGFloat = 0.0
for i in 0 ..< peerFrames.count {
totalSize += peerFrames[i].width
}
let spacing: CGFloat = floor((size.width - totalSize) / CGFloat(peerFrames.count))
offset = floor(spacing / 2.0)
for i in 0 ..< peerFrames.count {
let peerView = self.peerViews[i]
peerView.frame = CGRect(origin: CGPoint(x: offset, y: 20.0), size: peerFrames[i].size)
peerView.updateLayout(size: peerFrames[i].size)
offset += peerFrames[i].width + spacing
}
if self.peers != nil {
self.snapshotView?.removeFromSuperview()
if self.validSnapshotSize != size {
self.validSnapshotSize = size
self.updateSnapshot()
}
}
}
private func updateSnapshot() {
if let path = self.getSnapshotPath() {
DispatchQueue.main.async {
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, false, 0.0)
/*let context = UIGraphicsGetCurrentContext()
context?.setFillColor(UIColor.blue.cgColor)
context?.fill(CGRect(origin: CGPoint(), size: self.view.bounds.size))*/
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: false)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
if let image = image, let data = UIImagePNGRepresentation(image) {
let _ = try? FileManager.default.removeItem(atPath: path)
do {
try data.write(to: URL(fileURLWithPath: path))
} catch let e {
print("\(e)")
}
}
}
}
}
private func getSnapshotPath() -> String? {
let appBundleIdentifier = Bundle.main.bundleIdentifier!
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
return nil
}
let appGroupName = "group.\(appBundleIdentifier[..<lastDotRange.lowerBound])"
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
guard let appGroupUrl = maybeAppGroupUrl else {
return nil
}
let rootPath = rootPathForBasePath(appGroupUrl.path)
return rootPath + "/widget-snapshot.png"
}
}