mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-03-27 17:20:01 +00:00
Support widget data
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import Foundation
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import UIKit
|
||||
import WidgetItems
|
||||
|
||||
private extension UIColor {
|
||||
convenience init(rgb: UInt32) {
|
||||
@@ -53,7 +52,7 @@ private let deviceColorSpace: CGColorSpace = {
|
||||
}
|
||||
}()
|
||||
|
||||
private func avatarViewLettersImage(size: CGSize, peerId: PeerId, accountPeerId: PeerId, letters: [String]) -> UIImage? {
|
||||
private func avatarViewLettersImage(size: CGSize, peerId: Int64, accountPeerId: Int64, letters: [String]) -> UIImage? {
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
|
||||
let context = UIGraphicsGetCurrentContext()
|
||||
|
||||
@@ -61,7 +60,7 @@ private func avatarViewLettersImage(size: CGSize, peerId: PeerId, accountPeerId:
|
||||
context?.addEllipse(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
|
||||
context?.clip()
|
||||
|
||||
let colorIndex = abs(Int(accountPeerId.id + peerId.id))
|
||||
let colorIndex = abs(Int(accountPeerId + peerId))
|
||||
|
||||
let colorsArray = gradientColors[colorIndex % gradientColors.count]
|
||||
var locations: [CGFloat] = [1.0, 0.0]
|
||||
@@ -98,13 +97,13 @@ private func avatarViewLettersImage(size: CGSize, peerId: PeerId, accountPeerId:
|
||||
private let avatarSize = CGSize(width: 50.0, height: 50.0)
|
||||
|
||||
private final class AvatarView: UIImageView {
|
||||
init(account: Account, peer: Peer, size: CGSize) {
|
||||
init(accountPeerId: Int64, peer: WidgetDataPeer, size: CGSize) {
|
||||
super.init(frame: CGRect())
|
||||
|
||||
if let resource = peer.smallProfileImage?.resource, let path = account.postbox.mediaBox.completedResourcePath(resource), let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) {
|
||||
if let path = peer.avatarPath, let image = UIImage(contentsOfFile: path), let roundImage = avatarRoundImage(size: size, source: image) {
|
||||
self.image = roundImage
|
||||
} else {
|
||||
self.image = avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: account.peerId, letters: peer.displayLetters)
|
||||
self.image = avatarViewLettersImage(size: size, peerId: peer.id, accountPeerId: accountPeerId, letters: peer.letters)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,19 +113,20 @@ private final class AvatarView: UIImageView {
|
||||
}
|
||||
|
||||
final class PeerView: UIView {
|
||||
let peer: Peer
|
||||
let peer: WidgetDataPeer
|
||||
private let avatarView: AvatarView
|
||||
private let titleLabel: UILabel
|
||||
|
||||
private let tapped: () -> Void
|
||||
|
||||
init(account: Account, peer: Peer, tapped: @escaping () -> Void) {
|
||||
init(accountPeerId: Int64, peer: WidgetDataPeer, tapped: @escaping () -> Void) {
|
||||
self.peer = peer
|
||||
self.tapped = tapped
|
||||
self.avatarView = AvatarView(account: account, peer: peer, size: avatarSize)
|
||||
self.avatarView = AvatarView(accountPeerId: accountPeerId, peer: peer, size: avatarSize)
|
||||
|
||||
self.titleLabel = UILabel()
|
||||
self.titleLabel.text = peer.compactDisplayTitle
|
||||
let title = peer.name
|
||||
self.titleLabel.text = title
|
||||
self.titleLabel.textColor = .black
|
||||
self.titleLabel.font = UIFont.systemFont(ofSize: 11.0)
|
||||
self.titleLabel.lineBreakMode = .byTruncatingTail
|
||||
|
||||
@@ -1,57 +1,26 @@
|
||||
import UIKit
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import NotificationCenter
|
||||
import BuildConfig
|
||||
import WidgetItems
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
private func setupSharedLogger(_ path: String) {
|
||||
if !installedSharedLogger {
|
||||
installedSharedLogger = true
|
||||
Logger.setSharedLogger(Logger(basePath: path))
|
||||
}
|
||||
private func rootPathForBasePath(_ appGroupPath: String) -> String {
|
||||
return appGroupPath + "/telegram-data"
|
||||
}
|
||||
|
||||
private let auxiliaryMethods = AccountAuxiliaryMethods(updatePeerChatInputState: { _, _ in
|
||||
return nil
|
||||
}, fetchResource: { _, _, _, _ in
|
||||
return nil
|
||||
}, fetchResourceMediaReferenceHash: { _ in
|
||||
return .single(nil)
|
||||
}, prepareSecretThumbnailData: { _ in
|
||||
return nil
|
||||
})
|
||||
|
||||
@objc(TodayViewController)
|
||||
class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
private var initializedInterface = false
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private var buildConfig: BuildConfig?
|
||||
|
||||
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
|
||||
@@ -61,9 +30,6 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
let buildConfig = BuildConfig(baseAppBundleId: baseAppBundleId)
|
||||
self.buildConfig = buildConfig
|
||||
|
||||
let apiId: Int32 = buildConfig.apiId
|
||||
let languagesCategory = "ios"
|
||||
|
||||
let appGroupName = "group.\(baseAppBundleId)"
|
||||
let maybeAppGroupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupName)
|
||||
|
||||
@@ -72,56 +38,11 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
}
|
||||
|
||||
let rootPath = rootPathForBasePath(appGroupUrl.path)
|
||||
performAppGroupUpgrades(appGroupPath: appGroupUrl.path, rootPath: rootPath)
|
||||
let dataPath = rootPath + "/widget-data"
|
||||
|
||||
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>
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
initializeAccountManagement()
|
||||
let accountManager = AccountManager(basePath: rootPath + "/accounts-metadata")
|
||||
|
||||
let deviceSpecificEncryptionParameters = BuildConfig.deviceSpecificEncryptionParameters(rootPath, baseAppBundleId: baseAppBundleId)
|
||||
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
|
||||
|
||||
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: .single(buildConfig.bundleData(withAppToken: nil))), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: auxiliaryMethods, encryptionParameters: encryptionParameters)
|
||||
|> mapToSignal { account -> Signal<Account, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
return .single(account)
|
||||
case .unauthorized:
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: dataPath)), let widgetData = try? JSONDecoder().decode(WidgetData.self, from: data) {
|
||||
self.setWidgetData(widgetData: widgetData)
|
||||
}
|
||||
|
||||
let applicationInterface = account
|
||||
|> deliverOnMainQueue
|
||||
|> afterNext { [weak self] account in
|
||||
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:
|
||||
strongSelf.setPeers(account: account, peers: [])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
self.disposable.set(applicationInterface.start())
|
||||
}
|
||||
|
||||
func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) {
|
||||
@@ -133,34 +54,37 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
|
||||
}
|
||||
|
||||
private var peers: [Peer]?
|
||||
private var widgetData: WidgetData?
|
||||
|
||||
private func setPeers(account: Account, peers: [Peer]) {
|
||||
self.peers = peers
|
||||
private func setWidgetData(widgetData: WidgetData) {
|
||||
self.widgetData = widgetData
|
||||
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, let buildConfig = strongSelf.buildConfig {
|
||||
if let url = URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peer.id.toInt64())") {
|
||||
strongSelf.extensionContext?.open(url, completionHandler: nil)
|
||||
switch widgetData {
|
||||
case .notAuthorized, .disabled:
|
||||
break
|
||||
case let .peers(peers):
|
||||
for peer in peers.peers {
|
||||
let peerView = PeerView(accountPeerId: peers.accountPeerId, peer: peer, tapped: { [weak self] in
|
||||
if let strongSelf = self, let buildConfig = strongSelf.buildConfig {
|
||||
if let url = URL(string: "\(buildConfig.appSpecificUrlScheme)://localpeer?id=\(peer.id)") {
|
||||
strongSelf.extensionContext?.open(url, completionHandler: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
self.view.addSubview(peerView)
|
||||
self.peerViews.append(peerView)
|
||||
})
|
||||
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] = []
|
||||
|
||||
@@ -173,11 +97,6 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
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] = []
|
||||
@@ -205,49 +124,5 @@ class TodayViewController: UIViewController, NCWidgetProviding {
|
||||
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)
|
||||
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: false)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
if let image = image, let data = image.pngData() {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user