From 90cf68a00d4858d389876b49ddbcd064f4d32ab5 Mon Sep 17 00:00:00 2001 From: IgorChernyshov Date: Mon, 11 Oct 2021 09:32:36 +0300 Subject: [PATCH] Added sort functionality --- Sticky Links.xcodeproj/project.pbxproj | 4 + .../Controllers/CategoryViewController.swift | 82 ++++++++++++------ .../Controllers/LinksViewController.swift | 86 +++++++++++++------ Sticky Links/Model/SortType.swift | 19 ++++ .../Sticky_Links.xcdatamodel/contents | 6 +- Sticky Links/View/Base.lproj/Main.storyboard | 35 +++----- 6 files changed, 153 insertions(+), 79 deletions(-) create mode 100644 Sticky Links/Model/SortType.swift diff --git a/Sticky Links.xcodeproj/project.pbxproj b/Sticky Links.xcodeproj/project.pbxproj index ad1108b..eb8c46b 100644 --- a/Sticky Links.xcodeproj/project.pbxproj +++ b/Sticky Links.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ B290641727040F85004250FA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B290641527040F85004250FA /* LaunchScreen.storyboard */; }; B29064252704152A004250FA /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B29064242704152A004250FA /* WebViewController.swift */; }; B290642727041685004250FA /* CategoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B290642627041685004250FA /* CategoryViewController.swift */; }; + D6D538B527156D87001412AE /* SortType.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D538B427156D87001412AE /* SortType.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -34,6 +35,7 @@ B290641827040F85004250FA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B29064242704152A004250FA /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; B290642627041685004250FA /* CategoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryViewController.swift; sourceTree = ""; }; + D6D538B427156D87001412AE /* SortType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortType.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -102,6 +104,7 @@ isa = PBXGroup; children = ( B290641027040F81004250FA /* Sticky_Links.xcdatamodeld */, + D6D538B427156D87001412AE /* SortType.swift */, ); path = Model; sourceTree = ""; @@ -181,6 +184,7 @@ B290641227040F81004250FA /* Sticky_Links.xcdatamodeld in Sources */, B290640C27040F81004250FA /* LinksViewController.swift in Sources */, B290640827040F81004250FA /* AppDelegate.swift in Sources */, + D6D538B527156D87001412AE /* SortType.swift in Sources */, 18FA0757270DED8100AEC7D8 /* Colors.swift in Sources */, B29064252704152A004250FA /* WebViewController.swift in Sources */, B290642727041685004250FA /* CategoryViewController.swift in Sources */, diff --git a/Sticky Links/Controllers/CategoryViewController.swift b/Sticky Links/Controllers/CategoryViewController.swift index 80d25e7..cfe74db 100644 --- a/Sticky Links/Controllers/CategoryViewController.swift +++ b/Sticky Links/Controllers/CategoryViewController.swift @@ -9,16 +9,41 @@ import UIKit import CoreData class CategoryViewController: UITableViewController { - - - var categoryArray = [Category]() + + // MARK: Properties + var categoryArray = [Category]() var filteredCategoryData: [Category] = [] let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let request : NSFetchRequest = Category.fetchRequest() var searchInProgress: Bool = false + + private var sortType: SortType = .none { + willSet { + // If user taps the same options twice the sort will be reversed + if sortType == newValue { + categoryArray.reverse() + } else { + sortCategories(type: newValue) + } + tableView.reloadData() + } + } + + // MARK: Subviews @IBOutlet weak var searchBar: UISearchBar! @IBOutlet weak var outletSwitch: UISwitch! + private lazy var sortButton: UIBarButtonItem = { + let byName = UIAction(title: "Name") { [weak self] action in + self?.sortType = .name + } + let byDateCreated = UIAction(title: "Date created") { [weak self] action in + self?.sortType = .dateCreated + } + let menu = UIMenu(title: "Sort by", children: [byName, byDateCreated]) + return UIBarButtonItem(title: "Sort by", image: UIImage(systemName: "arrow.up.arrow.down"), primaryAction: nil, menu: menu) + }() + @IBAction func darkAction(_ sender: Any) { if outletSwitch.isOn { view.window?.overrideUserInterfaceStyle = .dark @@ -27,12 +52,13 @@ class CategoryViewController: UITableViewController { view.window?.overrideUserInterfaceStyle = .light UserDefaults.standard.set(false, forKey: "DarkMode") } - } + // MARK: Lifecycle override func viewDidLoad() { super.viewDidLoad() print(FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)) + navigationItem.rightBarButtonItems?.append(sortButton) loadCategory() outletSwitch.isOn = UserDefaults.standard.value(forKey: "DarkMode") as? Bool ?? false @@ -87,7 +113,8 @@ extension CategoryViewController{ } private func deleteContextualAction(forRowat indexPath: IndexPath) -> UIContextualAction { - let action = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in + let action = UIContextualAction(style: .destructive, title: "Delete") { [weak self] action, view, completionHandler in + guard let self = self else { return } var name = "" if self.searchInProgress == true { name = self.filteredCategoryData[indexPath.row].name! @@ -122,12 +149,17 @@ extension CategoryViewController{ var textField = UITextField() let alert = UIAlertController(title: "Add Category", message: "", preferredStyle: .alert) - let addAction = UIAlertAction(title: "Add", style: .default) { (action) in - let categoryName = Category(context: self.context) - categoryName.name = textField.text! - self.categoryArray.append(categoryName) - self.filteredCategoryData.append(categoryName) + let addAction = UIAlertAction(title: "Add", style: .default) { [weak self] (action) in + guard let self = self else { return } + guard let newCategoryName = textField.text else { return } + let newCategory = Category(context: self.context) + newCategory.name = newCategoryName + newCategory.dateCreated = Date() + self.categoryArray.append(newCategory) + self.filteredCategoryData.append(newCategory) + self.sortCategories(type: self.sortType) self.saveCategory() + self.tableView.reloadData() } @@ -152,8 +184,13 @@ extension CategoryViewController{ //MARK: SORTING extension CategoryViewController{ - @IBAction func sortCategory(_ sender: UIBarButtonItem) { - } + private func sortCategories(type: SortType) { + switch type { + case .none: break + case .name: categoryArray.sort { $0.name ?? "" < $1.name ?? "" } + case .dateCreated: categoryArray.sort { $0.dateCreated ?? Date() < $1.dateCreated ?? Date() } + } + } } //MARK: SEARCH BAR @@ -190,25 +227,22 @@ extension CategoryViewController: UISearchBarDelegate{ } } -//MARK: Helper Fucntions - -extension CategoryViewController{ - func saveCategory(){ - do{ +//MARK: Core Data +extension CategoryViewController { + private func saveCategory() { + do { try context.save() - } - catch{ + } catch { print("\(error)") } - tableView.reloadData() } - func loadCategory(){ - do{ + private func loadCategory() { + do { categoryArray = try context.fetch(request) - }catch{ + sortCategories(type: sortType) + } catch { print("\(error)") } - tableView.reloadData() } } diff --git a/Sticky Links/Controllers/LinksViewController.swift b/Sticky Links/Controllers/LinksViewController.swift index 98a7cee..f0c5aa1 100644 --- a/Sticky Links/Controllers/LinksViewController.swift +++ b/Sticky Links/Controllers/LinksViewController.swift @@ -7,9 +7,11 @@ import UIKit import CoreData + class LinksViewController: UITableViewController { - - var links=[Items]() + + // MARK: Properties + var links = [Items]() var filteredLinksData: [Items] = [] var searchInProgress: Bool = false let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext @@ -19,17 +21,39 @@ class LinksViewController: UITableViewController { loadLink() } } - + + private var sortType: SortType = .none { + willSet { + // If user taps the same options twice the sort will be reversed + if sortType == newValue { + links.reverse() + } else { + sortLinks(type: newValue) + } + tableView.reloadData() + } + } + + // MARK: Subviews @IBOutlet weak var searchBar: UISearchBar! - - -// override func viewWillAppear(_ animated: Bool) { -// -// } + + private lazy var sortButton: UIBarButtonItem = { + let byName = UIAction(title: "Name") { [weak self] action in + self?.sortType = .name + } + let byDateCreated = UIAction(title: "Date created") { [weak self] action in + self?.sortType = .dateCreated + } + let menu = UIMenu(title: "Sort by", children: [byName, byDateCreated]) + return UIBarButtonItem(title: "Sort by", image: UIImage(systemName: "arrow.up.arrow.down"), primaryAction: nil, menu: menu) + }() + + // MARK: Lifecycle override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. view.backgroundColor = UIColor.primaryBackgroundColor + navigationItem.rightBarButtonItems?.append(sortButton) searchBar.delegate = self searchBar.autocapitalizationType = .none filteredLinksData = links @@ -77,7 +101,8 @@ extension LinksViewController{ } private func deleteContextualAction(forRowat indexPath: IndexPath) -> UIContextualAction { - let action = UIContextualAction(style: .destructive, title: "Delete") { action, view, completionHandler in + let action = UIContextualAction(style: .destructive, title: "Delete") { [weak self] action, view, completionHandler in + guard let self = self else { return } let title = self.links[indexPath.row].title! let alert = UIAlertController(title: "Are you sure you want to delete this item?", message: "\(title) will be deleted and can't be retrived afterwards", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { _ in @@ -103,13 +128,18 @@ extension LinksViewController{ var textField = UITextField() var linktextField = UITextField() let alert = UIAlertController(title: "Add your favourite Webpages", message: "", preferredStyle: .alert) - let addAction = UIAlertAction(title: "Add", style: .default) { (action) in + let addAction = UIAlertAction(title: "Add", style: .default) { [weak self] (action) in + guard let self = self else { return } + guard let pageTitle = textField.text, let pageLink = linktextField.text else { return } let newLink = Items(context: self.context) - newLink.title = textField.text! - newLink.link = linktextField.text! + newLink.title = pageTitle + newLink.link = pageLink newLink.parentCategory = self.selectedProperty + newLink.dateCreated = Date() self.links.append(newLink) + self.sortLinks(type: self.sortType) self.saveLink() + self.tableView.reloadData() } let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) alert.addTextField { alertTextField in @@ -134,7 +164,12 @@ extension LinksViewController{ //MARK: SORTING extension LinksViewController{ - @IBAction func sortLinksButton(_ sender: UIBarButtonItem) { + private func sortLinks(type: SortType) { + switch type { + case .none: break + case .name: links.sort { $0.title ?? "" < $1.title ?? "" } + case .dateCreated: links.sort { $0.dateCreated ?? Date() < $1.dateCreated ?? Date() } + } } } @@ -162,8 +197,8 @@ extension LinksViewController: UISearchBarDelegate{ searchInProgress = false searchBar.text = "" searchBar.resignFirstResponder() - self.tableView.resignFirstResponder() - self.searchBar.showsCancelButton = false + tableView.resignFirstResponder() + searchBar.showsCancelButton = false tableView.reloadData() } @@ -173,27 +208,22 @@ extension LinksViewController: UISearchBarDelegate{ } -//MARK: Helper Functions +//MARK: Core Data extension LinksViewController{ - func saveLink(){ - do{ + private func saveLink() { + do { try context.save() - } - catch{ + } catch { print("\(error)") } - tableView.reloadData() } - func loadLink(){ - do{ + private func loadLink() { + do { links = try context.fetch(request) - }catch{ + sortLinks(type: sortType) + } catch { print("\(error)") } - tableView.reloadData() } - } - - diff --git a/Sticky Links/Model/SortType.swift b/Sticky Links/Model/SortType.swift new file mode 100644 index 0000000..5034f05 --- /dev/null +++ b/Sticky Links/Model/SortType.swift @@ -0,0 +1,19 @@ +// +// SortType.swift +// Sticky Links +// +// Created by Igor Chernyshov on 12.10.2021. +// + +/// Supported types of items sorting. +enum SortType: String { + + /// Do not sort items. + case `none` + + /// Sort items by name. + case name + + /// Sort items by date created. + case dateCreated +} diff --git a/Sticky Links/Model/Sticky_Links.xcdatamodeld/Sticky_Links.xcdatamodel/contents b/Sticky Links/Model/Sticky_Links.xcdatamodeld/Sticky_Links.xcdatamodel/contents index f67ede3..98f80c4 100644 --- a/Sticky Links/Model/Sticky_Links.xcdatamodeld/Sticky_Links.xcdatamodel/contents +++ b/Sticky Links/Model/Sticky_Links.xcdatamodeld/Sticky_Links.xcdatamodel/contents @@ -1,16 +1,18 @@ + + - - + + \ No newline at end of file diff --git a/Sticky Links/View/Base.lproj/Main.storyboard b/Sticky Links/View/Base.lproj/Main.storyboard index a72a0a7..602813c 100644 --- a/Sticky Links/View/Base.lproj/Main.storyboard +++ b/Sticky Links/View/Base.lproj/Main.storyboard @@ -62,18 +62,11 @@ - - - - - - - - - - - - + + + + + @@ -205,18 +198,11 @@ - - - - - - - - - - - - + + + + + @@ -231,7 +217,6 @@ -