Skip to content

Commit 1961116

Browse files
committed
Move schedule day section title calculation logic to view layer
1 parent 6d539e6 commit 1961116

3 files changed

Lines changed: 71 additions & 51 deletions

File tree

Modules/Sources/ScheduleFeature/Schedule/Day/DaySectionFeature.swift

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,10 @@ public struct DaySectionFeature {
1717
case past
1818
case today
1919
case future
20-
21-
fileprivate init(for date: Date, now: Date, calendar: Calendar) {
22-
if calendar.isDate(date, inSameDayAs: now) {
23-
self = .today
24-
} else if date < now {
25-
self = .past
26-
} else {
27-
self = .future
28-
}
29-
}
3020
}
3121

3222
public var id: UUID
3323
var dayDate: DayDate
34-
var title: String = ""
35-
var subtitle: String? = nil
36-
var relativity: Relativity = .future
3724
var pairRows: IdentifiedArrayOf<PairRowFeature.State>
3825

3926
init(
@@ -61,40 +48,65 @@ public struct DaySectionFeature {
6148

6249
@CasePathable
6350
public enum Action {
64-
case onAppear
6551
case pairRows(IdentifiedActionOf<PairRowFeature>)
6652
}
6753

68-
@Dependency(\.date.now) var now
69-
@Dependency(\.calendar) var calendar
70-
7154
public var body: some ReducerOf<Self> {
72-
Reduce { state, action in
73-
switch action {
74-
case .onAppear:
75-
switch state.dayDate {
76-
case .continuousDate(let date, let weekNumber):
77-
state.title = String(localized: "screen.schedule.day.title.\(date.formatted(.scheduleDay)).\(weekNumber)")
78-
state.subtitle = Self.relativeFormatter.relativeName(for: date, now: now)
79-
state.relativity = State.Relativity(for: date, now: now, calendar: calendar)
80-
case .weekday(let weekday):
81-
state.title = weekday.localizedName(in: calendar).capitalized
82-
state.subtitle = nil
83-
state.relativity = .future
84-
case .examDate(let date):
85-
state.title = date?.formatted(.examDay) ?? "-/-"
86-
state.subtitle = date.flatMap { Self.relativeFormatter.relativeName(for: $0, now: now) }
87-
state.relativity = date.map { State.Relativity(for: $0, now: now, calendar: calendar) } ?? .future
88-
}
89-
return .none
90-
case .pairRows:
91-
return .none
92-
}
93-
}
55+
EmptyReducer()
9456
.forEach(\.pairRows, action: \.pairRows) {
9557
PairRowFeature()
9658
}
9759
}
9860

61+
}
62+
63+
// MARK: - Helpers
64+
65+
extension DaySectionFeature.State.DayDate {
66+
var title: String {
67+
switch self {
68+
case .continuousDate(let date, let weekNumber):
69+
return String(localized: "screen.schedule.day.title.\(date.formatted(.scheduleDay)).\(weekNumber)")
70+
case .weekday(let weekday):
71+
@Dependency(\.calendar) var calendar
72+
return weekday.localizedName(in: calendar).capitalized
73+
case .examDate(let date):
74+
return date?.formatted(.examDay) ?? "-/-"
75+
}
76+
}
77+
78+
func subtitle(for now: Date) -> String? {
79+
switch self {
80+
case .continuousDate(let date, _):
81+
Self.relativeFormatter.relativeName(for: date, now: now)
82+
case .weekday:
83+
nil
84+
case .examDate(let date):
85+
date.flatMap { Self.relativeFormatter.relativeName(for: $0, now: now) }
86+
}
87+
}
88+
89+
func relativity(for now: Date) -> DaySectionFeature.State.Relativity {
90+
switch self {
91+
case .continuousDate(let date, let weekNumber):
92+
relativity(for: date, now: now)
93+
case .weekday(let weekday):
94+
.future
95+
case .examDate(let date):
96+
date.map { relativity(for: $0, now: now) } ?? .future
97+
}
98+
}
99+
100+
private func relativity(for date: Date, now: Date) -> DaySectionFeature.State.Relativity {
101+
@Dependency(\.calendar) var calendar
102+
if calendar.isDate(date, inSameDayAs: now) {
103+
return .today
104+
} else if date < now {
105+
return .past
106+
} else {
107+
return .future
108+
}
109+
}
110+
99111
private static let relativeFormatter = RelativeDateTimeFormatter.relativeNameOnly()
100112
}

Modules/Sources/ScheduleFeature/Schedule/Day/DaySectionView.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import ComposableArchitecture
44

55
struct DaySectionView: View {
66
let store: StoreOf<DaySectionFeature>
7+
@State var title: String = ""
8+
@State var subtitle: String? = nil
9+
@State var relativity: ScheduleDateTitle.Relativity = .upcoming
710

811
var body: some View {
912
WithPerceptionTracking {
@@ -16,16 +19,25 @@ struct DaySectionView: View {
1619
content: { PairRowView(store: $0) }
1720
)
1821
.transformEnvironment(\.pairFilteringMode) { mode in
19-
if store.relativity == .past { mode = .filter }
22+
// Filter all pairs in passed section
23+
if relativity == .passed { mode = .filter }
2024
}
2125
} header:{
2226
ScheduleDateTitle(
23-
date: store.title,
24-
relativeDate: store.subtitle,
25-
relativity: ScheduleDateTitle.Relativity(store.relativity)
27+
date: title,
28+
relativeDate: subtitle,
29+
relativity: relativity
2630
)
2731
.transaction { $0.animation = nil }
28-
.onAppear { store.send(.onAppear) }
32+
.onAppear {
33+
// This data is dynamic and depends on `.now` value
34+
// We should recalculate it every time view appears
35+
// It is intentionally moved to view layer to prevent
36+
// spamming store with `onAppear` events too often
37+
title = store.dayDate.title
38+
subtitle = store.dayDate.subtitle(for: .now)
39+
relativity = ScheduleDateTitle.Relativity(store.dayDate.relativity(for: .now))
40+
}
2941
}
3042
}
3143
}

Modules/Sources/ScheduleFeature/Schedule/List/ScheduleListView.swift

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,9 @@ private struct ScheduleContentListView: View {
4444
}
4545
}
4646

47-
ForEach(
48-
store.scope(
49-
state: \.days,
50-
action: \.days
51-
),
52-
content: DaySectionView.init
53-
)
47+
ForEach(store.scope(state: \.days, action: \.days)) { store in
48+
DaySectionView(store: store)
49+
}
5450

5551
switch store.loading {
5652
case .loadMore:

0 commit comments

Comments
 (0)