Skip to content

Commit

Permalink
Merge pull request #9 from loloop/mc/widget-ui
Browse files Browse the repository at this point in the history
adds a new home screen
  • Loading branch information
loloop authored Nov 17, 2023
2 parents c003d33 + 3dbcd46 commit d33ebf5
Show file tree
Hide file tree
Showing 38 changed files with 890 additions and 593 deletions.
43 changes: 30 additions & 13 deletions app/LandinhoLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ let package = Package(
.library(name: "RacesAdmin", targets: ["RacesAdmin"]),
.library(name: "ScheduleList", targets: ["ScheduleList"]),
.library(name: "Settings", targets: ["Settings"]),
.library(name: "Widgets", targets: ["Widgets"]),
.library(name: "WidgetUI", targets: ["WidgetUI"]),
],
dependencies: [
.package(
url: "https://github.com/pointfreeco/swift-composable-architecture",
from: Version(1, 0, 0)),
from: Version(1, 4, 2)),
],
targets: [
.target(
Expand All @@ -38,11 +40,11 @@ let package = Package(
composable
]),

.target(
name: "APIClient",
dependencies: [
composable
]),
.target(
name: "APIClient",
dependencies: [
composable
]),

.target(
name: "Common"),
Expand All @@ -59,17 +61,16 @@ let package = Package(
dependencies: [
"APIClient",
"Common",
"EventsAdmin",
"RacesAdmin",
composable
]),

.target(
name: "EventDetail",
dependencies: [
"APIClient",
composable
]),
.target(
name: "EventDetail",
dependencies: [
"APIClient",
composable
]),

.target(
name: "EventsAdmin",
Expand Down Expand Up @@ -99,7 +100,9 @@ let package = Package(
.target(
name: "ScheduleList",
dependencies: [
"Common",
"EventDetail",
"WidgetUI",
composable
]),

Expand All @@ -110,5 +113,19 @@ let package = Package(
"APIClient",
composable
]),

.target(
name: "Widgets",
dependencies: [
"Common",
"APIClient",
composable
]),

.target(
name: "WidgetUI",
dependencies: [
"Common"
]),
]
)
5 changes: 4 additions & 1 deletion app/LandinhoLib/Sources/APIClient/APIErrorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ public struct APIErrorView: View {
public var body: some View {
// TODO: Don't show description on RELEASE
ContentUnavailableView(
"Something went wrong",
"Algo de errado aconteceu",
systemImage: "xmark.octagon",
description: Text((error as? APIError)?.jsonString ?? ""))
.onAppear {
dump(error as? APIError)
}
}
}
4 changes: 4 additions & 0 deletions app/LandinhoLib/Sources/APIClient/Request.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ public extension Request {
method: "GET")
}

static func get(_ queryItems: [String: String] = [:]) -> Self {
return .get(queryItems: queryItems.map { URLQueryItem(name: $0.key, value: $0.value)})
}

static var get: Self {
Request(
data: nil,
Expand Down
100 changes: 7 additions & 93 deletions app/LandinhoLib/Sources/Admin/Admin.swift
Original file line number Diff line number Diff line change
@@ -1,103 +1,36 @@
//
// File.swift
//
// Admin.swift
//
//
// Created by Mauricio Cardozo on 14/11/23.
//

import ComposableArchitecture
import Foundation
import CategoriesAdmin
import EventsAdmin
import RacesAdmin

// This layer is reserved for future use

public struct Admin: Reducer {
public init() {}

public struct State: Equatable {
public init() {}

var path = StackState<Path.State>()

var categoriesAdminState = CategoriesAdmin.State()
}

public enum Action: Equatable {
case categoriesAdmin(CategoriesAdmin.Action)

// TODO: This should probably be refactored to tree-based navigation, no point in keeping it a stack
// but also no point in refactoring it now
case path(StackAction<Path.State, Path.Action>)
}

public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .categoriesAdmin(.onCategoryTap(let id)):
guard
let categories = state.categoriesAdminState.categoryList.response.value,
let selectedCategory = categories.first(where: { $0.id == id })
else {
return .none
}

state.path.append(
.racesAdmin(
.init(title: selectedCategory.title, tag: selectedCategory.tag)
)
)
return .none

case .path(.element(id: _, action: .racesAdmin(.onRaceTap(let race)))):
state.path.append(
.eventsAdmin(
.init(
id: race.id,
title: race.title)
)
)
return .none

case .categoriesAdmin, .path:
return .none
}
}
.forEach(\.path, action: /Action.path) {
Path()
}

Scope(state: \.categoriesAdminState, action: /Action.categoriesAdmin) {
CategoriesAdmin()
}
}

public struct Path: Reducer {
public init() {}

public enum State: Equatable {
case racesAdmin(RacesAdmin.State)
case eventsAdmin(EventsAdmin.State)
}

public enum Action: Equatable {
case racesAdmin(RacesAdmin.Action)
case eventsAdmin(EventsAdmin.Action)
}

public var body: some ReducerOf<Self> {
Scope(state: /State.racesAdmin, action: /Action.racesAdmin) {
RacesAdmin()
}

Scope(state: /State.eventsAdmin, action: /Action.eventsAdmin) {
EventsAdmin()
}
}
}
}



