Skip to content

Commit c41683d

Browse files
authored
Merge pull request #37 from SubvertDev/feature/page-navigation-input
Page navigation input
2 parents c945406 + 83e3b93 commit c41683d

File tree

5 files changed

+116
-16
lines changed

5 files changed

+116
-16
lines changed

Modules/Sources/ForumFeature/ForumScreen.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public struct ForumScreen: View {
4646
}
4747
}
4848
.scrollContentBackground(.hidden)
49+
.scrollDismissesKeyboard(.immediately)
4950
.refreshable {
5051
await store.send(.onRefresh).finish()
5152
}

Modules/Sources/PageNavigationFeature/PageNavigationFeature.swift

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,20 @@ public struct PageNavigationFeature: Reducer, Sendable {
2222

2323
public init() {}
2424

25+
// MARK: - State
26+
2527
@ObservableState
2628
public struct State: Equatable {
29+
public enum Field: Sendable { case page }
30+
2731
@Shared(.appSettings) var appSettings: AppSettings
2832

2933
let type: PageNavigationType
30-
public var count: Int = 0
31-
public var offset: Int = 0
34+
public var page = "1"
35+
public var count = 0
36+
public var offset = 0
3237
var perPage: Int
38+
public var focus: Field?
3339
public var shouldShow: Bool {
3440
return count > perPage
3541
}
@@ -59,27 +65,65 @@ public struct PageNavigationFeature: Reducer, Sendable {
5965
}
6066
}
6167

62-
public enum Action {
68+
// MARK: - Action
69+
70+
public enum Action: BindableAction {
71+
case binding(BindingAction<State>)
6372
case firstPageTapped
6473
case previousPageTapped
6574
case nextPageTapped
6675
case lastPageTapped
76+
case doneButtonTapped
77+
case onViewTapped
78+
case goToPage(newPage: Int)
6779

6880
case update(count: Int, offset: Int?)
6981
case offsetChanged(to: Int)
7082
}
7183

84+
// MARK: - Body
85+
7286
public var body: some Reducer<State, Action> {
87+
BindingReducer()
88+
7389
Reduce<State, Action> { state, action in
7490
switch action {
91+
case .binding(\.focus):
92+
state.page = String(state.currentPage)
93+
return .none
94+
95+
case .binding:
96+
return .none
97+
98+
case .doneButtonTapped:
99+
state.focus = nil
100+
guard let newPage = Int(state.page) else {
101+
state.page = String(state.currentPage)
102+
return .none
103+
}
104+
guard newPage != state.currentPage else {
105+
return .none
106+
}
107+
return .send(.goToPage(newPage: newPage))
108+
109+
case .goToPage(let newPage):
110+
state.offset = (newPage - 1) * state.perPage
111+
112+
case .onViewTapped:
113+
state.focus = state.focus == nil ? .page : nil
114+
return .none
115+
75116
case .firstPageTapped:
76117
state.offset = 0
118+
state.page = String(state.currentPage)
77119

78120
case .previousPageTapped:
79121
state.offset -= state.perPage
122+
state.page = String(state.currentPage)
80123

81124
case .nextPageTapped:
82125
state.offset += state.perPage
126+
state.page = String(state.currentPage)
83127

84128
case .lastPageTapped:
85129
let targetOffset = state.count - (state.count % state.perPage)
@@ -88,6 +132,7 @@ public struct PageNavigationFeature: Reducer, Sendable {
88132
} else {
89133
state.offset = targetOffset
90134
}
135+
state.page = String(state.currentPage)
91136

92137
case let .update(count: count, offset: offset):
93138
state.count = count

Modules/Sources/PageNavigationFeature/PageNavigationView.swift

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import ComposableArchitecture
1010
import SFSafeSymbols
1111
import Models
1212
import SharedUI
13+
import Perception
1314

1415
public struct PageNavigation: View {
1516

1617
// MARK: - Properties
1718

18-
public var store: StoreOf<PageNavigationFeature>
19+
@Perception.Bindable public var store: StoreOf<PageNavigationFeature>
20+
@FocusState private var focus: PageNavigationFeature.State.Field?
1921

2022
// MARK: - Init
2123

@@ -71,20 +73,55 @@ public struct PageNavigation: View {
7173
.disabled(store.currentPage + 1 > store.totalPages)
7274
}
7375
.overlay {
74-
Text(String("\(store.currentPage) / \(store.totalPages)"))
75-
.font(.subheadline)
76-
.foregroundStyle(Color(.Labels.secondary))
77-
.padding(.vertical, 6)
78-
.padding(.horizontal, 12)
79-
.background(
80-
RoundedRectangle(cornerRadius: 8)
81-
.foregroundStyle(Color(.Background.teritary))
82-
)
83-
.contentTransition(.numericText())
76+
HStack(spacing: 8) {
77+
TextField(String(""), text: $store.page)
78+
.font(.subheadline)
79+
.keyboardType(.numberPad)
80+
.focused($focus, equals: PageNavigationFeature.State.Field.page)
81+
.fixedSize()
82+
.onChange(of: store.page) { newValue in
83+
guard !store.page.isEmpty else { return }
84+
store.page = String(min(Int(store.page.filter(\.isNumber))!, store.totalPages))
85+
}
86+
.toolbar {
87+
ToolbarItemGroup(placement: .keyboard) {
88+
Spacer()
89+
90+
Button {
91+
store.send(.doneButtonTapped)
92+
} label: {
93+
Text("Done", bundle: .module)
94+
}
95+
}
96+
}
97+
.opacity(store.focus == nil ? 0 : 1)
98+
.overlay {
99+
Text(store.page)
100+
.font(.subheadline)
101+
.fixedSize()
102+
.opacity(store.focus == nil ? 1 : 0)
103+
.contentTransition(.numericText())
104+
.animation(.default, value: store.page)
105+
}
106+
107+
Text(verbatim: "/")
108+
.font(.subheadline)
109+
110+
Text(verbatim: "\(store.totalPages)")
111+
.font(.subheadline)
112+
}
113+
.padding(.vertical, 6)
114+
.padding(.horizontal, 12)
115+
.background(
116+
RoundedRectangle(cornerRadius: 8)
117+
.foregroundStyle(Color(.Background.teritary))
118+
)
119+
.onTapGesture {
120+
store.send(.onViewTapped)
121+
}
84122
}
123+
.bind($store.focus, to: $focus)
85124
.listRowSeparator(.hidden)
86-
.animation(.default, value: store.currentPage)
87-
.frame(maxWidth: .infinity, maxHeight: 32)
88125
}
89126

90127
// MARK: - Navigation Arrow
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"sourceLanguage" : "en",
3+
"strings" : {
4+
"Done" : {
5+
"localizations" : {
6+
"ru" : {
7+
"stringUnit" : {
8+
"state" : "translated",
9+
"value" : "Готово"
10+
}
11+
}
12+
}
13+
}
14+
},
15+
"version" : "1.0"
16+
}

Modules/Sources/TopicFeature/TopicScreen.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public struct TopicScreen: View {
5252
}
5353
}
5454
}
55+
.scrollDismissesKeyboard(.immediately)
5556
}
5657
}
5758
.overlay {

0 commit comments

Comments
 (0)