Skip to content

Commit c2f07f6

Browse files
committed
iOS: [Schedule] Initial schedule list
1 parent dda7350 commit c2f07f6

4 files changed

Lines changed: 115 additions & 12 deletions

File tree

iosApp/OPass/Schedule/ScheduleModel.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@
99
//
1010

1111
import Shared
12+
import SwiftUI
1213
import SwiftDate
1314
import OrderedCollections
1415

16+
enum ScheduleViewState {
17+
case ready(ScheduleData)
18+
case failed(Error)
19+
case loading
20+
}
21+
1522
struct ScheduleData {
1623
let sessions: [(DateInRegion, [(DateInRegion, ArraySlice<Session>)])]
1724
let speakers: OrderedDictionary<String, Speaker>
@@ -20,8 +27,18 @@ struct ScheduleData {
2027
let tags: OrderedDictionary<String, LocalizedObject>
2128
}
2229

23-
enum ScheduleViewState {
24-
case ready(ScheduleData)
25-
case failed(Error)
26-
case loading
30+
struct ScheduleFilter: Hashable {
31+
var speaker: Set<String> = []
32+
var type: Set<String> = []
33+
var room: Set<String> = []
34+
var tag: Set<String> = []
35+
var liked = false
36+
var count = 0
37+
}
38+
39+
struct OffsetKey: PreferenceKey {
40+
static var defaultValue: CGFloat = .zero
41+
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
42+
value = nextValue()
43+
}
2744
}

iosApp/OPass/Schedule/ScheduleViewModel.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import Shared
1212
import SwiftUI
13+
import SwiftDate
1314
import Algorithms
1415
import OrderedCollections
1516

@@ -18,11 +19,14 @@ class ScheduleViewModel {
1819
@ObservationIgnored
1920
@AppStorage("EventID") private var eventID = ""
2021

21-
private(set) var schedule: ScheduleData?
22+
private(set) var data: ScheduleData?
2223
private(set) var error: Error?
2324

25+
var filters = ScheduleFilter()
26+
var selectedDay: Int? = 0
27+
2428
var viewState: ScheduleViewState {
25-
if let schedule { return .ready(schedule) }
29+
if let data { return .ready(data) }
2630
if let error { return .failed(error) }
2731
return .loading
2832
}
@@ -75,12 +79,29 @@ class ScheduleViewModel {
7579
let rooms = OrderedDictionary(schedule.rooms.map({ ($0.id, $0) }), uniquingKeysWith: { $1 })
7680
let tags = OrderedDictionary(schedule.tags.map({ ($0.id, $0) }), uniquingKeysWith: { $1 })
7781

78-
return self.schedule = .init(
82+
self.selectedDay = sessions.firstIndex { $0.0.isToday } ?? 0
83+
84+
return self.data = .init(
7985
sessions: sessions,
8086
speakers: speakers,
8187
types: types,
8288
rooms: rooms,
8389
tags: tags
8490
)
8591
}
92+
93+
func filterSessions(_ sessions: [(DateInRegion, [(DateInRegion, ArraySlice<Session>)])]) -> [(DateInRegion, [(DateInRegion, ArraySlice<Session>)])] {
94+
if filters.count == 0 { return sessions }
95+
let s = sessions.map { day in
96+
let daySessions = day.1.compactMap { section in
97+
let filteredSessions = section.1.filter { session in
98+
if !filters.speaker.isEmpty, filters.speaker.isDisjoint(with: session.speakers) { return false }
99+
return true
100+
}
101+
return filteredSessions.isEmpty ? nil : (section.0, ArraySlice(filteredSessions))
102+
}
103+
return (day.0, daySessions)
104+
}
105+
return s
106+
}
86107
}

iosApp/OPass/Schedule/View/ScheduleView.swift

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,21 @@
1010

1111
import Shared
1212
import SwiftUI
13+
import SwiftDate
1314

1415
struct ScheduleView: View {
1516
@State private var viewModel = ScheduleViewModel()
1617

18+
@State var tabProgress: CGFloat = 0
19+
1720
var body: some View {
1821
VStack {
1922
switch viewModel.viewState {
2023
case .ready(let schedule):
21-
VStack {
22-
Text("Loaded")
24+
if schedule.sessions.count == 1 {
25+
sessionList(schedule.sessions[0].1)
26+
} else {
27+
scheduleList(schedule.sessions)
2328
}
2429
case .failed(let error):
2530
ContentUnavailableView(
@@ -35,4 +40,67 @@ struct ScheduleView: View {
3540
.analyticsScreen(name: "ScheduleView")
3641
.environment(viewModel)
3742
}
43+
44+
private func scheduleList(_ schedule: [(DateInRegion, [(DateInRegion, ArraySlice<Session>)])]) -> some View {
45+
GeometryReader {
46+
let size = $0.size
47+
ScrollView(.horizontal) {
48+
LazyHStack(spacing: 0) {
49+
ForEach(schedule, id:\.0) {
50+
sessionList($0.1)
51+
}
52+
}
53+
.scrollTargetLayout()
54+
.overlay {
55+
GeometryReader {
56+
Color.clear
57+
.preference(
58+
key: OffsetKey.self,
59+
value: $0.frame(in: .scrollView(axis: .horizontal)).minX
60+
)
61+
.onPreferenceChange(OffsetKey.self) { value in
62+
tabProgress = max(min((-value / (size.width * CGFloat(schedule.count - 1))), 1), 0)
63+
}
64+
}
65+
}
66+
}
67+
.scrollPosition(id: $viewModel.selectedDay)
68+
.scrollTargetBehavior(.paging)
69+
.scrollIndicators(.never)
70+
.ignoresSafeArea(.all, edges: .bottom)
71+
// .background(.listBackground)
72+
}
73+
}
74+
75+
private func sessionList(_ sessions: [(DateInRegion, ArraySlice<Session>)]) -> some View {
76+
ScrollView(.vertical) {
77+
LazyVStack {
78+
ForEach(sessions, id: \.0) { (_, sectionSessions) in
79+
LazyVStack(alignment: .leading, spacing: 0) {
80+
ForEach(sectionSessions, id: \.id) {
81+
Text($0.title)
82+
}
83+
}
84+
}
85+
}
86+
.padding()
87+
88+
}
89+
.containerRelativeFrame(.horizontal)
90+
.scrollIndicators(.automatic)
91+
// .overlay {
92+
// if sessions.isEmpty {
93+
// ContentUnavailableView {
94+
// Label("No Sessions Found", systemImage: "text.badge.xmark")
95+
// } description: {
96+
// Text("Use fewer filters or reset all filters.")
97+
// } actions: {
98+
// Button("Reset Filters") {
99+
// self.filters = .init()
100+
// }
101+
// .bold()
102+
// }
103+
// }
104+
// }
105+
}
38106
}

iosApp/Supporting Files/Localizable.xcstrings

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@
9494
},
9595
"Hello, World!" : {
9696

97-
},
98-
"Loaded" : {
99-
10097
},
10198
"Loading" : {
10299
"localizations" : {

0 commit comments

Comments
 (0)