Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ struct RecordDetailFeature {
@ObservableState
struct State: Equatable {
@Presents var alert: AlertState<Action.Alert>?
@Presents var sheet: SheetState?
@Presents var history: RecordHistoryDestination?
@Presents var versionDetail: RecordVersionDetailDestination?
let goalTitle: String
let allowsMutation: Bool
var record: DevelopmentRecord
Expand Down Expand Up @@ -63,6 +66,9 @@ struct RecordDetailFeature {

enum Action: Equatable {
case alert(PresentationAction<Alert>)
case sheet(PresentationAction<Never>)
case history(PresentationAction<Never>)
case versionDetail(PresentationAction<Never>)
case view(ViewAction)
case store(StoreAction)

Expand All @@ -72,7 +78,11 @@ struct RecordDetailFeature {

enum ViewAction: Equatable {
case fetch
case finishEditing
case restore(DevelopmentRecord.Version)
case selectVersion(DevelopmentRecord.Version)
case tapCorrection
case tapHistory
}

enum StoreAction: Equatable {
Expand All @@ -83,6 +93,11 @@ struct RecordDetailFeature {
}
}

@ObservableState
enum SheetState: Equatable {
case editor
}

@Dependency(\.developmentFetchRecordsUseCase) private var fetchRecordsUseCase
@Dependency(\.developmentFetchRecordHistoryUseCase) private var fetchRecordHistoryUseCase
@Dependency(\.developmentRestoreRecordUseCase) private var restoreRecordUseCase
Expand Down Expand Up @@ -114,6 +129,19 @@ struct RecordDetailFeature {
)
case .alert:
break
case .sheet(.dismiss):
state.sheet = nil
case .sheet:
break
case .history(.dismiss):
state.history = nil
state.versionDetail = nil
case .history:
break
case .versionDetail(.dismiss):
state.versionDetail = nil
case .versionDetail:
break
case .view(.fetch):
guard state.contentState != .loading,
!state.isRestoring,
Expand All @@ -122,12 +150,28 @@ struct RecordDetailFeature {
state.contentState = .loading
state.restoredSourceVersionID = nil
return fetchEffect(goalID: state.record.goalId, recordID: state.record.id)
case .view(.finishEditing):
state.sheet = nil
return .send(.view(.fetch))
case .view(.restore(let version)):
guard !state.isRestoring,
state.allowsMutation,
state.record.draft == nil,
version.id != state.currentVersionID else { break }
state.alert = Self.restoreConfirmationAlert(version)
case .view(.selectVersion(let version)):
guard version.id != state.currentVersionID,
state.versions.contains(where: { $0.id == version.id }) else { break }
state.versionDetail = RecordVersionDetailDestination(version: version)
case .view(.tapCorrection):
guard state.allowsMutation,
state.contentState == .loaded,
state.currentVersion != nil else { break }
state.sheet = .editor
case .view(.tapHistory):
guard state.contentState == .loaded,
state.currentVersion != nil else { break }
state.history = RecordHistoryDestination(recordID: state.record.id)
case .store(.loaded(let record, let versions)):
state.record = record
state.versions = versions.sorted { $0.number < $1.number }
Expand Down Expand Up @@ -158,6 +202,18 @@ struct RecordDetailFeature {
}
}

@ObservableState
struct RecordHistoryDestination: Equatable, Identifiable {
let recordID: String
var id: String { recordID }
}

@ObservableState
struct RecordVersionDetailDestination: Equatable, Identifiable {
let version: DevelopmentRecord.Version
var id: String { version.id }
}

private extension RecordDetailFeature {
func fetchEffect(goalID: String, recordID: String) -> Effect<Action> {
.run { [fetchRecordsUseCase, fetchRecordHistoryUseCase] send in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ public struct RecordDetailView: View {
@Environment(\.dismiss) private var dismiss
private let onUpdate: () -> Void
@State private var store: StoreOf<RecordDetailFeature>
@State private var isEditorPresented = false
@State private var isHistoryPresented = false

public init(
goalTitle: String,
Expand Down Expand Up @@ -70,7 +68,7 @@ public struct RecordDetailView: View {
.toolbarVisibility(.hidden, for: .navigationBar)
.onAppear { store.send(.view(.fetch)) }
.prominentAlert(store, state: \.alert, action: \.alert)
.sheet(isPresented: $isEditorPresented) {
.sheet(item: $store.scope(state: \.sheet, action: \.sheet)) { _ in
RecordEditorView(
goalId: store.record.goalId,
goalTitle: store.goalTitle,
Expand All @@ -79,7 +77,10 @@ public struct RecordDetailView: View {
onCompletion: finishEditing
)
}
.navigationDestination(isPresented: $isHistoryPresented, interactivePop: true) {
.navigationDestination(
item: $store.scope(state: \.history, action: \.history),
interactivePop: true
) { _ in
RecordVersionHistoryView(store: store)
}
.overlay {
Expand Down Expand Up @@ -212,7 +213,7 @@ public struct RecordDetailView: View {

private var correctionButton: some View {
Button {
isEditorPresented = true
store.send(.view(.tapCorrection))
} label: {
Label(
RecordPresentation.text("development_record_correct"),
Expand All @@ -228,7 +229,7 @@ public struct RecordDetailView: View {

private var historyButton: some View {
Button {
isHistoryPresented = true
store.send(.view(.tapHistory))
} label: {
Label(
RecordPresentation.text("development_record_history_title"),
Expand All @@ -246,8 +247,7 @@ public struct RecordDetailView: View {
}

private func finishEditing() {
isEditorPresented = false
store.send(.view(.fetch))
store.send(.view(.finishEditing))
onUpdate()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import PresentationShared

struct RecordVersionHistoryView: View {
@Environment(\.dismiss) private var dismiss
@State private var destination: VersionDestination?

let store: StoreOf<RecordDetailFeature>
@Bindable var store: StoreOf<RecordDetailFeature>

private var sortedVersions: [DevelopmentRecord.Version] {
store.versions.sorted { $1.number < $0.number }
Expand All @@ -37,7 +36,10 @@ struct RecordVersionHistoryView: View {
.safeAreaInset(edge: .bottom, spacing: 0) { footer }
.background(Color.appBackground)
.toolbarVisibility(.hidden, for: .navigationBar)
.navigationDestination(item: $destination, interactivePop: true) { destination in
.navigationDestination(
item: $store.scope(state: \.versionDetail, action: \.versionDetail),
interactivePop: true
) { destination in
RecordVersionDetailView(
store: store,
version: destination.version
Expand Down Expand Up @@ -106,7 +108,7 @@ struct RecordVersionHistoryView: View {
if version.id == store.currentVersionID {
dismiss()
} else {
destination = VersionDestination(version: version)
store.send(.view(.selectVersion(version)))
}
} label: {
VersionHistoryRow(
Expand Down Expand Up @@ -263,8 +265,3 @@ struct RecordVersionBadge: View {
)
}
}

private struct VersionDestination: Identifiable {
let version: DevelopmentRecord.Version
var id: String { version.id }
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,39 @@ import PresentationShared

@MainActor
struct RecordDetailFeatureTests {
@Test("편집과 이력 화면 표시는 Feature 상태를 전환한다")
func 편집과_이력_화면_표시는_Feature_상태를_전환한다() async throws {
let currentVersion = try makeDevelopmentRecordVersion(id: "version-2", number: 2)
let previousVersion = try makeDevelopmentRecordVersion(id: "version-1")
let record = try makeConfirmedDevelopmentRecord(
versionId: currentVersion.id,
versionNumber: currentVersion.number
)
var state = RecordDetailFeature.State(goalTitle: "개발 목표", record: record)
state.versions = [previousVersion, currentVersion]
state.contentState = .loaded
let store = TestStore(initialState: state) {
RecordDetailFeature()
}

await store.send(.view(.tapCorrection)) {
$0.sheet = .editor
}
await store.send(.sheet(.dismiss)) {
$0.sheet = nil
}
await store.send(.view(.tapHistory)) {
$0.history = RecordHistoryDestination(recordID: record.id)
}
await store.send(.view(.selectVersion(previousVersion))) {
$0.versionDetail = RecordVersionDetailDestination(version: previousVersion)
}
await store.send(.history(.dismiss)) {
$0.history = nil
$0.versionDetail = nil
}
}

@Test("상세는 currentVersion과 일치하는 확정 버전을 표시한다")
func 상세는_currentVersion과_일치하는_확정_버전을_표시한다() async throws {
let record = try makeConfirmedDevelopmentRecord()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,3 @@ private struct DevelopmentGoalStatusBadge: View {
.background(Color.accent.opacity(0.1), in: .capsule)
}
}

enum GoalPresentation: Identifiable {
case create
case detail(String)

var id: String {
switch self {
case .create:
"create"
case .detail(let goalID):
goalID
}
}
}
25 changes: 24 additions & 1 deletion Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ struct HomeFeature {
case startObserving
case fetchData
case todoEditorCreated
case tapCreateDevelopmentGoal
case tapDevelopmentGoal(String)
case tapManageTodoCategory
case tapTodoCategoryExpansionButton
case tapTodoCategory(TodoCategory)
Expand All @@ -80,6 +82,8 @@ struct HomeFeature {
enum SheetState: Equatable {
case reorderTodo(CategoryManageFeature.State)
case contentPicker
case goalCreate
case goalDetail(String)

var categoryManageState: CategoryManageFeature.State? {
get {
Expand All @@ -91,6 +95,15 @@ struct HomeFeature {
self = .reorderTodo(newValue)
}
}

var isDevelopmentGoalPresentation: Bool {
switch self {
case .goalCreate, .goalDetail:
true
case .reorderTodo, .contentPicker:
false
}
}
}

@CasePathable
Expand Down Expand Up @@ -170,7 +183,13 @@ struct HomeFeature {
state.selectedTodoCategory = nil
case .fullScreenCover:
break
case .sheet(.dismiss), .sheet(.presented(.tapCloseButton)):
case .sheet(.dismiss):
let refreshesDevelopmentGoals = state.sheet?.isDevelopmentGoalPresentation == true
state.sheet = nil
if refreshesDevelopmentGoals {
return .send(.view(.fetchData))
}
case .sheet(.presented(.tapCloseButton)):
state.sheet = nil
case .sheet(.presented(.categoryManage(.delegate(.done(let preferences))))):
return orderTodoCategory(preferences, state: &state)
Expand Down Expand Up @@ -230,6 +249,10 @@ private extension HomeFeature {
trackTodoCreateEffect(),
.send(.view(.fetchData))
)
case .tapCreateDevelopmentGoal:
state.sheet = .goalCreate
case .tapDevelopmentGoal(let goalID):
state.sheet = .goalDetail(goalID)
case .tapManageTodoCategory:
state.sheet = .reorderTodo(CategoryManageFeature.State(preferences: state.preferences))
case .tapTodoCategoryExpansionButton:
Expand Down
Loading
Loading