Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Searchable Push Row for Eureka
import Eureka
open class _SearchablePushRow<T: Equatable, Cell: CellType> : TableSelectorRow<Cell, SearchableViewController<T>> where Cell: BaseCell, Cell: TypedCellType, Cell.Value == T, T: SearchableItem, T: CustomStringConvertible {
public required init(tag: String?) {
super.init(tag: tag)
onCreateControllerCallback = { [weak self] _ in
let controller = SearchableViewController<T>()
controller.searchPlaceholder = self?.searchPlaceholder
return controller
}
}
var searchPlaceholder: String?
}
/// Selector Controller (used to select one option among a list)
open class SearchableViewController<T:Equatable> : _SearchableViewController<T, ListCheckRow<T>, T> where T:SearchableItem, T: CustomStringConvertible {
}
open class _SearchableViewController<T: Equatable, Row: SelectableRowType, TOriginal:Equatable> : UITableViewController, UISearchResultsUpdating, TypedRowControllerType where Row: BaseRow, Row: TypedRowType, Row.Cell.Value == T, T: SearchableItem, T: CustomStringConvertible, TOriginal: SearchableItem, TOriginal: CustomStringConvertible {
/// A closure to be called when the controller disappears.
public var onDismissCallback: ((UIViewController) -> ())?
open var row: RowOf<Row.Cell.Value>!
let searchController = UISearchController(searchResultsController: nil)
required public init() {
super.init(style: .grouped)
self.navigationItem.titleView = self.searchController.searchBar
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = false
self.definesPresentationContext = true
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var originalOptions = [T]()
var currentOptions = [T]()
var searchPlaceholder: String?
open override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
searchController.searchBar.placeholder = searchPlaceholder
//tableView!.tableHeaderView = searchController.searchBar
if let options = row.dataProvider?.arrayData {
self.originalOptions = options
self.currentOptions = options
}
self.tableView.reloadData()
}
fileprivate func filter(_ query: String) {
if query == "" {
currentOptions = self.originalOptions
} else {
currentOptions = self.originalOptions.filter{ $0.matchesSearchQuery(query) }
}
self.tableView.reloadData()
}
open override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
open override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return self.row?.title
}
open override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentOptions.count
}
open override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let option = self.currentOptions[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = option.description
return cell
}
open override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let option = self.currentOptions[indexPath.row]
row.value = option
onDismissCallback?(self)
}
open func updateSearchResults(for searchController: UISearchController) {
filter(searchController.searchBar.text!)
}
}
/// Generic row type where a user must select a value among several options.
open class TableSelectorRow<Cell: CellType, VCType: TypedRowControllerType>: OptionsRow<Cell> where Cell: BaseCell, VCType: UITableViewController, VCType.RowValue == Cell.Value {
open var onCreateControllerCallback : ((FormViewController)->(VCType))?
required public init(tag: String?) {
super.init(tag: tag)
}
/**
Extends `didSelect` method
*/
open override func customDidSelect() {
super.customDidSelect()
if isDisabled {
return
}
guard let createController = onCreateControllerCallback else {
return
}
let controller = createController(cell.formViewController()!)
prepareSelector(controller: controller)
let formViewController = cell.formViewController()!
formViewController.show(controller, sender: nil)
}
/**
Prepares the pushed row setting its title and completion callback.
*/
open override func prepare(for segue: UIStoryboardSegue) {
super.prepare(for: segue)
guard let controller = segue.destination as? VCType else { return }
prepareSelector(controller: controller)
}
fileprivate func prepareSelector(controller: VCType) {
controller.row = self
controller.title = selectorTitle ?? controller.title
controller.onDismissCallback = {vc in
_ = vc.navigationController?.popViewController(animated: true)
}
}
}
public final class SearchablePushRow<T: Equatable> : _SearchablePushRow<T, PushSelectorCell<T>>, RowType where T: SearchableItem, T: CustomStringConvertible {
public required init(tag: String?) {
super.init(tag: tag)
}
}
public protocol SearchableItem {
func matchesSearchQuery(_ query: String) -> Bool
}
@rhalbrook
Copy link

rhalbrook commented Apr 18, 2017

I am kind of new to using Eureka...Do you have any working examples that you could offer, for download, to see this in action?

@MartinP7r
Copy link

MartinP7r commented Sep 4, 2017

would a multiple selector row be impementable with this?

@sarbogast
Copy link

sarbogast commented Jun 27, 2019

Anybody managed to integrate that in the latest versions of Eureka? For me it complains on line 51 about RowOf not having dataProvider anymore, but I can't figure out how to fix this.

@sarbogast
Copy link

sarbogast commented Jun 27, 2019

Actually, for those who are looking for a more recent version that is working perfectly in Swift 5 with the latest version of Eureka, there is one there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment