From caa6a4527906b0b7398240b2608c72a9273cb204 Mon Sep 17 00:00:00 2001 From: Christian Elies Date: Sun, 27 Sep 2020 11:02:43 +0200 Subject: [PATCH 1/5] feat(iOS 14): preparations --- .../public/Views/AdvancedList.swift | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/Sources/AdvancedList/public/Views/AdvancedList.swift b/Sources/AdvancedList/public/Views/AdvancedList.swift index 0e174e5..123daf0 100644 --- a/Sources/AdvancedList/public/Views/AdvancedList.swift +++ b/Sources/AdvancedList/public/Views/AdvancedList.swift @@ -104,23 +104,40 @@ extension AdvancedList { } // MARK: - Private helper -extension AdvancedList { +private extension AdvancedList { private func configure(_ configuration: @escaping Configuration) -> Self { var result = self result.configurations.append(configuration) return result } - private func getListView() -> some View { - List { - configurations - .reduce(AnyDynamicViewContent(ForEach(data) { item in - getItemView(item) - })) { (currentView, configuration) in configuration(currentView) } + @ViewBuilder func getListView() -> some View { + #if !os(tvOS) + if #available(iOS 14, macOS 11, *) { + ScrollView { + LazyVStack(alignment: .leading, content: rows) + .padding() + } + } else { + List(content: rows) } + #else + List(content: rows) + #endif + } + + func rows() -> some View { + configurations + .reduce( + AnyDynamicViewContent( + ForEach(data) { item in + getItemView(item) + } + ) + ) { (currentView, configuration) in configuration(currentView) } } - private func getItemView(_ item: Data.Element) -> some View { + func getItemView(_ item: Data.Element) -> some View { content(item) .onAppear { listItemAppears(item) @@ -131,7 +148,7 @@ extension AdvancedList { } } - private func listItemAppears(_ item: Data.Element) { + func listItemAppears(_ item: Data.Element) { guard let pagination = pagination else { return } From 48ce5b0d39e99b363ddf0f68ca1e7928433a4145 Mon Sep 17 00:00:00 2001 From: Christian Elies Date: Fri, 16 Oct 2020 23:41:51 +0200 Subject: [PATCH 2/5] refactor(): added mac catalyst to available check --- Sources/AdvancedList/public/Views/AdvancedList.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/AdvancedList/public/Views/AdvancedList.swift b/Sources/AdvancedList/public/Views/AdvancedList.swift index 123daf0..08e0c76 100644 --- a/Sources/AdvancedList/public/Views/AdvancedList.swift +++ b/Sources/AdvancedList/public/Views/AdvancedList.swift @@ -113,7 +113,7 @@ private extension AdvancedList { @ViewBuilder func getListView() -> some View { #if !os(tvOS) - if #available(iOS 14, macOS 11, *) { + if #available(iOS 14, macOS 11, macCatalyst 14, *) { ScrollView { LazyVStack(alignment: .leading, content: rows) .padding() From 19bd84407c5214d35aef697e04bbdb6bfc7b763a Mon Sep 17 00:00:00 2001 From: Christian Elies Date: Mon, 2 Nov 2020 20:07:33 +0100 Subject: [PATCH 3/5] feat(): implemented support for a custom list view --- .../Models/AnyAdvancedListPagination.swift | 2 +- .../private/Models/ListState+error.swift | 2 +- .../Models/AdvancedListPagination.swift | 2 +- .../Models/AdvancedListPaginationState.swift | 2 +- .../Models/AdvancedListPaginationType.swift | 2 +- .../Models/AnyDynamicViewContent.swift | 10 ++-- .../public/Views/AdvancedList.swift | 48 +++++++++++++------ 7 files changed, 44 insertions(+), 24 deletions(-) rename Sources/AdvancedList/{private => public}/Models/AnyDynamicViewContent.swift (52%) diff --git a/Sources/AdvancedList/private/Models/AnyAdvancedListPagination.swift b/Sources/AdvancedList/private/Models/AnyAdvancedListPagination.swift index 34fe3fb..adbb5e0 100644 --- a/Sources/AdvancedList/private/Models/AnyAdvancedListPagination.swift +++ b/Sources/AdvancedList/private/Models/AnyAdvancedListPagination.swift @@ -1,6 +1,6 @@ // // AnyAdvancedListPagination.swift -// +// AdvancedList // // Created by Christian Elies on 31.07.20. // diff --git a/Sources/AdvancedList/private/Models/ListState+error.swift b/Sources/AdvancedList/private/Models/ListState+error.swift index 0308d24..f38a551 100644 --- a/Sources/AdvancedList/private/Models/ListState+error.swift +++ b/Sources/AdvancedList/private/Models/ListState+error.swift @@ -1,6 +1,6 @@ // // ListState+error.swift -// +// AdvancedList // // Created by Christian Elies on 02.08.20. // diff --git a/Sources/AdvancedList/public/Models/AdvancedListPagination.swift b/Sources/AdvancedList/public/Models/AdvancedListPagination.swift index b07eb2f..5de7ce5 100644 --- a/Sources/AdvancedList/public/Models/AdvancedListPagination.swift +++ b/Sources/AdvancedList/public/Models/AdvancedListPagination.swift @@ -1,6 +1,6 @@ // // AdvancedListPagination.swift -// +// AdvancedList // // Created by Christian Elies on 15.08.19. // diff --git a/Sources/AdvancedList/public/Models/AdvancedListPaginationState.swift b/Sources/AdvancedList/public/Models/AdvancedListPaginationState.swift index de74af9..fdf77a1 100644 --- a/Sources/AdvancedList/public/Models/AdvancedListPaginationState.swift +++ b/Sources/AdvancedList/public/Models/AdvancedListPaginationState.swift @@ -1,6 +1,6 @@ // // AdvancedListPaginationState.swift -// +// AdvancedList // // Created by Christian Elies on 17.08.19. // diff --git a/Sources/AdvancedList/public/Models/AdvancedListPaginationType.swift b/Sources/AdvancedList/public/Models/AdvancedListPaginationType.swift index e84397c..1224e96 100644 --- a/Sources/AdvancedList/public/Models/AdvancedListPaginationType.swift +++ b/Sources/AdvancedList/public/Models/AdvancedListPaginationType.swift @@ -1,6 +1,6 @@ // // AdvancedListPaginationType.swift -// +// AdvancedList // // Created by Christian Elies on 16.08.19. // diff --git a/Sources/AdvancedList/private/Models/AnyDynamicViewContent.swift b/Sources/AdvancedList/public/Models/AnyDynamicViewContent.swift similarity index 52% rename from Sources/AdvancedList/private/Models/AnyDynamicViewContent.swift rename to Sources/AdvancedList/public/Models/AnyDynamicViewContent.swift index 6f3285f..8d727d0 100644 --- a/Sources/AdvancedList/private/Models/AnyDynamicViewContent.swift +++ b/Sources/AdvancedList/public/Models/AnyDynamicViewContent.swift @@ -1,17 +1,19 @@ // // AnyDynamicViewContent.swift -// +// AdvancedList // // Created by Christian Elies on 20.11.19. // import SwiftUI -struct AnyDynamicViewContent: DynamicViewContent { +/// Type erased dynamic view content that generates views from an underlying collection of data. +public struct AnyDynamicViewContent: DynamicViewContent { private let view: AnyView - private(set) var data: AnyCollection - var body: some View { view } + public private(set) var data: AnyCollection + + public var body: some View { view } init(_ view: View) { self.view = AnyView(view) diff --git a/Sources/AdvancedList/public/Views/AdvancedList.swift b/Sources/AdvancedList/public/Views/AdvancedList.swift index 08e0c76..155e505 100644 --- a/Sources/AdvancedList/public/Views/AdvancedList.swift +++ b/Sources/AdvancedList/public/Views/AdvancedList.swift @@ -12,7 +12,8 @@ import SwiftUI /// An `advanced` container that presents rows of data arranged in a single column. /// Built-in `empty`, `error` and `loading` state. /// Supports `lastItem` or `thresholdItem` pagination. -public struct AdvancedList : View where Data.Element: Identifiable { +public struct AdvancedList : View where Data.Element: Identifiable { + public typealias Rows = () -> AnyDynamicViewContent public typealias OnMoveAction = Optional<(IndexSet, Int) -> Void> public typealias OnDeleteAction = Optional<(IndexSet) -> Void> @@ -20,6 +21,7 @@ public struct AdvancedList ListView)? private var content: (Data.Element) -> Content private var listState: Binding private let emptyStateView: () -> EmptyStateView @@ -33,6 +35,30 @@ public struct AdvancedList ListView, @ViewBuilder content: @escaping (Data.Element) -> Content, listState: Binding, @ViewBuilder emptyStateView: @escaping () -> EmptyStateView, @ViewBuilder errorStateView: @escaping (Error) -> ErrorStateView, @ViewBuilder loadingStateView: @escaping () -> LoadingStateView) { + self.data = data + self.listView = listView + self.content = content + self.listState = listState + self.emptyStateView = emptyStateView + self.errorStateView = errorStateView + self.loadingStateView = loadingStateView + configurations = [] + } +} + +extension AdvancedList where ListView == List { + /// Initializes the list with the given values. + /// Uses the native `SwiftUI` `List` as list view. + /// + /// - Parameters: + /// - data: The data for populating the list. /// - content: A view builder that creates the view for a single row of the list. /// - listState: A binding to a property that determines the state of the list. /// - emptyStateView: A view builder that creates the view for the empty state of the list. @@ -46,6 +72,7 @@ public struct AdvancedList some View { - #if !os(tvOS) - if #available(iOS 14, macOS 11, macCatalyst 14, *) { - ScrollView { - LazyVStack(alignment: .leading, content: rows) - .padding() - } - } else { - List(content: rows) - } - #else + func getListView(rows: Rows) -> List { List(content: rows) - #endif } - func rows() -> some View { + func rows() -> AnyDynamicViewContent { configurations .reduce( AnyDynamicViewContent( From 9adb379e6815e6e3ce9a8a6a7232d93bf57780ba Mon Sep 17 00:00:00 2001 From: Christian Elies Date: Mon, 2 Nov 2020 21:05:00 +0100 Subject: [PATCH 4/5] docs(readme): added custom list view information --- README.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0564fd9..562bafe 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,35 @@ AdvancedList(yourData, content: { item in .lineLimit(nil) }, loadingStateView: { Text("Loading ...") -}, pagination: .noPagination) +}) +``` + +### 🆕 Custom List view + +Starting from version `6.0.0` you can use a custom list view instead of the `SwiftUI` `List` used under the hood. As an example you can now easily use the **LazyVStack** introduced in **iOS 14** if needed. + +Upgrade from version `5.0.0` **without breaking anything**. Simply add the **listView parameter** after the upgrade: + +```swift +AdvancedList(yourData, listView: { rows in + if #available(iOS 14, macOS 11, *) { + ScrollView { + LazyVStack(alignment: .leading, content: rows) + .padding() + } + } else { + List(content: rows) + } +}, content: { item in + Text("Item") +}, listState: $listState, emptyStateView: { + Text("No data") +}, errorStateView: { error in + Text(error.localizedDescription) + .lineLimit(nil) +}, loadingStateView: { + Text("Loading ...") +}) ``` ### 📄 Pagination @@ -91,7 +119,7 @@ AdvancedList(yourData, content: { item in .lineLimit(nil) }, loadingStateView: { Text("Loading ...") -}, pagination: .noPagination) +}) .onMove { (indexSet, index) in // move me } @@ -130,7 +158,7 @@ AdvancedList(yourData, content: { item in } }, loadingStateView: { Text("Loading ...") -}, pagination: .noPagination) +}) ``` For more examples take a look at [AdvancedList-SwiftUI](https://github.com/crelies/AdvancedList-SwiftUI). From f3ed518bbd03195afbbedb909f3e1f70398d39c4 Mon Sep 17 00:00:00 2001 From: Christian Elies Date: Mon, 2 Nov 2020 23:38:55 +0100 Subject: [PATCH 5/5] docs(readme): fixed indentation --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 562bafe..5457170 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,14 @@ Upgrade from version `5.0.0` **without breaking anything**. Simply add the **lis ```swift AdvancedList(yourData, listView: { rows in - if #available(iOS 14, macOS 11, *) { - ScrollView { - LazyVStack(alignment: .leading, content: rows) - .padding() - } - } else { - List(content: rows) - } + if #available(iOS 14, macOS 11, *) { + ScrollView { + LazyVStack(alignment: .leading, content: rows) + .padding() + } + } else { + List(content: rows) + } }, content: { item in Text("Item") }, listState: $listState, emptyStateView: {