SwiftUI utilities done (for now)

This commit is contained in:
John Estropia
2021-02-21 10:56:27 +09:00
parent f2efe175e5
commit d7b852fca4
25 changed files with 1154 additions and 203 deletions

View File

@@ -72,7 +72,7 @@ extension Modern.ColorsDemo {
// MARK: Private
@LiveList(Modern.ColorsDemo.palettesPublisher)
private var palettes: LiveList<Modern.ColorsDemo.Palette>.Items
private var palettes: ListSnapshot
private let listView: (
_ listPublisher: ListPublisher<Modern.ColorsDemo.Palette>,

View File

@@ -30,14 +30,19 @@ extension Modern.ColorsDemo.UIKit {
return UIViewControllerType(self.palette)
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {
uiViewController.palette = Modern.ColorsDemo.dataStack.monitorObject(
self.palette.object!
)
}
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Void) {}
// MARK: Private
private let palette: ObjectPublisher<Modern.ColorsDemo.Palette>
private var palette: ObjectPublisher<Modern.ColorsDemo.Palette>
}
}

View File

@@ -46,7 +46,10 @@ extension Modern {
static let palettesPublisher: ListPublisher<Modern.ColorsDemo.Palette> = Modern.ColorsDemo.dataStack.publishList(
From<Modern.ColorsDemo.Palette>()
.sectionBy(\.$colorGroup)
.sectionBy(
\.$colorGroup,
sectionIndexTransformer: { $0?.first?.uppercased() }
)
.where(Modern.ColorsDemo.filter.whereClause())
.orderBy(.ascending(\.$hue))
)
@@ -57,7 +60,10 @@ extension Modern {
try! Modern.ColorsDemo.palettesPublisher.refetch(
From<Modern.ColorsDemo.Palette>()
.sectionBy(\.$colorGroup)
.sectionBy(
\.$colorGroup,
sectionIndexTransformer: { $0?.first?.uppercased() }
)
.where(self.filter.whereClause())
.orderBy(.ascending(\.$hue))
)

View File

@@ -15,10 +15,10 @@ extension Modern.ColorsDemo.SwiftUI {
struct DetailView: View {
/**
Sample 1: Setting an `ObjectPublisher` declared as an `@ObservedObject`
Sample 1: Using a `LiveObject` to observe object changes. Note that the `ObjectSnapshot` is always `Optional`
*/
@LiveObject
private var palette: LiveObject<Modern.ColorsDemo.Palette>.Item?
private var palette: ObjectSnapshot<Modern.ColorsDemo.Palette>?
/**
Sample 2: Setting properties that can be binded to controls (`Slider` in this case) by creating custom `@Binding` instances that updates the store when the values change.

View File

@@ -14,22 +14,22 @@ extension Modern.ColorsDemo.SwiftUI {
struct ItemView: View {
/**
Sample 1: Setting an `ObjectPublisher` declared as an `@ObservedObject`
Sample 1: Using a `LiveObject` to observe object changes. Note that the `ObjectSnapshot` is always `Optional`
*/
@LiveObject
private var palette: LiveObject<Modern.ColorsDemo.Palette>.Item?
// MARK: Internal
private var palette: ObjectSnapshot<Modern.ColorsDemo.Palette>?
/**
Sample 2: Initializing a `LiveObject` from an existing `ObjectPublisher`
*/
internal init(_ palette: ObjectPublisher<Modern.ColorsDemo.Palette>) {
self._palette = .init(palette)
}
// MARK: View
/**
Sample 3: Readding values directly from the `ObjectSnapshot`
*/
var body: some View {
if let palette = self.palette {

View File

@@ -14,22 +14,35 @@ extension Modern.ColorsDemo.SwiftUI {
struct ListView: View {
/**
Sample 1: Setting a sectioned `ListPublisher` declared as an `@ObservedObject`
Sample 1: Using a `LiveList` to observe list changes
*/
@LiveList
private var palettes: LiveList<Modern.ColorsDemo.Palette>.Items
private var palettes: ListSnapshot<Modern.ColorsDemo.Palette>
/**
Sample 2: Assigning sections and items of the `ListPublisher` to corresponding `View`s
Sample 2: Initializing a `LiveList` from an existing `ListPublisher`
*/
var body: some View {
return List {
init(
listPublisher: ListPublisher<Modern.ColorsDemo.Palette>,
onPaletteTapped: @escaping (ObjectPublisher<Modern.ColorsDemo.Palette>) -> Void
) {
self._palettes = .init(listPublisher)
self.onPaletteTapped = onPaletteTapped
}
/**
Sample 3: Assigning sections and items of the `ListSnapshot` to corresponding `View`s by using the correct `ForEach` overloads.
*/
var body: some View {
List {
ForEachSection(in: self.palettes) { sectionID, palettes in
ForEach(sectionIn: self.palettes) { section in
Section(header: Text(sectionID)) {
Section(header: Text(section.sectionID)) {
ForEach(palettes) { palette in
ForEach(objectIn: section) { palette in
Button(
action: {
@@ -45,7 +58,7 @@ extension Modern.ColorsDemo.SwiftUI {
}
.onDelete { itemIndices in
self.deleteColors(at: itemIndices, in: sectionID)
self.deleteColors(at: itemIndices, in: section.sectionID)
}
}
}
@@ -53,18 +66,6 @@ extension Modern.ColorsDemo.SwiftUI {
.animation(.default)
.listStyle(PlainListStyle())
.edgesIgnoringSafeArea([])
}
// MARK: Internal
init(
listPublisher: ListPublisher<Modern.ColorsDemo.Palette>,
onPaletteTapped: @escaping (ObjectPublisher<Modern.ColorsDemo.Palette>) -> Void
) {
self._palettes = .init(listPublisher)
self.onPaletteTapped = onPaletteTapped
}

View File

@@ -40,6 +40,15 @@ extension Modern.ColorsDemo.UIKit {
/**
Sample 3: We can end monitoring updates anytime. `removeObserver()` was called here for illustration purposes only. `ObjectMonitor`s safely remove deallocated observers automatically.
*/
var palette: ObjectMonitor<Modern.ColorsDemo.Palette> {
didSet {
oldValue.removeObserver(self)
self.startMonitoringObject()
}
}
deinit {
self.palette.removeObserver(self)
@@ -183,9 +192,8 @@ extension Modern.ColorsDemo.UIKit {
equalTo: view.safeAreaLayoutGuide.leadingAnchor,
constant: 10
),
containerView.bottomAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
constant: -10
containerView.centerYAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.centerYAnchor
),
containerView.trailingAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.trailingAnchor,
@@ -223,8 +231,6 @@ extension Modern.ColorsDemo.UIKit {
// MARK: Private
private let palette: ObjectMonitor<Modern.ColorsDemo.Palette>
@available(*, unavailable)
required init?(coder: NSCoder) {

View File

@@ -15,9 +15,9 @@ extension Modern.ColorsDemo.UIKit {
final class ListViewController: UITableViewController {
/**
Sample 1: Setting up a `DiffableDataSource.TableViewAdapter` that will manage tableView snapshot updates automatically. We can use the built-in `DiffableDataSource.TableViewAdapter` type directly, but in our case we want to enabled `UITableView` cell deletions so we create a custom subclass `DeletionEnabledDataSource` (see declaration below).
Sample 1: Setting up a `DiffableDataSource.TableViewAdapter` that will manage tableView snapshot updates automatically. We can use the built-in `DiffableDataSource.TableViewAdapter` type directly, but in our case we want to enabled `UITableView` cell deletions so we create a custom subclass `CustomDataSource` (see declaration below).
*/
private lazy var dataSource: DiffableDataSource.TableViewAdapter<Modern.ColorsDemo.Palette> = DeletionEnabledDataSource(
private lazy var dataSource: DiffableDataSource.TableViewAdapter<Modern.ColorsDemo.Palette> = CustomDataSource(
tableView: self.tableView,
dataStack: Modern.ColorsDemo.dataStack,
cellProvider: { (tableView, indexPath, palette) in
@@ -54,9 +54,11 @@ extension Modern.ColorsDemo.UIKit {
}
/**
Sample 4: This is the custom `DiffableDataSource.TableViewAdapter` subclass we wrote that enabled swipe-to-delete gestures on the `UITableView`.
Sample 4: This is the custom `DiffableDataSource.TableViewAdapter` subclass we wrote that enabled swipe-to-delete gestures and section index titles on the `UITableView`.
*/
final class DeletionEnabledDataSource: DiffableDataSource.TableViewAdapter<Modern.ColorsDemo.Palette> {
final class CustomDataSource: DiffableDataSource.TableViewAdapter<Modern.ColorsDemo.Palette> {
// MARK: UITableViewDataSource
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
@@ -79,6 +81,16 @@ extension Modern.ColorsDemo.UIKit {
break
}
}
override func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return self.sectionIndexTitlesForAllSections().compactMap({ $0 })
}
override func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
return index
}
}