Skip to content

Commit 8adfea2

Browse files
committed
adds categories view, fixes blinking on categoriesAdmin, adds ScheduleListItem view, adds a bunch of Widgets
1 parent 9e827cc commit 8adfea2

27 files changed

+1376
-38
lines changed

app/LandinhoLib/Sources/Categories/Categories.swift

+43-6
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,77 @@
55
// Created by Mauricio Cardozo on 12/11/23.
66
//
77

8+
import APIClient
9+
import Common
810
import Foundation
911
import ComposableArchitecture
1012
import SwiftUI
1113

14+
// TODO: On tap of a category, @PresentationState present a ScheduleList
15+
1216
public struct Categories: Reducer {
1317
public init() {}
1418

1519
public struct State: Equatable {
1620
public init() {}
21+
22+
public var categoriesState = APIClient<[RaceCategory]>.State(endpoint: "category")
1723
}
1824

1925
public enum Action: Equatable {
2026
case onAppear
27+
case categoriesRequest(APIClient<[RaceCategory]>.Action)
2128
}
2229

2330
public var body: some ReducerOf<Self> {
2431
Reduce { state, action in
2532
switch action {
2633
case .onAppear:
27-
#warning("TODO call API")
34+
return .none
35+
case .categoriesRequest:
2836
return .none
2937
}
3038
}
39+
40+
Scope(state: \.categoriesState, action: /Action.categoriesRequest) {
41+
APIClient()
42+
}
3143
}
3244
}
3345

