mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-09 06:43:25 +01:00
204 lines
7.7 KiB
Swift
204 lines
7.7 KiB
Swift
//
|
|
// UpdatesViewController.swift
|
|
// AltStore
|
|
//
|
|
// Created by Riley Testut on 5/20/19.
|
|
// Copyright © 2019 Riley Testut. All rights reserved.
|
|
//
|
|
|
|
import UIKit
|
|
|
|
import Roxas
|
|
|
|
class UpdatesViewController: UITableViewController
|
|
{
|
|
private lazy var dataSource = self.makeDataSource()
|
|
|
|
private lazy var dateFormatter: DateFormatter = {
|
|
let dateFormatter = DateFormatter()
|
|
dateFormatter.dateStyle = .short
|
|
dateFormatter.timeStyle = .none
|
|
return dateFormatter
|
|
}()
|
|
|
|
@IBOutlet private var progressView: UIProgressView!
|
|
|
|
required init?(coder aDecoder: NSCoder)
|
|
{
|
|
super.init(coder: aDecoder)
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(UpdatesViewController.didFetchApps(_:)), name: AppManager.didFetchAppsNotification, object: nil)
|
|
}
|
|
|
|
override func viewDidLoad()
|
|
{
|
|
super.viewDidLoad()
|
|
|
|
self.tableView.dataSource = self.dataSource
|
|
|
|
if let navigationBar = self.navigationController?.navigationBar
|
|
{
|
|
self.progressView.translatesAutoresizingMaskIntoConstraints = false
|
|
navigationBar.addSubview(self.progressView)
|
|
|
|
NSLayoutConstraint.activate([self.progressView.widthAnchor.constraint(equalTo: navigationBar.widthAnchor),
|
|
self.progressView.bottomAnchor.constraint(equalTo: navigationBar.bottomAnchor)])
|
|
}
|
|
}
|
|
|
|
override func viewDidAppear(_ animated: Bool)
|
|
{
|
|
super.viewDidAppear(animated)
|
|
|
|
self.update()
|
|
}
|
|
|
|
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
|
|
{
|
|
guard segue.identifier == "showAppDetail" else { return }
|
|
|
|
guard let cell = sender as? UITableViewCell, let indexPath = self.tableView.indexPath(for: cell) else { return }
|
|
|
|
let installedApp = self.dataSource.item(at: indexPath)
|
|
guard let app = installedApp.app else { return }
|
|
|
|
let appDetailViewController = segue.destination as! AppDetailViewController
|
|
appDetailViewController.app = app
|
|
}
|
|
}
|
|
|
|
private extension UpdatesViewController
|
|
{
|
|
func makeDataSource() -> RSTFetchedResultsTableViewDataSource<InstalledApp>
|
|
{
|
|
let fetchRequest = InstalledApp.fetchRequest() as NSFetchRequest<InstalledApp>
|
|
fetchRequest.predicate = NSPredicate(format: "%K != %K", #keyPath(InstalledApp.version), #keyPath(InstalledApp.app.version))
|
|
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \InstalledApp.app?.versionDate, ascending: false)]
|
|
fetchRequest.returnsObjectsAsFaults = false
|
|
|
|
let dataSource = RSTFetchedResultsTableViewDataSource(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext)
|
|
dataSource.cellConfigurationHandler = { (cell, installedApp, indexPath) in
|
|
guard let app = installedApp.app else { return }
|
|
|
|
cell.textLabel?.text = app.name + " (\(app.version))"
|
|
|
|
let detailText = self.dateFormatter.string(from: app.versionDate) + "\n\n" + (app.versionDescription ?? "No Update Description")
|
|
|
|
cell.detailTextLabel?.numberOfLines = 0
|
|
cell.detailTextLabel?.text = detailText
|
|
}
|
|
|
|
let placeholderView = RSTPlaceholderView()
|
|
placeholderView.textLabel.text = NSLocalizedString("No Updates", comment: "")
|
|
placeholderView.detailTextLabel.text = NSLocalizedString("There are no app updates at this time.", comment: "")
|
|
dataSource.placeholderView = placeholderView
|
|
|
|
return dataSource
|
|
}
|
|
|
|
func update()
|
|
{
|
|
if let count = self.dataSource.fetchedResultsController.fetchedObjects?.count, count > 0
|
|
{
|
|
self.navigationController?.tabBarItem.badgeValue = String(describing: count)
|
|
}
|
|
else
|
|
{
|
|
self.navigationController?.tabBarItem.badgeValue = nil
|
|
}
|
|
}
|
|
}
|
|
|
|
private extension UpdatesViewController
|
|
{
|
|
func update(_ installedApp: InstalledApp)
|
|
{
|
|
func updateApp()
|
|
{
|
|
let toastView = RSTToastView(text: "Updating...", detailText: nil)
|
|
toastView.tintColor = .altPurple
|
|
toastView.activityIndicatorView.startAnimating()
|
|
toastView.show(in: self.navigationController?.view ?? self.view)
|
|
|
|
let progress = AppManager.shared.install(installedApp.app, presentingViewController: self) { (result) in
|
|
do
|
|
{
|
|
let app = try result.get()
|
|
try app.managedObjectContext?.save()
|
|
|
|
DispatchQueue.main.async {
|
|
let installedApp = DatabaseManager.shared.persistentContainer.viewContext.object(with: installedApp.objectID) as! InstalledApp
|
|
|
|
let toastView = RSTToastView(text: "Updated \(installedApp.app.name) to version \(installedApp.version)!", detailText: nil)
|
|
toastView.tintColor = .altPurple
|
|
toastView.show(in: self.navigationController?.view ?? self.view, duration: 2)
|
|
|
|
self.update()
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
DispatchQueue.main.async {
|
|
let toastView = RSTToastView(text: "Failed to update \(installedApp.app.name)", detailText: error.localizedDescription)
|
|
toastView.tintColor = .altPurple
|
|
toastView.show(in: self.navigationController?.view ?? self.view, duration: 2)
|
|
}
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
self.progressView.observedProgress = nil
|
|
self.progressView.progress = 0.0
|
|
}
|
|
}
|
|
|
|
self.progressView.observedProgress = progress
|
|
}
|
|
|
|
if installedApp.app.identifier == App.altstoreAppID
|
|
{
|
|
let alertController = UIAlertController(title: NSLocalizedString("Update AltStore?", comment: ""), message: NSLocalizedString("AltStore will quit upon completion.", comment: ""), preferredStyle: .alert)
|
|
alertController.addAction(UIAlertAction(title: NSLocalizedString("Update and Quit", comment: ""), style: .default, handler: { (action) in
|
|
updateApp()
|
|
}))
|
|
alertController.addAction(.cancel)
|
|
|
|
self.present(alertController, animated: true, completion: nil)
|
|
}
|
|
else
|
|
{
|
|
updateApp()
|
|
}
|
|
}
|
|
|
|
@objc func didFetchApps(_ notification: Notification)
|
|
{
|
|
DispatchQueue.main.async {
|
|
if self.dataSource.fetchedResultsController.fetchedObjects == nil
|
|
{
|
|
do { try self.dataSource.fetchedResultsController.performFetch() }
|
|
catch { print("Error fetching:", error) }
|
|
}
|
|
|
|
self.update()
|
|
}
|
|
}
|
|
}
|
|
|
|
extension UpdatesViewController
|
|
{
|
|
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]?
|
|
{
|
|
let updateAction = UITableViewRowAction(style: .normal, title: "Update") { [weak self] (action, indexPath) in
|
|
guard let installedApp = self?.dataSource.item(at: indexPath) else { return }
|
|
self?.update(installedApp)
|
|
}
|
|
updateAction.backgroundColor = .altPurple
|
|
|
|
return [updateAction]
|
|
}
|
|
|
|
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
|
|
{
|
|
}
|
|
}
|