From 464e5c2dde75cd900005065b5f6023a3d765611f Mon Sep 17 00:00:00 2001 From: Isvvc Date: Tue, 30 Jun 2020 22:00:01 -0600 Subject: [PATCH] Add search bars to Attributes, Modules, and Ingredients tables --- .../AttributesTableViewController.swift | 84 +++++++++++++------ .../IngredientsTableViewController.swift | 71 +++++++++------- .../ModulesTableViewController.swift | 84 +++++++++++++------ 3 files changed, 161 insertions(+), 78 deletions(-) diff --git a/Character Tracker/Character Tracker/View Controllers/AttributesTableViewController.swift b/Character Tracker/Character Tracker/View Controllers/AttributesTableViewController.swift index ebbfd68..a5b5816 100644 --- a/Character Tracker/Character Tracker/View Controllers/AttributesTableViewController.swift +++ b/Character Tracker/Character Tracker/View Controllers/AttributesTableViewController.swift @@ -25,6 +25,8 @@ class AttributesTableViewController: UITableViewController, CharacterTrackerView var showAll = false var callbacks: [( (Attribute) -> Void )] = [] + let searchController = UISearchController(searchResultsController: nil) + var typeName: String { if let name = attributeType?.name { return name.capitalized @@ -41,31 +43,7 @@ class AttributesTableViewController: UITableViewController, CharacterTrackerView NSSortDescriptor(key: "name", ascending: true) ] - guard let game = gameReference?.game else { return nil } - - if !showAll { - var predicateString = "ANY games == %@" - var argumentsList: [Any] = [game] - - if let type = attributeType { - predicateString += " AND type == %@" - argumentsList.append(type) - } - - fetchRequest.predicate = NSPredicate(format: predicateString, argumentArray: argumentsList) - } else { - if let gameAttributes = game.attributes { - var predicateString = "NOT (SELF in %@)" - var argumentsList: [Any] = [gameAttributes] - - if let type = attributeType { - predicateString += " AND type == %@" - argumentsList.append(type) - } - - fetchRequest.predicate = NSPredicate(format: predicateString, argumentArray: argumentsList) - } - } + fetchRequest.predicate = frcPredicate() let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.shared.mainContext, @@ -103,6 +81,8 @@ class AttributesTableViewController: UITableViewController, CharacterTrackerView return frc }() + //MARK: View loading + override func viewDidLoad() { super.viewDidLoad() @@ -113,6 +93,12 @@ class AttributesTableViewController: UITableViewController, CharacterTrackerView addAttributeView.isHidden = true navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(close)) } + + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search" + navigationItem.searchController = searchController + definesPresentationContext = true } // MARK: - Table view data source @@ -189,12 +175,41 @@ class AttributesTableViewController: UITableViewController, CharacterTrackerView //MARK: Private - func choose(attribute: Attribute) { + private func choose(attribute: Attribute) { for callback in callbacks { callback(attribute) } } + private func frcPredicate(searchString: String? = nil) -> NSPredicate? { + guard let game = gameReference?.game else { return nil } + + var predicates: [NSPredicate] = [] + + if !showAll { + predicates.append(NSPredicate(format: "ANY games == %@", game)) + + if let type = attributeType { + predicates.append(NSPredicate(format: "type == %@", type)) + } + } else { + if let gameAttributes = game.attributes { + predicates.append(NSPredicate(format: "NOT (SELF in %@)", gameAttributes)) + + if let type = attributeType { + predicates.append(NSPredicate(format: "type == %@", type)) + } + } + } + + if let searchString = searchString?.lowercased(), + !searchString.isEmpty { + predicates.append(NSPredicate(format: "name CONTAINS[c] %@", searchString)) + } + + return NSCompoundPredicate(andPredicateWithSubpredicates: predicates) + } + //MARK: Actions @IBAction func addAttribute(_ sender: UIButton) { @@ -336,3 +351,20 @@ extension AttributesTableViewController: NSFetchedResultsControllerDelegate { } } } + +//MARK: Search results updating + +extension AttributesTableViewController: UISearchResultsUpdating { + func updateSearchResults(for searchController: UISearchController) { + guard let searchString = searchController.searchBar.text, + let predicate = frcPredicate(searchString: searchString) else { return } + + fetchedResultsController?.fetchRequest.predicate = predicate + do { + try fetchedResultsController?.performFetch() + tableView.reloadData() + } catch { + NSLog("Error performing fetch for module FRC: \(error)") + } + } +} diff --git a/Character Tracker/Character Tracker/View Controllers/IngredientsTableViewController.swift b/Character Tracker/Character Tracker/View Controllers/IngredientsTableViewController.swift index 5e4e66d..ad65ab6 100644 --- a/Character Tracker/Character Tracker/View Controllers/IngredientsTableViewController.swift +++ b/Character Tracker/Character Tracker/View Controllers/IngredientsTableViewController.swift @@ -17,6 +17,8 @@ class IngredientsTableViewController: UITableViewController, CharacterTrackerVie var ingredientController: IngredientController? var callbacks: [( (Ingredient) -> Void )] = [] + let searchController = UISearchController(searchResultsController: nil) + lazy var fetchedResultsController: NSFetchedResultsController = { let fetchRequest: NSFetchRequest = Ingredient.fetchRequest() @@ -24,10 +26,8 @@ class IngredientsTableViewController: UITableViewController, CharacterTrackerVie NSSortDescriptor(key: "name", ascending: true) ] - if let game = gameReference?.game { - fetchRequest.predicate = NSPredicate(format: "ANY games == %@", game) - } - + fetchRequest.predicate = frcPredicate() + let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.shared.mainContext, sectionNameKeyPath: nil, @@ -43,15 +43,17 @@ class IngredientsTableViewController: UITableViewController, CharacterTrackerVie return frc }() + + //MARK: View loading override func viewDidLoad() { super.viewDidLoad() - - // Uncomment the following line to preserve selection between presentations - // self.clearsSelectionOnViewWillAppear = false - - // Uncomment the following line to display an Edit button in the navigation bar for this view controller. - // self.navigationItem.rightBarButtonItem = self.editButtonItem + + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search" + navigationItem.searchController = searchController + definesPresentationContext = true } // MARK: - Table view data source @@ -83,25 +85,8 @@ class IngredientsTableViewController: UITableViewController, CharacterTrackerVie if editingStyle == .delete { let ingredient = fetchedResultsController.object(at: indexPath) ingredientController?.delete(ingredient: ingredient, context: CoreDataStack.shared.mainContext) - } else if editingStyle == .insert { - // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view - } - } - - /* - // Override to support rearranging the table view. - override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) { - - } - */ - - /* - // Override to support conditional rearranging of the table view. - override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - // Return false if you do not want the item to be re-orderable. - return true + } } - */ override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let ingredient = fetchedResultsController.object(at: indexPath) @@ -116,6 +101,19 @@ class IngredientsTableViewController: UITableViewController, CharacterTrackerVie } } + private func frcPredicate(searchString: String? = nil) -> NSPredicate? { + guard let game = gameReference?.game else { return nil } + + var predicates: [NSPredicate] = [NSPredicate(format: "ANY games == %@", game)] + + if let searchString = searchString?.lowercased(), + !searchString.isEmpty { + predicates.append(NSPredicate(format: "name CONTAINS[c] %@", searchString)) + } + + return NSCompoundPredicate(andPredicateWithSubpredicates: predicates) + } + //MARK: Public func askForQuantity(completion: @escaping (Int16?) -> Void ) { @@ -242,3 +240,20 @@ extension IngredientsTableViewController: NSFetchedResultsControllerDelegate { } } } + +//MARK: Search results updating + +extension IngredientsTableViewController: UISearchResultsUpdating { + func updateSearchResults(for searchController: UISearchController) { + guard let searchString = searchController.searchBar.text, + let predicate = frcPredicate(searchString: searchString) else { return } + + fetchedResultsController.fetchRequest.predicate = predicate + do { + try fetchedResultsController.performFetch() + tableView.reloadData() + } catch { + NSLog("Error performing fetch for module FRC: \(error)") + } + } +} diff --git a/Character Tracker/Character Tracker/View Controllers/ModulesTableViewController.swift b/Character Tracker/Character Tracker/View Controllers/ModulesTableViewController.swift index 71b00c2..d0a1992 100644 --- a/Character Tracker/Character Tracker/View Controllers/ModulesTableViewController.swift +++ b/Character Tracker/Character Tracker/View Controllers/ModulesTableViewController.swift @@ -26,6 +26,8 @@ class ModulesTableViewController: UITableViewController, CharacterTrackerViewCon var showAll = false var callbacks: [( (Module) -> Void )] = [] + let searchController = UISearchController(searchResultsController: nil) + var typeName: String { if let name = moduleType?.name { return name @@ -39,29 +41,7 @@ class ModulesTableViewController: UITableViewController, CharacterTrackerViewCon fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)] - guard let game = gameReference?.game else { return nil } - - var predicates: [NSPredicate] = [] - - if !showAll { - predicates.append(NSPredicate(format: "ANY games == %@", game)) - - if let type = moduleType { - predicates.append(NSPredicate(format: "type == %@", type)) - } - - if let excludedModuleUUID = excludedModule?.id { - predicates.append(NSPredicate(format: "id != %@", excludedModuleUUID as CVarArg)) - } - } else if let gameModules = game.modules { - predicates.append(NSPredicate(format: "NOT (SELF in %@)", gameModules)) - - if let type = moduleType { - predicates.append(NSPredicate(format: "type == %@", type)) - } - } - - fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates) + fetchRequest.predicate = frcPredicate() let frc = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataStack.shared.mainContext, @@ -78,6 +58,8 @@ class ModulesTableViewController: UITableViewController, CharacterTrackerViewCon return frc }() + + //MARK: View loading override func viewDidLoad() { super.viewDidLoad() @@ -89,6 +71,12 @@ class ModulesTableViewController: UITableViewController, CharacterTrackerViewCon addModuleView.isHidden = true navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(close)) } + + searchController.searchResultsUpdater = self + searchController.obscuresBackgroundDuringPresentation = false + searchController.searchBar.placeholder = "Search" + navigationItem.searchController = searchController + definesPresentationContext = true } //MARK: Table view data source @@ -168,11 +156,42 @@ class ModulesTableViewController: UITableViewController, CharacterTrackerViewCon //MARK: Private - func choose(module: Module) { + private func choose(module: Module) { for callback in callbacks { callback(module) } } + + private func frcPredicate(searchString: String? = nil) -> NSPredicate? { + guard let game = gameReference?.game else { return nil } + + var predicates: [NSPredicate] = [] + + if !showAll { + predicates.append(NSPredicate(format: "ANY games == %@", game)) + + if let type = moduleType { + predicates.append(NSPredicate(format: "type == %@", type)) + } + + if let excludedModuleUUID = excludedModule?.id { + predicates.append(NSPredicate(format: "id != %@", excludedModuleUUID as CVarArg)) + } + } else if let gameModules = game.modules { + predicates.append(NSPredicate(format: "NOT (SELF in %@)", gameModules)) + + if let type = moduleType { + predicates.append(NSPredicate(format: "type == %@", type)) + } + } + + if let searchString = searchString?.lowercased(), + !searchString.isEmpty { + predicates.append(NSPredicate(format: "name CONTAINS[c] %@", searchString)) + } + + return NSCompoundPredicate(andPredicateWithSubpredicates: predicates) + } //MARK: Navigation @@ -316,3 +335,20 @@ extension ModulesTableViewController: NSFetchedResultsControllerDelegate { } } } + +//MARK: Search results updating + +extension ModulesTableViewController: UISearchResultsUpdating { + func updateSearchResults(for searchController: UISearchController) { + guard let searchString = searchController.searchBar.text, + let predicate = frcPredicate(searchString: searchString) else { return } + + fetchedResultsController?.fetchRequest.predicate = predicate + do { + try fetchedResultsController?.performFetch() + tableView.reloadData() + } catch { + NSLog("Error performing fetch for module FRC: \(error)") + } + } +}