Skip to content

Commit

Permalink
Merge pull request #15 from loloop/mc/event-detail-and-sharing
Browse files Browse the repository at this point in the history
adds event detail and sharing screens
  • Loading branch information
loloop authored Nov 21, 2023
2 parents f9b7e9b + 2b89a17 commit 7cffed1
Show file tree
Hide file tree
Showing 30 changed files with 1,158 additions and 53 deletions.
12 changes: 12 additions & 0 deletions app/LandinhoLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ let package = Package(
.library(name: "RacesAdmin", targets: ["RacesAdmin"]),
.library(name: "ScheduleList", targets: ["ScheduleList"]),
.library(name: "Settings", targets: ["Settings"]),
.library(name: "Sharing", targets: ["Sharing"]),
.library(name: "Widgets", targets: ["Widgets"]),
.library(name: "WidgetUI", targets: ["WidgetUI"]),
],
Expand Down Expand Up @@ -69,6 +70,7 @@ let package = Package(
name: "EventDetail",
dependencies: [
"APIClient",
"WidgetUI",
composable
]),

Expand All @@ -85,6 +87,8 @@ let package = Package(
dependencies: [
"Common",
"ScheduleList",
"EventDetail",
"Sharing",
composable
]),

Expand Down Expand Up @@ -114,6 +118,14 @@ let package = Package(
composable
]),

.target(
name: "Sharing",
dependencies: [
"Common",
"WidgetUI",
composable
]),

.target(
name: "Widgets",
dependencies: [
Expand Down
41 changes: 41 additions & 0 deletions app/LandinhoLib/Sources/Common/Race.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,44 @@ public struct MegaRace: Codable, Equatable, Identifiable, Hashable {
events: events))
}
}

@_spi(Mock) public extension MegaRace {
static var mock: MegaRace {
.init(
id: UUID(),
title: "Fórmula 1 Heineken Grande Prêmio de São Paulo 2021",
shortTitle: "São Paulo",
events: [
.init(
id: UUID(),
title: "Treino Livre 1",
date: Date(),
isMainEvent: false),
.init(
id: UUID(),
title: "Treino Livre 2",
date: Date(),
isMainEvent: false),
.init(
id: UUID(),
title: "Treino Livre 3",
date: Date().advanced(by: 100000),
isMainEvent: false),
.init(
id: UUID(),
title: "Classificação",
date: Date().advanced(by: 100000),
isMainEvent: false),
.init(
id: UUID(),
title: "Corrida",
date: Date().advanced(by: 200000),
isMainEvent: true)
],
category: .init(
id: UUID().uuidString,
title: "Formula 1",
tag: "f1",
comment: "Event data by CalendarioF1.com"))
}
}
189 changes: 185 additions & 4 deletions app/LandinhoLib/Sources/EventDetail/EventDetail.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//
// File.swift
// EventDetail.swift
//
//
// Created by Mauricio Cardozo on 12/11/23.
//

@_spi(Mock) import Common
import Foundation
import ComposableArchitecture
import SwiftUI
Expand All @@ -13,17 +14,36 @@ public struct EventDetail: Reducer {
public init() {}

public struct State: Equatable {
public init() {}
public init(raceID: UUID) {
self.raceID = raceID
self.race = nil
}

public init(race: MegaRace) {
self.raceID = nil
self.race = race
}

let raceID: UUID?
let race: MegaRace?
}

public enum Action: Equatable {
case onAppear
case delegate(DelegateAction)
}

public enum DelegateAction: Equatable {
case onShareTap(race: MegaRace, isSquareAspectRatio: Bool)
}

public var body: some ReducerOf<Self> {
Reduce { state, action in
switch action {
case .onAppear:
// TODO: Fetch from raceID if race is nil
return .none
case .delegate:
return .none
}
}
Expand All @@ -38,9 +58,170 @@ public struct EventDetailView: View {
let store: StoreOf<EventDetail>

public var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
Text("Placeholder")
Group {
WithViewStore(store, observe: { $0 }) { viewStore in
if let race = viewStore.race {
InnerEventDetailView(store: store, race: race)
} else {
ContentUnavailableView(
"Algo de errado aconteceu",
systemImage: "xmark.octagon",
description: Text("Tipo deu ruim MESMO porque ainda não tá pronto"))
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
.background.secondary
)
}
}

struct InnerEventDetailView: View {
let store: StoreOf<EventDetail>
let race: MegaRace

var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 20) {

MainEventsView(events: mainEvents)

RoundedRectangle(cornerRadius: 25.0, style: .continuous)
.frame(height: 200)
.overlay {
// TODO: Track SVG, Apple Map or whatever here
Text("Placeholder - Mapa de pista")
.foregroundStyle(.primary)
.colorInvert()
}

VStack(alignment: .leading) {
Text("Título Completo")
.font(.caption)
Text(race.title)
.font(.title3)
}

VStack(alignment: .leading) {
Text("Eventos")
.font(.title2)

Spacer()

VStack(alignment: .leading) {
ForEach(eventsByDate) { event in
Text(event.date)
.font(.headline)
ForEach(event.events) { innerEvent in
HStack {
Text(innerEvent.title)
.font(.title3)

Spacer()
Text(innerEvent.time)
.fontDesign(.monospaced)
}
}
Spacer()
}

Text("Todos os horários estão no fuso horário do Brasil")
.font(.caption)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
}
.frame(maxWidth: .infinity)
.navigationTitle(race.shortTitle)
.toolbar {
ToolbarItem {
Menu {
Button("Instagram", systemImage: "photo") {
store.send(.delegate(.onShareTap(race: race, isSquareAspectRatio: false)))
}
Button("Quadrado", systemImage: "crop") {
store.send(.delegate(.onShareTap(race: race, isSquareAspectRatio: true)))
}
} label: {
Image(systemName: "square.and.arrow.up")
}
}
}
}

var mainEvents: [RaceEvent] {
race.events.filter { $0.isMainEvent }
}

var eventsByDate: [EventByDate] {
EventByDateFactory.convert(events: race.events)
}
}

struct MainEventsView: View {

let events: [RaceEvent]

var body: some View {
if events.count == 1 {
singleEventView
} else {
multipleEventsView
}
}

var singleEventView: some View {
VStack {
ForEach(events) { event in
HStack {
Text(event.title)
.font(.title)
Spacer()
Text(event.date.formatted(.dateTime.hour().minute()))
.font(.title)
}
.padding()
.padding(.horizontal)
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 25.0, style: .continuous))
.shadow(color: .black.opacity(0.1), radius: 1)
}
}
}

var multipleEventsView: some View {
ScrollView(.horizontal) {
HStack {
ForEach(events) { event in
VStack {
Text(event.title)
.font(.title2)
Spacer()
Text(event.date.formatted(.dateTime.hour().minute()))
.font(.title)
}
.padding()
.padding(.horizontal)
.background(Color(.systemBackground))
.clipShape(RoundedRectangle(cornerRadius: 10.0, style: .continuous))
.shadow(color: .black.opacity(0.1), radius: 1)
}
}
}
.scrollClipDisabled()
.scrollIndicators(.hidden, axes: .horizontal)
}
}

#Preview {
NavigationStack {
EventDetailView(store: .init(initialState: .init(race: .mock), reducer: {
EventDetail()
}))
}
}
Loading

0 comments on commit 7cffed1

Please sign in to comment.