Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Modules/Sources/ForumFeature/ForumScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public struct ForumScreen: View {
}
}
.scrollContentBackground(.hidden)
.scrollDismissesKeyboard(.immediately)
.refreshable {
await store.send(.onRefresh).finish()
}
Expand Down
51 changes: 48 additions & 3 deletions Modules/Sources/PageNavigationFeature/PageNavigationFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@ public struct PageNavigationFeature: Reducer, Sendable {

public init() {}

// MARK: - State

@ObservableState
public struct State: Equatable {
public enum Field: Sendable { case page }

@Shared(.appSettings) var appSettings: AppSettings

let type: PageNavigationType
public var count: Int = 0
public var offset: Int = 0
public var page = "1"
public var count = 0
public var offset = 0
var perPage: Int
public var focus: Field?
public var shouldShow: Bool {
return count > perPage
}
Expand Down Expand Up @@ -59,27 +65,65 @@ public struct PageNavigationFeature: Reducer, Sendable {
}
}

public enum Action {
// MARK: - Action

public enum Action: BindableAction {
case binding(BindingAction<State>)
case firstPageTapped
case previousPageTapped
case nextPageTapped
case lastPageTapped
case doneButtonTapped
case onViewTapped
case goToPage(newPage: Int)

case update(count: Int, offset: Int?)
case offsetChanged(to: Int)
}

// MARK: - Body

public var body: some Reducer<State, Action> {
BindingReducer()

Reduce<State, Action> { state, action in
switch action {
case .binding(\.focus):
state.page = String(state.currentPage)
return .none

case .binding:
return .none

case .doneButtonTapped:
state.focus = nil
guard let newPage = Int(state.page) else {
state.page = String(state.currentPage)
return .none
}
guard newPage != state.currentPage else {
return .none
}
return .send(.goToPage(newPage: newPage))

case .goToPage(let newPage):
state.offset = (newPage - 1) * state.perPage

case .onViewTapped:
state.focus = state.focus == nil ? .page : nil
return .none

case .firstPageTapped:
state.offset = 0
state.page = String(state.currentPage)

case .previousPageTapped:
state.offset -= state.perPage
state.page = String(state.currentPage)

case .nextPageTapped:
state.offset += state.perPage
state.page = String(state.currentPage)

case .lastPageTapped:
let targetOffset = state.count - (state.count % state.perPage)
Expand All @@ -88,6 +132,7 @@ public struct PageNavigationFeature: Reducer, Sendable {
} else {
state.offset = targetOffset
}
state.page = String(state.currentPage)

case let .update(count: count, offset: offset):
state.count = count
Expand Down
63 changes: 50 additions & 13 deletions Modules/Sources/PageNavigationFeature/PageNavigationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import ComposableArchitecture
import SFSafeSymbols
import Models
import SharedUI
import Perception

public struct PageNavigation: View {

// MARK: - Properties

public var store: StoreOf<PageNavigationFeature>
@Perception.Bindable public var store: StoreOf<PageNavigationFeature>
@FocusState private var focus: PageNavigationFeature.State.Field?

// MARK: - Init

Expand Down Expand Up @@ -71,20 +73,55 @@ public struct PageNavigation: View {
.disabled(store.currentPage + 1 > store.totalPages)
}
.overlay {
Text(String("\(store.currentPage) / \(store.totalPages)"))
.font(.subheadline)
.foregroundStyle(Color(.Labels.secondary))
.padding(.vertical, 6)
.padding(.horizontal, 12)
.background(
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color(.Background.teritary))
)
.contentTransition(.numericText())
HStack(spacing: 8) {
TextField(String(""), text: $store.page)
.font(.subheadline)
.keyboardType(.numberPad)
.focused($focus, equals: PageNavigationFeature.State.Field.page)
.fixedSize()
.onChange(of: store.page) { newValue in
guard !store.page.isEmpty else { return }
store.page = String(min(Int(store.page.filter(\.isNumber))!, store.totalPages))
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()

Button {
store.send(.doneButtonTapped)
} label: {
Text("Done", bundle: .module)
}
}
}
.opacity(store.focus == nil ? 0 : 1)
.overlay {
Text(store.page)
.font(.subheadline)
.fixedSize()
.opacity(store.focus == nil ? 1 : 0)
.contentTransition(.numericText())
.animation(.default, value: store.page)
}

Text(verbatim: "/")
.font(.subheadline)

Text(verbatim: "\(store.totalPages)")
.font(.subheadline)
}
.padding(.vertical, 6)
.padding(.horizontal, 12)
.background(
RoundedRectangle(cornerRadius: 8)
.foregroundStyle(Color(.Background.teritary))
)
.onTapGesture {
store.send(.onViewTapped)
}
}
.bind($store.focus, to: $focus)
.listRowSeparator(.hidden)
.animation(.default, value: store.currentPage)
.frame(maxWidth: .infinity, maxHeight: 32)
}

// MARK: - Navigation Arrow
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"sourceLanguage" : "en",
"strings" : {
"Done" : {
"localizations" : {
"ru" : {
"stringUnit" : {
"state" : "translated",
"value" : "Готово"
}
}
}
}
},
"version" : "1.0"
}
1 change: 1 addition & 0 deletions Modules/Sources/TopicFeature/TopicScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public struct TopicScreen: View {
}
}
}
.scrollDismissesKeyboard(.immediately)
}
}
.overlay {
Expand Down