passforios/pass/Services/PasswordNavigationDataSource.swift

112 lines
3.6 KiB
Swift
Raw Normal View History

2021-01-17 19:49:05 -08:00
//
// PasswordNavigationDataSource.swift
// pass
//
// Created by Sun, Mingshen on 1/16/21.
// Copyright © 2021 Bob Sun. All rights reserved.
//
import passKit
2021-01-31 13:17:37 +01:00
import UIKit
2021-01-17 19:49:05 -08:00
struct Section {
var title: String
var entries: [PasswordTableEntry]
}
class PasswordNavigationDataSource: NSObject, UITableViewDataSource {
var sections: [Section]
var filteredSections: [Section]
var isSearchActive = false
let hideSectionHeaderThreshold = 6
init(entries: [PasswordTableEntry] = []) {
2021-01-31 13:17:37 +01:00
self.sections = buildSections(from: entries)
self.filteredSections = sections
2021-01-17 19:49:05 -08:00
}
2021-01-31 13:17:37 +01:00
func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int {
2021-01-17 19:49:05 -08:00
filteredSections[section].entries.count
}
2021-01-31 13:17:37 +01:00
func tableView(_: UITableView, titleForHeaderInSection section: Int) -> String? {
2021-01-17 19:49:05 -08:00
showSectionTitles() ? filteredSections[section].title : nil
}
2021-01-31 13:17:37 +01:00
func tableView(_: UITableView, sectionForSectionIndexTitle _: String, at index: Int) -> Int {
2021-01-17 19:49:05 -08:00
index
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) as! PasswordTableViewCell
let entry = getPasswordTableEntry(at: indexPath)
cell.configure(with: entry)
return cell
}
2021-01-31 13:17:37 +01:00
func numberOfSections(in _: UITableView) -> Int {
2021-01-17 19:49:05 -08:00
filteredSections.count
}
func sectionIndexTitles(for _: UITableView) -> [String]? {
showSectionTitles() ? filteredSections.map(\.title) : nil
}
func showSectionTitles() -> Bool {
!isSearchActive && filteredSections.count > hideSectionHeaderThreshold
}
func getPasswordTableEntry(at indexPath: IndexPath) -> PasswordTableEntry {
filteredSections[indexPath.section].entries[indexPath.row]
}
func showTableEntries(matching text: String) {
guard !text.isEmpty else {
filteredSections = sections
return
}
filteredSections = sections.map { section in
let entries = section.entries.filter { $0.match(text) }
return Section(title: section.title, entries: entries)
}
.filter { !$0.entries.isEmpty }
}
func showUnsyncedTableEntries() {
filteredSections = sections.map { section in
let entries = section.entries.filter { !$0.synced }
return Section(title: section.title, entries: entries)
}
.filter { !$0.entries.isEmpty }
}
}
private func buildSections(from entries: [PasswordTableEntry]) -> [Section] {
let collation = UILocalizedIndexedCollation.current()
let sectionTitles = collation.sectionIndexTitles
var sections = [Section]()
// initialize all sections
for titleNumber in 0 ..< sectionTitles.count {
sections.append(Section(title: sectionTitles[titleNumber], entries: [PasswordTableEntry]()))
}
// put entries into sections
for entry in entries {
let sectionNumber = collation.section(for: entry, collationStringSelector: #selector(getter: PasswordTableEntry.title))
sections[sectionNumber].entries.append(entry)
}
// sort each list and set sectionTitles
for titleNumber in 0 ..< sectionTitles.count {
let entriesToSort = sections[titleNumber].entries
let sortedEntries = collation.sortedArray(from: entriesToSort, collationStringSelector: #selector(getter: PasswordTableEntry.title))
sections[titleNumber].entries = sortedEntries as! [PasswordTableEntry]
}
// only keep non-empty sections
return sections.filter { !$0.entries.isEmpty }
}