diff --git a/BPOrganizer/Base.lproj/Main.storyboard b/BPOrganizer/Base.lproj/Main.storyboard index 25a7638..2da9576 100644 --- a/BPOrganizer/Base.lproj/Main.storyboard +++ b/BPOrganizer/Base.lproj/Main.storyboard @@ -1,24 +1,226 @@ - + + - + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BPOrganizer/ViewController.swift b/BPOrganizer/ViewController.swift index 10f4058..dc56cc6 100644 --- a/BPOrganizer/ViewController.swift +++ b/BPOrganizer/ViewController.swift @@ -7,13 +7,400 @@ import UIKit -class ViewController: UIViewController { +protocol ObjectSavable { + func setObject(_ object: Object, forKey: String) throws where Object: Encodable + func getObject(forKey: String, castTo type: Object.Type) throws -> Object where Object: Decodable +} +enum ObjectSavableError: String, LocalizedError { + case unableToEncode = "Unable to encode object into data" + case noValue = "No data object found for the given key" + case unableToDecode = "Unable to decode object into given type" + + var errorDescription: String? { + rawValue + } +} +extension UserDefaults: ObjectSavable { + func setObject(_ object: Object, forKey: String) throws where Object: Encodable { + let encoder = JSONEncoder() + do { + let data = try encoder.encode(object) + set(data, forKey: forKey) + } catch { + throw ObjectSavableError.unableToEncode + } + } + + func getObject(forKey: String, castTo type: Object.Type) throws -> Object where Object: Decodable { + guard let data = data(forKey: forKey) else { throw ObjectSavableError.noValue } + let decoder = JSONDecoder() + do { + let object = try decoder.decode(type, from: data) + return object + } catch { + throw ObjectSavableError.unableToDecode + } + } +} +extension String { + func contains(find: String) -> Bool{ + return self.range(of: find) != nil + } + func containsIgnoringCase(find: String) -> Bool{ + return self.range(of: find, options: .caseInsensitive) != nil + } +} + +struct passingValues{ + static var bag:Int = 0 + static var pocket:Int = 0 +} + +class pocket: Codable { + var pocketName: String = "" + var contents:[String] = [] +} + +class bag: Codable { + var bagName:String = "" + var pockets:[pocket] = [] +} + +class ViewController: UIViewController, UIDocumentPickerDelegate, UIPickerViewDataSource, UITableViewDataSource, UITableViewDelegate, UIPickerViewDelegate { + + var bags:[bag] = [] + + func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return bags.count + } + + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return bags[row].bagName + } + + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + if (bags.count > 0){ + print(bags[bagPicker.selectedRow(inComponent: 0)].pockets) + pocketsTable.reloadData() + } + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if (bags.count > 0){ + return bags[bagPicker.selectedRow(inComponent: 0)].pockets.count + } else { + return 0 + } + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "pocket", for: indexPath) + cell.textLabel?.text = bags[bagPicker.selectedRow(inComponent: 0)].pockets[indexPath.row].pocketName + return cell + } + + func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return true + } + + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + bags[bagPicker.selectedRow(inComponent: 0)].pockets.remove(at: indexPath.row) + tableView.deleteRows(at: [indexPath], with: .fade) + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + } + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + print(bags[bagPicker.selectedRow(inComponent: 0)].pockets[indexPath.row].pocketName) + passingValues.bag = bagPicker.selectedRow(inComponent: 0) + passingValues.pocket = indexPath.row + print(passingValues.bag) + print(passingValues.pocket) + let NotificationVC = self.storyboard?.instantiateViewController(withIdentifier: "ViewController2") as! UIViewController + NotificationVC.modalPresentationStyle = .fullScreen + pocketsTable.reloadData() + self.present(NotificationVC, animated: true, completion: nil) + } + + @IBOutlet var pocketsTable: UITableView! + + @IBOutlet var bagPicker: UIPickerView! + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. + + pocketsTable.dataSource = self + pocketsTable.delegate = self + bagPicker.dataSource = self + bagPicker.delegate = self + + if (bags.count > 0){ + bagPicker.selectRow(0, inComponent: 0, animated: true) + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewWillAppear(true) + do { + bags = try UserDefaults.standard.getObject(forKey: "bagsSavedData", castTo: [bag].self) + print(bags) + } catch { + print(error.localizedDescription) + } + pocketsTable.reloadData() + bagPicker.reloadComponent(0) + } + + override func viewDidDisappear(_ animated: Bool) { + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + } + + @IBAction func AddBag(_ sender: Any) { + var newBagName:String = "" + let alert = UIAlertController(title: "Enter Bag Name", message: "", preferredStyle: .alert) + alert.addTextField { (textField) in + textField.text = "" + textField.autocapitalizationType = .words + textField.placeholder = "Bag Name" + } + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in + let textField = alert?.textFields![0] // Force unwrapping because we know it exists. + print("Text field: \(textField!.text ?? "Bag")") + if ((textField!.text ?? "Bag") == ""){ + return + } + newBagName = (textField!.text ?? "Bag") + + + let newBag:bag = bag.init() + newBag.bagName = newBagName + newBag.pockets = [] + + self.bags.append(newBag) + print(self.bags) + do { + try UserDefaults.standard.setObject(self.bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + self.bagPicker.reloadAllComponents() + })) + self.present(alert, animated: true, completion: nil) + } + + @IBAction func DeleteBag(_ sender: Any) { + if (bags.count > 0){ + bags.remove(at: bagPicker.selectedRow(inComponent: 0)) + bagPicker.selectRow(0, inComponent: 0, animated: true) + bagPicker.reloadAllComponents() + pocketsTable.reloadData() + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + } + } + + @IBAction func SearchBags(_ sender: Any) { + if (bags.count > 0){ + var searchQuery:String = "" + let alert = UIAlertController(title: "Enter Search String", message: "", preferredStyle: .alert) + alert.addTextField { (textField) in + textField.text = "" + textField.autocapitalizationType = .words + textField.placeholder = "Search for..." + } + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in + let textField = alert?.textFields![0] // Force unwrapping because we know it exists. + print("Text field: \(textField!.text ?? "Search")") + if ((textField!.text ?? "Search") == ""){ + return + } + searchQuery = (textField!.text ?? "Search") + + var didFindMatches = "Matches found:" + var matchesString = "" + + for b in self.bags { + print("searching bag \(b.bagName)") + for p in b.pockets { + print("searching pocket \(p.pocketName)") + for c in p.contents { + if c.containsIgnoringCase(find: searchQuery){ + matchesString.append("\n") + matchesString.append("Found Item: \(c)") + matchesString.append("\n") + matchesString.append("In Pocket: \(p.pocketName)") + matchesString.append("\n") + matchesString.append("Of Bag: \(b.bagName)") + matchesString.append("\n") + } + } + } + } + + if (matchesString == ""){ + didFindMatches = "No Matches Found" + } + + let matchesAlert = UIAlertController(title: didFindMatches, message: matchesString, preferredStyle: .alert) + matchesAlert.addAction( UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in + print("Ok button tapped") + })) + self.present(matchesAlert, animated: true, completion: nil) + })) + self.present(alert, animated: true, completion: nil) + } + } + + @IBAction func AddPocket(_ sender: Any) { + if (bags.count > 0){ + var newPocketName:String = "" + let alert = UIAlertController(title: "Enter Pocket Name", message: "", preferredStyle: .alert) + alert.addTextField { (textField) in + textField.text = "" + textField.autocapitalizationType = .words + textField.placeholder = "Pocket Name" + } + alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in + let textField = alert?.textFields![0] // Force unwrapping because we know it exists. + print("Text field: \(textField!.text ?? "Pocket")") + if ((textField!.text ?? "Pocket") == ""){ + return + } + newPocketName = (textField!.text ?? "Pocket") + + let newPocket:pocket = pocket.init() + newPocket.pocketName = newPocketName + newPocket.contents = [] + + self.bags[self.bagPicker.selectedRow(inComponent: 0)].pockets.append(newPocket) + print(self.bags[self.bagPicker.selectedRow(inComponent: 0)].pockets) + do { + try UserDefaults.standard.setObject(self.bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + self.pocketsTable.reloadData() + })) + self.present(alert, animated: true, completion: nil) + } } - - } +class ViewController2: UIViewController, UITableViewDataSource, UITableViewDelegate { + + var bags:[bag] = [] + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + do { + bags = try UserDefaults.standard.getObject(forKey: "bagsSavedData", castTo: [bag].self) + print(bags) + } catch { + print(error.localizedDescription) + } + return bags[passingValues.bag].pockets[passingValues.pocket].contents.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "pocketitem", for: indexPath) + cell.textLabel?.text = bags[passingValues.bag].pockets[passingValues.pocket].contents[indexPath.row] + return cell + } + + func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { + return true + } + + func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + if editingStyle == .delete { + do { + bags = try UserDefaults.standard.getObject(forKey: "bagsSavedData", castTo: [bag].self) + print(bags) + } catch { + print(error.localizedDescription) + } + print("Delete Item: \(bags[passingValues.bag].pockets[passingValues.pocket].contents[indexPath.row])") + bags[passingValues.bag].pockets[passingValues.pocket].contents.remove(at: indexPath.row) + //tableView.deleteRows(at: [indexPath], with: .fade) + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + itemsTable.reloadData() + } + } + + @IBOutlet var PocketLabel: UILabel! + + @IBOutlet var ItemName: UITextField! + + @IBOutlet var itemsTable: UITableView! + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + + itemsTable.dataSource = self + itemsTable.delegate = self + } + + override func viewWillAppear(_ animated: Bool) { + do { + bags = try UserDefaults.standard.getObject(forKey: "bagsSavedData", castTo: [bag].self) + print(bags) + } catch { + print(error.localizedDescription) + } + itemsTable.reloadData() + PocketLabel.text = bags[passingValues.bag].pockets[passingValues.pocket].pocketName + } + + override func viewWillDisappear(_ animated: Bool) { + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + } + + @IBAction func AddItem(_ sender: Any) { + let newItem = ItemName.text + if (newItem != "" && newItem != nil){ + bags[passingValues.bag].pockets[passingValues.pocket].contents.append(newItem!) + ItemName.text = "" + do { + try UserDefaults.standard.setObject(bags, forKey: "bagsSavedData") + } catch { + print(error.localizedDescription) + } + itemsTable.reloadData() + } + } + + @IBAction func DismissModal(_ sender: Any) { + dismiss(animated: true) + } + + @IBAction func DismissKB(_ sender: Any) { + ItemName.resignFirstResponder() + } + +}