2019-05-20 22:24:16 +02:00
//
// U p d a t e s V i e w C o n t r o l l e r . s w i f t
// A l t S t o r e
//
// C r e a t e d b y R i l e y T e s t u t o n 5 / 2 0 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R i l e y T e s t u t . A l l r i g h t s r e s e r v e d .
//
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
} ( )
2019-06-17 14:49:23 -07:00
@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 )
}
2019-05-20 22:24:16 +02:00
override func viewDidLoad ( )
{
super . viewDidLoad ( )
self . tableView . dataSource = self . dataSource
2019-06-17 14:49:23 -07:00
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 ) ] )
}
2019-05-20 22:24:16 +02:00
}
override func viewDidAppear ( _ animated : Bool )
{
super . viewDidAppear ( animated )
2019-06-17 14:49:23 -07:00
self . update ( )
2019-05-20 22:24:16 +02:00
}
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
}
2019-06-17 14:49:23 -07:00
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
2019-05-20 22:24:16 +02:00
return dataSource
}
2019-06-17 14:49:23 -07:00
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 )
{
2019-06-17 16:31:10 -07:00
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 ( )
2019-06-17 14:49:23 -07:00
2019-06-17 16:31:10 -07:00
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 ( )
}
2019-06-17 14:49:23 -07:00
}
2019-06-17 16:31:10 -07:00
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 )
}
}
2019-06-17 14:49:23 -07:00
DispatchQueue . main . async {
2019-06-17 16:31:10 -07:00
self . progressView . observedProgress = nil
self . progressView . progress = 0.0
2019-06-17 14:49:23 -07:00
}
}
2019-06-17 16:31:10 -07:00
self . progressView . observedProgress = progress
2019-06-17 14:49:23 -07:00
}
2019-06-17 16:31:10 -07:00
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 ( )
}
2019-06-17 14:49:23 -07:00
}
@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 )
{
}
2019-05-20 22:24:16 +02:00
}