34-
3546
public struct CategoriesView: View {
36-
public init() {}
47+
public init(store: StoreOf<Categories>) {
48+
self.store = store
49+
}
50+
51+
let store: StoreOf<Categories>
52+
3753
public var body: some View {
38-
VStack {
39-
Text("Placeholder for category list")
54+
WithViewStore(store, observe: { $0 }) { viewStore in
55+
switch viewStore.categoriesState.response {
56+
case .idle:
57+
Text("Idle")
58+
case .loading:
59+
ProgressView()
60+
case .reloading(let categories), .finished(.success(let categories)):
61+
List(categories) { category in
62+
HStack {
63+
VStack(alignment: .leading) {
64+
Text(category.title)
65+
.font(.headline)
66+
// TODO: Request next race for a given category and display it here
67+
Text("We should show what's the next race here, and its time")
68+
.font(.caption)
69+
}
70+
Spacer()
71+
// TODO: Add a way to favorite categories
72+
Image(systemName: "heart")
73+
}
74+
}
75+
case .finished(.failure(let error)):
76+
APIErrorView(error: error)
77+
}
4078
}
41-
.padding()
4279
}
4380
}
4481

app/LandinhoLib/Sources/CategoriesAdmin/Views/CategoriesAdminView.swift

+7-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,13 @@ public struct CategoriesAdminView: View {
2020
public var body: some View {
2121
WithViewStore(store, observe: { $0 }) { viewStore in
2222
switch viewStore.categoryList.response {
23-
case .idle, .loading, .reloading:
23+
case .idle:
24+
Color(.systemBackground)
25+
.opacity(0.01)
26+
.onAppear {
27+
store.send(.onAppear)
28+
}
29+
case .loading, .reloading:
2430
ProgressView()
2531
case .finished(.failure(let error)):
2632
APIErrorView(error: error)
@@ -57,9 +63,6 @@ public struct CategoriesAdminView: View {
5763
}
5864
.navigationTitle("Categories")
5965
.navigationBarTitleDisplayMode(.large)
60-
.onAppear {
61-
store.send(.onAppear)
62-
}
6366
.toolbar {
6467
ToolbarItem {
6568
Button(action: {

app/LandinhoLib/Sources/Common/Race.swift

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
import Foundation
99

1010
public struct Race: Codable, Equatable, Identifiable, Hashable {
11+
public init(id: UUID, title: String, events: [RaceEvent]) {
12+
self.id = id
13+
self.title = title
14+
self.events = events
15+
}
16+
1117
public let id: UUID
1218
public let title: String
1319
public let events: [RaceEvent]

app/LandinhoLib/Sources/Common/RaceEvent.swift

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
import Foundation
99

1010
public struct RaceEvent: Codable, Equatable, Identifiable, Hashable {
11+
public init(id: UUID, title: String, date: Date) {
12+
self.id = id
13+
self.title = title
14+
self.date = date
15+
}
16+
1117
public let id: UUID
1218
public let title: String
1319
public let date: Date

app/LandinhoLib/Sources/ScheduleList/ScheduleList.swift

+61-14
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public struct ScheduleList: Reducer {
2222

2323
let categoryTag: String?
2424

25-
var racesState = APIClient<Race>.State(endpoint: "next-race")
25+
public var racesState = APIClient<ScheduleListResponse>.State(endpoint: "next-race")
2626
}
2727

2828
public enum Action: Equatable {
2929
case onAppear
3030

31-
case racesRequest(APIClient<Race>.Action)
31+
case racesRequest(APIClient<ScheduleListResponse>.Action)
3232
}
3333

3434
public var body: some ReducerOf<Self> {
@@ -45,6 +45,16 @@ public struct ScheduleList: Reducer {
4545
APIClient()
4646
}
4747
}
48+
49+
public struct ScheduleListResponse: Codable, Equatable {
50+
public init(categoryComment: String, nextRace: Race) {
51+
self.categoryComment = categoryComment
52+
self.nextRace = nextRace
53+
}
54+
55+
public let categoryComment: String
56+
public let nextRace: Race
57+
}
4858
}
4959

5060
public struct ScheduleListView: View {
@@ -56,18 +66,17 @@ public struct ScheduleListView: View {
5666

5767
public var body: some View {
5868
WithViewStore(store, observe: { $0 }) { viewStore in
59-
ScrollView {
60-
VStack {
61-
switch viewStore.racesState.response {
62-
case .idle:
63-
Text("idle")
64-
case .loading:
65-
Text("loading")
66-
case .reloading(let race), .finished(.success(let race)):
67-
Text("finished or reloading - \(race.title)")
68-
case .finished(.failure(let error)):
69-
APIErrorView(error: error)
70-
}
69+
List {
70+
switch viewStore.racesState.response {
71+
case .idle:
72+
EmptyView()
73+
case .loading:
74+
ProgressView()
75+
case .reloading(let response), .finished(.success(let response)):
76+
ScheduleListItem(response)
77+
.padding(.vertical)
78+
case .finished(.failure(let error)):
79+
APIErrorView(error: error)
7180
}
7281
}
7382
}
@@ -77,3 +86,41 @@ public struct ScheduleListView: View {
7786
}
7887
}
7988

89+
// TODO: This should not take in an 'internal' model
90+
public struct ScheduleListItem: View {
91+
public init(_ response: ScheduleList.ScheduleListResponse) {
92+
self.response = response
93+
}
94+
95+
let response: ScheduleList.ScheduleListResponse
96+
97+
public var body: some View {
98+
VStack(alignment: .leading) {
99+
Text("Category title")
100+
.font(.callout)
101+
102+
Text(response.nextRace.title)
103+
.font(.title3)
104+
105+
HStack {
106+
RoundedRectangle(cornerRadius: 25.0, style: .continuous)
107+
.frame(maxWidth: 100)
108+
109+
Spacer()
110+
VStack(alignment: .leading) {
111+
112+
113+
ForEach(response.nextRace.events) { event in
114+
HStack {
115+
Text(event.title)
116+
Text(event.date.formatted())
117+
}
118+
.font(.caption)
119+
}
120+
}
121+
}
122+
}
123+
}
124+
}
125+
126+

app/LandinhoLib/Sources/Settings/Settings.swift

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import Foundation
1010
import ComposableArchitecture
1111
import SwiftUI
1212

13+
14+
1315
public struct Settings: Reducer {
1416
public init() {}
1517

@@ -45,6 +47,7 @@ public struct SettingsView: View {
4547
let store: StoreOf<Settings>
4648

4749
public var body: some View {
50+
// TODO: Create an actual settings view instead of just encapsulating Admin
4851
AdminView(store: store.scope(
4952
state: \.adminState,
5053
action: Settings.Action.admin)

app/VroomVroom copy-Info.plist

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict/>
5+
</plist>

0 commit comments

Comments
 (0)