[ExpFeat] Adds filter button to change RepairSaveStatesViewController’s date range
* Recent (Last month) * All
This commit is contained in:
parent
d5f910ff00
commit
5c7e3cc5b9
@ -422,6 +422,7 @@ private extension RepairDatabaseViewController
|
|||||||
Logger.database.info("Finished repairing Games and GameSaves, reviewing recent SaveStates...")
|
Logger.database.info("Finished repairing Games and GameSaves, reviewing recent SaveStates...")
|
||||||
|
|
||||||
let viewController = ReviewSaveStatesViewController()
|
let viewController = ReviewSaveStatesViewController()
|
||||||
|
viewController.filter = .sinceLastBeta
|
||||||
viewController.completionHandler = { [weak self] in
|
viewController.completionHandler = { [weak self] in
|
||||||
self?.finish()
|
self?.finish()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,16 @@ import OSLog
|
|||||||
import Harmony
|
import Harmony
|
||||||
import Roxas
|
import Roxas
|
||||||
|
|
||||||
|
extension ReviewSaveStatesViewController
|
||||||
|
{
|
||||||
|
enum Filter
|
||||||
|
{
|
||||||
|
case recent
|
||||||
|
case all
|
||||||
|
case sinceLastBeta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension RecordFlags
|
extension RecordFlags
|
||||||
{
|
{
|
||||||
static let isGameRelationshipVerified = RecordFlags(rawValue: 1 << 0)
|
static let isGameRelationshipVerified = RecordFlags(rawValue: 1 << 0)
|
||||||
@ -19,6 +29,12 @@ extension RecordFlags
|
|||||||
|
|
||||||
class ReviewSaveStatesViewController: UITableViewController
|
class ReviewSaveStatesViewController: UITableViewController
|
||||||
{
|
{
|
||||||
|
var filter: Filter = .recent {
|
||||||
|
didSet {
|
||||||
|
self.updateDataSource()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var completionHandler: (() -> Void)?
|
var completionHandler: (() -> Void)?
|
||||||
|
|
||||||
private lazy var managedObjectContext = DatabaseManager.shared.newBackgroundSavingViewContext()
|
private lazy var managedObjectContext = DatabaseManager.shared.newBackgroundSavingViewContext()
|
||||||
@ -27,6 +43,8 @@ class ReviewSaveStatesViewController: UITableViewController
|
|||||||
private lazy var descriptionDataSource = self.makeDescriptionDataSource()
|
private lazy var descriptionDataSource = self.makeDescriptionDataSource()
|
||||||
private lazy var saveStatesDataSource = self.makeSaveStatesDataSource()
|
private lazy var saveStatesDataSource = self.makeSaveStatesDataSource()
|
||||||
|
|
||||||
|
private weak var _parentNavigationController: UINavigationController?
|
||||||
|
|
||||||
init()
|
init()
|
||||||
{
|
{
|
||||||
super.init(style: .insetGrouped)
|
super.init(style: .insetGrouped)
|
||||||
@ -60,8 +78,36 @@ class ReviewSaveStatesViewController: UITableViewController
|
|||||||
{
|
{
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
// Must set parent's navigationItem.title for when we're contained in SwiftUI View.
|
if let parent = self.parent, parent.navigationItem.title == nil
|
||||||
self.parent?.navigationItem.title = NSLocalizedString("Review Save States", comment: "")
|
{
|
||||||
|
// Must change parent's navigationItem when we're contained in SwiftUI View.
|
||||||
|
parent.navigationItem.title = NSLocalizedString("Review Save States", comment: "")
|
||||||
|
parent.navigationItem.rightBarButtonItem = self.makeFilterButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewWillDisappear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
|
_parentNavigationController = self.parent?.navigationController
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidDisappear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewDidDisappear(animated)
|
||||||
|
|
||||||
|
switch self.filter
|
||||||
|
{
|
||||||
|
case .all, .recent:
|
||||||
|
if self.parent == nil || self.parent?.parent == nil
|
||||||
|
{
|
||||||
|
// Only finish if we're popped off navigation controller.
|
||||||
|
self.finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
case .sinceLastBeta: break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,13 +129,7 @@ private extension ReviewSaveStatesViewController
|
|||||||
|
|
||||||
func makeSaveStatesDataSource() -> RSTFetchedResultsTableViewPrefetchingDataSource<SaveState, UIImage>
|
func makeSaveStatesDataSource() -> RSTFetchedResultsTableViewPrefetchingDataSource<SaveState, UIImage>
|
||||||
{
|
{
|
||||||
let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) ?? Date().addingTimeInterval(-1 * 60 * 60 * 24 * 30)
|
let fetchedResultsController = self.makeSaveStatesFetchedResultsController()
|
||||||
|
|
||||||
let fetchRequest = SaveState.fetchRequest()
|
|
||||||
fetchRequest.predicate = NSPredicate(format: "%K > %@", #keyPath(SaveState.modifiedDate), oneMonthAgo as NSDate)
|
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \SaveState.game?.name, ascending: true), NSSortDescriptor(keyPath: \SaveState.modifiedDate, ascending: false)]
|
|
||||||
|
|
||||||
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: #keyPath(SaveState.game.name), cacheName: nil)
|
|
||||||
|
|
||||||
let dataSource = RSTFetchedResultsTableViewPrefetchingDataSource<SaveState, UIImage>(fetchedResultsController: fetchedResultsController)
|
let dataSource = RSTFetchedResultsTableViewPrefetchingDataSource<SaveState, UIImage>(fetchedResultsController: fetchedResultsController)
|
||||||
dataSource.cellConfigurationHandler = { (cell, saveState, indexPath) in
|
dataSource.cellConfigurationHandler = { (cell, saveState, indexPath) in
|
||||||
@ -140,6 +180,67 @@ private extension ReviewSaveStatesViewController
|
|||||||
|
|
||||||
return dataSource
|
return dataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeSaveStatesFetchedResultsController() -> NSFetchedResultsController<SaveState>
|
||||||
|
{
|
||||||
|
let fetchRequest = SaveState.fetchRequest()
|
||||||
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
|
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \SaveState.game?.name, ascending: true), NSSortDescriptor(keyPath: \SaveState.modifiedDate, ascending: false)]
|
||||||
|
|
||||||
|
let predicate = NSPredicate(format: "%K != %@", #keyPath(SaveState.type), SaveStateType.auto.rawValue as NSNumber)
|
||||||
|
|
||||||
|
switch self.filter
|
||||||
|
{
|
||||||
|
case .recent:
|
||||||
|
let oneMonthAgo = Calendar.current.date(byAdding: .month, value: -1, to: Date()) ?? Date().addingTimeInterval(-1 * 60 * 60 * 24 * 30)
|
||||||
|
let recentPredicate = NSPredicate(format: "%K > %@", #keyPath(SaveState.modifiedDate), oneMonthAgo as NSDate)
|
||||||
|
|
||||||
|
fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, recentPredicate])
|
||||||
|
|
||||||
|
case .all:
|
||||||
|
fetchRequest.predicate = predicate
|
||||||
|
|
||||||
|
case .sinceLastBeta:
|
||||||
|
let dateComponents = DateComponents(year: 2023, month: 7, day: 18, hour: 0, minute: 0, second: 0)
|
||||||
|
let lastBetaDate = Calendar.current.date(from: dateComponents) ?? Date().addingTimeInterval(-1 * 60 * 60 * 24 * 45)
|
||||||
|
|
||||||
|
let sinceLastBetaPredicate = NSPredicate(format: "%K > %@", #keyPath(SaveState.modifiedDate), lastBetaDate as NSDate)
|
||||||
|
fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate, sinceLastBetaPredicate])
|
||||||
|
}
|
||||||
|
|
||||||
|
let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext, sectionNameKeyPath: #keyPath(SaveState.game.name), cacheName: nil)
|
||||||
|
return fetchedResultsController
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateDataSource()
|
||||||
|
{
|
||||||
|
let fetchedResultsController = self.makeSaveStatesFetchedResultsController()
|
||||||
|
self.saveStatesDataSource.fetchedResultsController = fetchedResultsController
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeFilterButton() -> UIBarButtonItem
|
||||||
|
{
|
||||||
|
let recentAction = UIAction(title: NSLocalizedString("Past Month", comment: ""), image: UIImage(systemName: "calendar")) { [weak self] _ in
|
||||||
|
self?.filter = .recent
|
||||||
|
}
|
||||||
|
let allAction = UIAction(title: NSLocalizedString("All Time", comment: ""), image: UIImage(systemName: "clock")) { [weak self] _ in
|
||||||
|
self?.filter = .all
|
||||||
|
}
|
||||||
|
|
||||||
|
var options: UIMenu.Options = []
|
||||||
|
if #available(iOS 15, *)
|
||||||
|
{
|
||||||
|
options = .singleSelection
|
||||||
|
|
||||||
|
recentAction.state = self.filter == .recent ? .on : .off
|
||||||
|
allAction.state = self.filter == .all ? .on : .off
|
||||||
|
}
|
||||||
|
|
||||||
|
let filterMenu = UIMenu(options: options, children: [recentAction, allAction])
|
||||||
|
|
||||||
|
let filterButton = UIBarButtonItem(title: NSLocalizedString("Filter", comment: ""), image: UIImage(systemName: "calendar.badge.clock"), menu: filterMenu)
|
||||||
|
return filterButton
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension ReviewSaveStatesViewController
|
private extension ReviewSaveStatesViewController
|
||||||
@ -190,9 +291,22 @@ private extension ReviewSaveStatesViewController
|
|||||||
self.managedObjectContext.perform {
|
self.managedObjectContext.perform {
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
let saveStates: [SaveState]?
|
||||||
|
|
||||||
|
switch self.filter
|
||||||
|
{
|
||||||
|
case .recent, .all:
|
||||||
|
// Only upload metadata for changed SaveStates.
|
||||||
|
saveStates = self.managedObjectContext.updatedObjects.compactMap { $0 as? SaveState }
|
||||||
|
|
||||||
|
case .sinceLastBeta:
|
||||||
|
// Upload metadata for _all_ SaveStates.
|
||||||
|
saveStates = self.saveStatesDataSource.fetchedResultsController.fetchedObjects
|
||||||
|
}
|
||||||
|
|
||||||
try self.managedObjectContext.save()
|
try self.managedObjectContext.save()
|
||||||
|
|
||||||
if let saveStates = self.saveStatesDataSource.fetchedResultsController.fetchedObjects, let coordinator = SyncManager.shared.coordinator
|
if let saveStates = saveStates, let coordinator = SyncManager.shared.coordinator
|
||||||
{
|
{
|
||||||
let records = try coordinator.recordController.fetchRecords(for: saveStates)
|
let records = try coordinator.recordController.fetchRecords(for: saveStates)
|
||||||
if let context = records.first?.recordedObject?.managedObjectContext
|
if let context = records.first?.recordedObject?.managedObjectContext
|
||||||
@ -224,7 +338,7 @@ private extension ReviewSaveStatesViewController
|
|||||||
self.navigationItem.rightBarButtonItem?.isIndicatingActivity = false
|
self.navigationItem.rightBarButtonItem?.isIndicatingActivity = false
|
||||||
|
|
||||||
let alertController = UIAlertController(title: NSLocalizedString("Unable to Save Changes", comment: ""), error: error)
|
let alertController = UIAlertController(title: NSLocalizedString("Unable to Save Changes", comment: ""), error: error)
|
||||||
self.present(alertController, animated: true)
|
(self._parentNavigationController ?? self).present(alertController, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user