Skip to content

Commit fd724c4

Browse files
authored
Release 1.1.0 (#4)
Release `1.1.0`
2 parents 816bbe2 + f8ff627 commit fd724c4

5 files changed

Lines changed: 100 additions & 13 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
- name: ${{ matrix.name }}
5555
run: xcodebuild test -scheme "Blade-Package" -destination "platform=macOS" clean -enableCodeCoverage YES ${{ matrix.params }} -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
5656
- name: Upload coverage reports to Codecov
57-
uses: codecov/codecov-action@v3.1.0
57+
uses: codecov/codecov-action@v4.5.0
5858
with:
5959
token: ${{ secrets.CODECOV_TOKEN }}
6060
xcode: true
@@ -116,7 +116,7 @@ jobs:
116116
- name: ${{ matrix.name }}
117117
run: xcodebuild test -scheme "Blade-Package" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES ${{ matrix.params }} -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
118118
- name: Upload coverage reports to Codecov
119-
uses: codecov/codecov-action@v3.1.0
119+
uses: codecov/codecov-action@v4.5.0
120120
with:
121121
token: ${{ secrets.CODECOV_TOKEN }}
122122
xcode: true
@@ -155,7 +155,7 @@ jobs:
155155
- name: ${{ matrix.name }}
156156
run: xcodebuild test -scheme "Blade-Package" -destination "${{ matrix.destination }}" clean -enableCodeCoverage YES ${{ matrix.params }} -resultBundlePath "test_output/${{ matrix.name }}.xcresult" || exit 1
157157
- name: Upload coverage reports to Codecov
158-
uses: codecov/codecov-action@v3.1.0
158+
uses: codecov/codecov-action@v4.5.0
159159
with:
160160
token: ${{ secrets.CODECOV_TOKEN }}
161161
xcode: true

CHANGELOG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22
All notable changes to this project will be documented in this file.
33

44
#### 1.x Releases
5-
- `1.0.x` Releases - [1.0.0](#100)
5+
- `1.0.x` Releases - [1.0.0](#100) | [1.1.0](#110)
6+
7+
## [1.1.0](https://github.com/space-code/blade/releases/tag/1.1.0)
8+
Released on 2024-08-26.
9+
10+
#### Added
11+
- Integrate header and footer views into the list view.
12+
- Added in Pull Request [#3](https://github.com/space-code/blade/pull/3).
613

714
## [1.0.0](https://github.com/space-code/blade/releases/tag/1.0.0)
815
Released on 2024-02-05.
916

1017
#### Added
1118
- Initial release of Blade.
12-
- Added by [Nikita Vasilev](https://github.com/nik3212).
19+
- Added by [Nikita Vasilev](https://github.com/nik3212).

Sources/BladeTCA/Classes/Presentation/ViewModifiers/LoadingViewModifier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct LoadingViewModifier: ViewModifier {
1313
// MARK: ViewModifier
1414

1515
func body(content: Content) -> some View {
16-
VStack {
16+
Group {
1717
content
1818

1919
if isLoading {

Sources/BladeTCA/Classes/Presentation/Views/PaginatorListView.swift

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,88 @@ import BladeTCA
77
import ComposableArchitecture
88
import SwiftUI
99

10+
// MARK: - PaginatorListView
11+
1012
public struct PaginatorListView<
1113
State: Equatable & Identifiable,
1214
Action: Equatable,
15+
Header: View,
1316
Body: View,
17+
Footer: View,
1418
PositionType: Equatable,
1519
Request: Equatable
1620
>: View {
1721
// MARK: Types
1822

1923
private typealias StoreType = ViewStoreOf<PaginatorReducer<State, Action, PositionType, Request>>
2024

25+
@SwiftUI.State private var isLoading = false
26+
2127
// MARK: Properties
2228

2329
public let store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>
30+
public let header: () -> Header
2431
public let content: (State) -> Body
32+
public let footer: () -> Footer
2533

2634
public init(
2735
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
28-
content: @escaping (State) -> Body
36+
@ViewBuilder header: @escaping () -> Header,
37+
@ViewBuilder content: @escaping (State) -> Body,
38+
@ViewBuilder footer: @escaping () -> Footer
2939
) {
3040
self.store = store
41+
self.header = header
3142
self.content = content
43+
self.footer = footer
3244
}
3345

3446
// MARK: View
3547

3648
public var body: some View {
37-
WithViewStore(store, observe: { $0 }) { (viewStore: StoreType) in
38-
List(viewStore.items) { item in
39-
content(item)
40-
.onAppear {
41-
viewStore.send(.itemAppeared(item.id))
49+
List {
50+
Section {
51+
header()
52+
}
53+
54+
WithViewStore(store, observe: { $0 }) { (viewStore: StoreType) in
55+
Section(content: {
56+
ForEach(viewStore.items) { item in
57+
content(item)
58+
.onAppear {
59+
viewStore.send(.itemAppeared(item.id))
60+
}
4261
}
62+
})
63+
}
64+
65+
Section {
66+
footer()
67+
}
68+
69+
Section {
70+
EmptyView()
71+
.modifier(LoadingViewModifier(isLoading: isLoading))
4372
}
44-
.modifier(LoadingViewModifier(isLoading: viewStore.isLoading && !viewStore.items.isEmpty))
4573
}
4674
}
4775
}
76+
77+
public extension PaginatorListView where Header == EmptyView, Footer == EmptyView {
78+
init(
79+
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
80+
@ViewBuilder content: @escaping (State) -> Body
81+
) {
82+
self.init(store: store, header: { EmptyView() }, content: content, footer: { EmptyView() })
83+
}
84+
}
85+
86+
public extension PaginatorListView where Header: View, Footer == EmptyView {
87+
init(
88+
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
89+
header: @escaping () -> Header,
90+
@ViewBuilder content: @escaping (State) -> Body
91+
) {
92+
self.init(store: store, header: header, content: content, footer: { EmptyView() })
93+
}
94+
}

Sources/BladeTCA/Classes/Presentation/Views/PaginatorView.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ public struct PaginatorView<
1414
Action: Equatable,
1515
PositionType: Equatable,
1616
Request: Equatable,
17+
Header: View,
1718
Body: View,
19+
Footer: View,
1820
RowContent: View
1921
>: View {
2022
// MARK: Types
@@ -24,35 +26,66 @@ public struct PaginatorView<
2426
// MARK: Properties
2527

2628
public let store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>
29+
public let header: () -> Header
2730
public let content: ([State], @escaping (State) -> AnyView) -> Body
31+
public let footer: () -> Footer
2832
public let rowContent: (State) -> RowContent
2933

3034
// MARK: Initialization
3135

3236
public init(
3337
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
38+
@ViewBuilder header: @escaping () -> Header,
3439
@ViewBuilder content: @escaping ([State], @escaping (State) -> AnyView) -> Body,
40+
@ViewBuilder footer: @escaping () -> Footer,
3541
@ViewBuilder rowContent: @escaping (State) -> RowContent
3642
) {
3743
self.store = store
44+
self.header = header
3845
self.content = content
46+
self.footer = footer
3947
self.rowContent = rowContent
4048
}
4149

4250
// MARK: View
4351

4452
public var body: some View {
4553
WithViewStore(store, observe: { $0 }) { (viewStore: StoreType) in
54+
header()
55+
4656
content(viewStore.items.elements) { item in
4757
rowContent(item)
4858
.onAppear { viewStore.send(.itemAppeared(item.id)) }
4959
.any
5060
}
5161
.modifier(LoadingViewModifier(isLoading: viewStore.isLoading && !viewStore.items.isEmpty))
62+
63+
footer()
5264
}
5365
}
5466
}
5567

68+
public extension PaginatorView where Header == EmptyView, Footer == EmptyView {
69+
init(
70+
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
71+
@ViewBuilder content: @escaping ([State], @escaping (State) -> AnyView) -> Body,
72+
@ViewBuilder rowContent: @escaping (State) -> RowContent
73+
) {
74+
self.init(store: store, header: { EmptyView() }, content: content, footer: { EmptyView() }, rowContent: rowContent)
75+
}
76+
}
77+
78+
public extension PaginatorView where Header: View, Footer == EmptyView {
79+
init(
80+
store: Store<PaginatorState<State, PositionType>, PaginatorAction<State, Action, Request>>,
81+
header: @escaping () -> Header,
82+
@ViewBuilder content: @escaping ([State], @escaping (State) -> AnyView) -> Body,
83+
@ViewBuilder rowContent: @escaping (State) -> RowContent
84+
) {
85+
self.init(store: store, header: header, content: content, footer: { EmptyView() }, rowContent: rowContent)
86+
}
87+
}
88+
5689
// MARK: Extension
5790

5891
private extension View {

0 commit comments

Comments
 (0)