Skip to content

Commit

Permalink
Support for tablerSort with Core Data sources, for #8
Browse files Browse the repository at this point in the history
  • Loading branch information
Reed Es committed Feb 28, 2022
1 parent 3a6c0ba commit edcdd87
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 16 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@ macOS | iOS

## Features

* Convenient display of tabular data from a `RandomAccessCollection` source
* Convenient display of tabular data from a `RandomAccessCollection` or Core Data source
* Presently targeting macOS v11+ and iOS v14+\*\*
* Supporting bound and unbound arrays, and Core Data too
* With bound data, add inline controls to interactively change (and mutate) your data model
* Optional sort by column support, with concise syntax
* Optional sort-by-column support, with concise syntax
* Optional support for colored rows, with selection overlay
* No View type erasure (i.e., use of `AnyView`) which can impact scalability and performance
* No View type erasure (i.e., use of `AnyView`), which can impact scalability and performance
* No external dependencies!

For List-based tables:
* Optional moving of rows through drag and drop
* Support for single-select and multi-select
* Support for no-select, single-select, and multi-select

For ScrollView/LazyVStack-based tables:
* Support for single-select (possibily multi-select in future)
* Support for no-select and single-select (possibily multi-select in future)

For ScrollView/LazyVGrid-based tables:
* Likely the most scalable and efficient, but least flexible
Expand Down Expand Up @@ -145,6 +145,8 @@ private func header(_ ctx: TablerSortContext<Fruit>) -> some View {

When the user clicks on a header column for the first time, it is sorted in ascending order, with an up-arrow "▲" indicator. If clicked a successive time, a descending sort is executed, with a down-arrow "▼" indicator.

For sorting with Core Data, see the _TablerCoreDemo_ app.

## Bound data

macOS | iOS
Expand Down Expand Up @@ -185,7 +187,8 @@ TODO add details here, with example of move action handler.

## See Also

* [TablerDemo](https://github.com/openalloc/TablerDemo) - the demonstration app for this library
* [TablerDemo](https://github.com/openalloc/TablerDemo) - the demonstration app for this library, for `RandomAccessCollection` data sources
* [TablerCoreDemo](https://github.com/openalloc/TablerCoreDemo) - the demonstration app for this library, for Core Data sources

Swift open-source libraries (by the same author):

Expand Down
71 changes: 61 additions & 10 deletions Sources/TablerSort.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,27 @@ where Element: Identifiable
}
}

public extension View {
func tablerSort<Element, Results, T>(_ ctx: TablerSortContext<Element>,
_ results: inout Results,
_ keyPath: KeyPath<Element, T>,
_ onSort: (Element, Element) -> Bool)
extension View {

/// RandomAccessCollection support
public func tablerSort<Element, Results, T>(_ ctx: TablerSortContext<Element>,
_ results: inout Results,
_ keyPath: KeyPath<Element, T>,
_ onSort: (Element, Element) -> Bool)
where Results: RandomAccessCollection & MutableCollection,
Results.Element == Element
{
let otherDirection = updateSort(ctx, keyPath)

if otherDirection == .forward {
results.sort(by: onSort)
} else {
results.sort(by: { !onSort($0, $1) })
}
}

func updateSort<Element, T>(_ ctx: TablerSortContext<Element>,
_ keyPath: KeyPath<Element, T>) -> TablerSort<Element>.Direction {
// NOTE type-erase to track sort state
let anyKeyPath: AnyKeyPath = keyPath

Expand All @@ -87,10 +100,48 @@ public extension View {
// store the new direction for future header taps for the field
ctx.wrappedValue = TablerSort(anyKeyPath, otherDirection)

if otherDirection == .forward {
results.sort(by: onSort)
} else {
results.sort(by: { !onSort($0, $1) })
}
return otherDirection
}
}

@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
public extension View {

/// Core-data support
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Bool >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Bool? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Date >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Date? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Double >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Double?>) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Float >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Float? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int16 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int16? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int32 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int32? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int64 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int64? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int8 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int8? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, Int? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, String >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, String?>) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt16 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt16?>) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt32 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt32?>) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt64 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt64?>) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt8 >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt8? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UInt? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UUID >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }
func tablerSort<E: NSObject>(_ c: TablerSortContext<E>, _ k: KeyPath<E, UUID? >) -> SortDescriptor<E> { SortDescriptor<E>(k, order: xlat(updateSort(c, k))) }

private func xlat<Element>(_ direction: TablerSort<Element>.Direction) -> SortOrder {
direction == .forward ? SortOrder.forward : SortOrder.reverse
}
}

0 comments on commit edcdd87

Please sign in to comment.