import SwiftUI

public struct AdminView: View {
Expand All @@ -108,27 +41,8 @@ public struct AdminView: View {
let store: StoreOf<Admin>

public var body: some View {
NavigationStackStore(store.scope(state: \.path, action: Admin.Action.path)) {
CategoriesAdminView(store: store.scope(
state: \.categoriesAdminState,
action: Admin.Action.categoriesAdmin))
} destination: { state in
switch state {
case .racesAdmin:
CaseLet(
/Admin.Path.State.racesAdmin,
action: Admin.Path.Action.racesAdmin,
then: RacesAdminView.init(store:)
)

case .eventsAdmin:
CaseLet(
/Admin.Path.State.eventsAdmin,
action: Admin.Path.Action.eventsAdmin,
then: EventsAdminView.init(store:)
)

}
}
CategoriesAdminView(store: store.scope(
state: \.categoriesAdminState,
action: Admin.Action.categoriesAdmin))
}
}
95 changes: 52 additions & 43 deletions app/LandinhoLib/Sources/CategoriesAdmin/CategoriesAdmin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,47 @@ import APIClient
import Common
import ComposableArchitecture
import Foundation
import EventsAdmin
import RacesAdmin

public struct CategoriesAdmin: Reducer {
import EventsAdmin

extension CategoriesAdmin {
@Reducer
public struct Destination {
public init() {}

public enum State: Equatable {
case categoryEditor(CategoryEditor.State)
case racesAdmin(RacesAdmin.State)
}

public enum Action: Equatable {
case categoryEditor(CategoryEditor.Action)
case racesAdmin(RacesAdmin.Action)
}

public var body: some ReducerOf<Self> {
Scope(state: \.categoryEditor, action: \.categoryEditor) {
CategoryEditor()
}

Scope(state: \.racesAdmin, action: \.racesAdmin) {
RacesAdmin()
}
}
}
}

@Reducer
public struct CategoriesAdmin {
public init() {}

public struct State: Equatable {
public init() {}

@PresentationState var categoryEditorState: CategoryEditor.State?
@PresentationState var destination: Destination.State?

public var categoryList = APIClient<[RaceCategory]>.State(endpoint: "category")
var path = StackState<Path.State>()
}

public enum Action: Equatable {
Expand All @@ -31,8 +59,7 @@ public struct CategoriesAdmin: Reducer {
case onCategoryEditorTap(String)

case categoryRequest(APIClient<[RaceCategory]>.Action)
case categoryEditor(PresentationAction<CategoryEditor.Action>)
case path(StackAction<Path.State, Path.Action>)
case destination(PresentationAction<Destination.Action>)
}

public var body: some ReducerOf<CategoriesAdmin> {
Expand All @@ -43,13 +70,22 @@ public struct CategoriesAdmin: Reducer {
await send(.categoryRequest(.request(.get)))
}

case .onCategoryTap:
// TODO: Add a DelegateAction
// Used to let parent feature know which one has been tapped
case .onCategoryTap(let id):
guard
let categories = state.categoryList.response.value,
let selectedCategory = categories.first(where: { $0.id == id })
else {
return .none
}

state.destination = .racesAdmin(
.init(
title: selectedCategory.title,
tag: selectedCategory.tag))
return .none

case .onPlusTap:
state.categoryEditorState = .init()
state.destination = .categoryEditor(.init())
return .none

case .onCategoryEditorTap(let id):
Expand All @@ -60,52 +96,25 @@ public struct CategoriesAdmin: Reducer {
return .none
}

state.categoryEditorState = .init(category: selectedCategory)
state.destination = .categoryEditor(.init(category: selectedCategory))
return .none

case .categoryEditor(.presented(.categoryRequest(.response(.finished(.success))))):
case .destination(.presented(.categoryEditor(.categoryRequest(.response(.finished(.success)))))):
return .merge(
.send(.onAppear),
.send(.categoryEditor(.dismiss))
.send(.destination(.dismiss))
)

case .categoryRequest, .categoryEditor, .path:
case .categoryRequest, .destination:
return .none
}
}
.ifLet(\.$categoryEditorState, action: /Action.categoryEditor) {
CategoryEditor()
}
.forEach(\.path, action: /Action.path) {
Path()
.ifLet(\.$destination, action: \.destination) {
Destination()
}

Scope(state: \.categoryList, action: /Action.categoryRequest) {
APIClient()
}
}

public struct Path: Reducer {
public init() {}

public enum State: Equatable {
case races(RacesAdmin.State)
case events(EventsAdmin.State)
}

public enum Action: Equatable {
case races(RacesAdmin.Action)
case events(EventsAdmin.Action)
}

public var body: some ReducerOf<Self> {
Scope(state: /State.races, action: /Action.races) {
RacesAdmin()
}

Scope(state: /State.events, action: /Action.events) {
EventsAdmin()
}
}
}
}
Loading

0 comments on commit d33ebf5

Please sign in to comment.