From 31167bd0627a0e66d3cdbb2490ff5cc37a3f1b24 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 08:51:58 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20Development=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=ED=82=A4=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DevelopmentDependencyPreparation.swift | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Application/Presentation/Development/Sources/Dependency/DevelopmentDependencyPreparation.swift b/Application/Presentation/Development/Sources/Dependency/DevelopmentDependencyPreparation.swift index e58ffecf..ee4e6389 100644 --- a/Application/Presentation/Development/Sources/Dependency/DevelopmentDependencyPreparation.swift +++ b/Application/Presentation/Development/Sources/Dependency/DevelopmentDependencyPreparation.swift @@ -56,133 +56,133 @@ public enum DevelopmentDependencyPreparation { extension DependencyValues { var developmentCreateGoalUseCase: CreateDevelopmentGoalUseCase { - get { self[DevelopmentCreateGoalUseCaseKey.self] } - set { self[DevelopmentCreateGoalUseCaseKey.self] = newValue } + get { self[CreateGoalUseCaseKey.self] } + set { self[CreateGoalUseCaseKey.self] = newValue } } var developmentFetchGoalUseCase: FetchDevelopmentGoalUseCase { - get { self[DevelopmentFetchGoalUseCaseKey.self] } - set { self[DevelopmentFetchGoalUseCaseKey.self] = newValue } + get { self[FetchGoalUseCaseKey.self] } + set { self[FetchGoalUseCaseKey.self] = newValue } } var developmentFetchRecordsUseCase: FetchDevelopmentRecordsUseCase { - get { self[DevelopmentFetchRecordsUseCaseKey.self] } - set { self[DevelopmentFetchRecordsUseCaseKey.self] = newValue } + get { self[FetchRecordsUseCaseKey.self] } + set { self[FetchRecordsUseCaseKey.self] = newValue } } var developmentUpdateGoalStatusUseCase: UpdateDevelopmentGoalStatusUseCase { - get { self[DevelopmentUpdateGoalStatusUseCaseKey.self] } - set { self[DevelopmentUpdateGoalStatusUseCaseKey.self] = newValue } + get { self[UpdateGoalStatusUseCaseKey.self] } + set { self[UpdateGoalStatusUseCaseKey.self] = newValue } } var developmentFetchRecordHistoryUseCase: FetchDevelopmentRecordHistoryUseCase { - get { self[DevelopmentFetchRecordHistoryUseCaseKey.self] } - set { self[DevelopmentFetchRecordHistoryUseCaseKey.self] = newValue } + get { self[FetchRecordHistoryUseCaseKey.self] } + set { self[FetchRecordHistoryUseCaseKey.self] = newValue } } var developmentFetchRecordVersionUseCase: FetchDevelopmentRecordVersionUseCase { - get { self[DevelopmentFetchRecordVersionUseCaseKey.self] } - set { self[DevelopmentFetchRecordVersionUseCaseKey.self] = newValue } + get { self[FetchRecordVersionUseCaseKey.self] } + set { self[FetchRecordVersionUseCaseKey.self] = newValue } } var developmentCreateRecordUseCase: CreateDevelopmentRecordUseCase { - get { self[DevelopmentCreateRecordUseCaseKey.self] } - set { self[DevelopmentCreateRecordUseCaseKey.self] = newValue } + get { self[CreateRecordUseCaseKey.self] } + set { self[CreateRecordUseCaseKey.self] = newValue } } var developmentSaveRecordDraftUseCase: SaveDevelopmentRecordDraftUseCase { - get { self[DevelopmentSaveRecordDraftUseCaseKey.self] } - set { self[DevelopmentSaveRecordDraftUseCaseKey.self] = newValue } + get { self[SaveRecordDraftUseCaseKey.self] } + set { self[SaveRecordDraftUseCaseKey.self] = newValue } } var developmentConfirmRecordUseCase: ConfirmDevelopmentRecordUseCase { - get { self[DevelopmentConfirmRecordUseCaseKey.self] } - set { self[DevelopmentConfirmRecordUseCaseKey.self] = newValue } + get { self[ConfirmRecordUseCaseKey.self] } + set { self[ConfirmRecordUseCaseKey.self] = newValue } } var developmentRestoreRecordUseCase: RestoreDevelopmentRecordUseCase { - get { self[DevelopmentRestoreRecordUseCaseKey.self] } - set { self[DevelopmentRestoreRecordUseCaseKey.self] = newValue } + get { self[RestoreRecordUseCaseKey.self] } + set { self[RestoreRecordUseCaseKey.self] = newValue } } var developmentFetchTodosUseCase: FetchTodosUseCase { - get { self[DevelopmentFetchTodosUseCaseKey.self] } - set { self[DevelopmentFetchTodosUseCaseKey.self] = newValue } + get { self[FetchTodosUseCaseKey.self] } + set { self[FetchTodosUseCaseKey.self] = newValue } } var developmentUpdateTodoGoalUseCase: UpdateTodoGoalUseCase { - get { self[DevelopmentUpdateTodoGoalUseCaseKey.self] } - set { self[DevelopmentUpdateTodoGoalUseCaseKey.self] = newValue } + get { self[UpdateTodoGoalUseCaseKey.self] } + set { self[UpdateTodoGoalUseCaseKey.self] = newValue } } } -private enum DevelopmentCreateGoalUseCaseKey: DependencyKey { +private enum CreateGoalUseCaseKey: DependencyKey { static var liveValue: CreateDevelopmentGoalUseCase { preconditionFailure("CreateDevelopmentGoalUseCase must be provided.") } } -private enum DevelopmentFetchGoalUseCaseKey: DependencyKey { +private enum FetchGoalUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentGoalUseCase { preconditionFailure("FetchDevelopmentGoalUseCase must be provided.") } } -private enum DevelopmentFetchRecordsUseCaseKey: DependencyKey { +private enum FetchRecordsUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentRecordsUseCase { preconditionFailure("FetchDevelopmentRecordsUseCase must be provided.") } } -private enum DevelopmentUpdateGoalStatusUseCaseKey: DependencyKey { +private enum UpdateGoalStatusUseCaseKey: DependencyKey { static var liveValue: UpdateDevelopmentGoalStatusUseCase { preconditionFailure("UpdateDevelopmentGoalStatusUseCase must be provided.") } } -private enum DevelopmentFetchRecordHistoryUseCaseKey: DependencyKey { +private enum FetchRecordHistoryUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentRecordHistoryUseCase { preconditionFailure("FetchDevelopmentRecordHistoryUseCase must be provided.") } } -private enum DevelopmentFetchRecordVersionUseCaseKey: DependencyKey { +private enum FetchRecordVersionUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentRecordVersionUseCase { preconditionFailure("FetchDevelopmentRecordVersionUseCase must be provided.") } } -private enum DevelopmentCreateRecordUseCaseKey: DependencyKey { +private enum CreateRecordUseCaseKey: DependencyKey { static var liveValue: CreateDevelopmentRecordUseCase { preconditionFailure("CreateDevelopmentRecordUseCase must be provided.") } } -private enum DevelopmentSaveRecordDraftUseCaseKey: DependencyKey { +private enum SaveRecordDraftUseCaseKey: DependencyKey { static var liveValue: SaveDevelopmentRecordDraftUseCase { preconditionFailure("SaveDevelopmentRecordDraftUseCase must be provided.") } } -private enum DevelopmentConfirmRecordUseCaseKey: DependencyKey { +private enum ConfirmRecordUseCaseKey: DependencyKey { static var liveValue: ConfirmDevelopmentRecordUseCase { preconditionFailure("ConfirmDevelopmentRecordUseCase must be provided.") } } -private enum DevelopmentRestoreRecordUseCaseKey: DependencyKey { +private enum RestoreRecordUseCaseKey: DependencyKey { static var liveValue: RestoreDevelopmentRecordUseCase { preconditionFailure("RestoreDevelopmentRecordUseCase must be provided.") } } -private enum DevelopmentFetchTodosUseCaseKey: DependencyKey { +private enum FetchTodosUseCaseKey: DependencyKey { static var liveValue: FetchTodosUseCase { preconditionFailure("FetchTodosUseCase must be provided.") } } -private enum DevelopmentUpdateTodoGoalUseCaseKey: DependencyKey { +private enum UpdateTodoGoalUseCaseKey: DependencyKey { static var liveValue: UpdateTodoGoalUseCase { preconditionFailure("UpdateTodoGoalUseCase must be provided.") } From f535fd6db4e996dcc838a1235e9799bf9d8aa3a6 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 08:56:09 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20ProfileTab=20=EB=82=B4=EB=B6=80?= =?UTF-8?q?=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tmapBuilder.swift => HeatmapBuilder.swift} | 26 ++++++------ .../Profile/ProfileFeature+Dependencies.swift | 42 +++++++++---------- .../Profile/ProfileFeature+State.swift | 12 +++--- .../Sources/Profile/ProfileFeature.swift | 18 ++++---- .../Sources/Profile/ProfileView.swift | 4 +- .../Sources/Structure/AvatarImageData.swift | 17 ++++++++ .../Structure/ProfileAvatarImageData.swift | 17 -------- .../Tests/Profile/ProfileFeatureTests.swift | 18 ++++---- 8 files changed, 77 insertions(+), 77 deletions(-) rename Application/Presentation/ProfileTab/Sources/Profile/{ProfileHeatmapBuilder.swift => HeatmapBuilder.swift} (92%) create mode 100644 Application/Presentation/ProfileTab/Sources/Structure/AvatarImageData.swift delete mode 100644 Application/Presentation/ProfileTab/Sources/Structure/ProfileAvatarImageData.swift diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileHeatmapBuilder.swift b/Application/Presentation/ProfileTab/Sources/Profile/HeatmapBuilder.swift similarity index 92% rename from Application/Presentation/ProfileTab/Sources/Profile/ProfileHeatmapBuilder.swift rename to Application/Presentation/ProfileTab/Sources/Profile/HeatmapBuilder.swift index 46dd4271..60f69dc4 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileHeatmapBuilder.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/HeatmapBuilder.swift @@ -1,5 +1,5 @@ // -// ProfileHeatmapBuilder.swift +// HeatmapBuilder.swift // ProfileTab // // Created by opfic on 6/15/26. @@ -9,7 +9,7 @@ import Core import Domain import Foundation -private struct ProfileHeatmapActivityCounts { +private struct HeatmapActivityCounts { var createdCount = 0 var completedCount = 0 var deletedCount = 0 @@ -26,12 +26,12 @@ private struct ProfileHeatmapActivityCounts { } } -private struct ProfileHeatmapActivityEntry { +private struct HeatmapActivityEntry { var todo: Todo var activityKinds: Set } -enum ProfileHeatmapBuilder { +enum HeatmapBuilder { static func quarterStart(for date: Date) -> Date? { let month = Calendar.current.component(.month, from: date) let startMonth = ((month - 1) / 3) * 3 + 1 @@ -139,8 +139,8 @@ enum ProfileHeatmapBuilder { deletedTodos: [Todo], quarterStart: Date ) -> (quarter: HeatmapQuarter, dayActivitiesByDate: [Date: [HeatmapActivityItem]]) { - var dailyCountsByDate: [Date: ProfileHeatmapActivityCounts] = [:] - var activityEntriesByDate: [Date: [String: ProfileHeatmapActivityEntry]] = [:] + var dailyCountsByDate: [Date: HeatmapActivityCounts] = [:] + var activityEntriesByDate: [Date: [String: HeatmapActivityEntry]] = [:] for todo in createdTodos { appendHeatmapActivity( @@ -191,7 +191,7 @@ enum ProfileHeatmapBuilder { } private static func makeActivityMonths( - dailyCountsByDate: [Date: ProfileHeatmapActivityCounts], + dailyCountsByDate: [Date: HeatmapActivityCounts], quarterStart: Date ) -> [HeatmapMonth] { let monthStarts = (0..<3).compactMap { @@ -208,7 +208,7 @@ enum ProfileHeatmapBuilder { private static func makeActivityMonth( monthStart: Date, - dailyCountsByDate: [Date: ProfileHeatmapActivityCounts] + dailyCountsByDate: [Date: HeatmapActivityCounts] ) -> HeatmapMonth { guard let monthInterval = Calendar.current.dateInterval(of: .month, for: monthStart), let monthLastDay = Calendar.current.date(byAdding: .day, value: -1, to: monthInterval.end), @@ -222,7 +222,7 @@ enum ProfileHeatmapBuilder { while cursor < lastWeekInterval.end { let normalizedDate = Calendar.current.startOfDay(for: cursor) let isInMonth = Calendar.current.isDate(normalizedDate, equalTo: monthStart, toGranularity: .month) - let dailyCounts = dailyCountsByDate[normalizedDate] ?? ProfileHeatmapActivityCounts() + let dailyCounts = dailyCountsByDate[normalizedDate] ?? HeatmapActivityCounts() let createdCount = isInMonth ? dailyCounts.createdCount : 0 let completedCount = isInMonth ? dailyCounts.completedCount : 0 let deletedCount = isInMonth ? dailyCounts.deletedCount : 0 @@ -254,16 +254,16 @@ enum ProfileHeatmapBuilder { todo: Todo, kind: ActivityKind, occurredAt: Date, - dailyCountsByDate: inout [Date: ProfileHeatmapActivityCounts], - activityEntriesByDate: inout [Date: [String: ProfileHeatmapActivityEntry]] + dailyCountsByDate: inout [Date: HeatmapActivityCounts], + activityEntriesByDate: inout [Date: [String: HeatmapActivityEntry]] ) { let dayStart = Calendar.current.startOfDay(for: occurredAt) - var heatmapActivityCounts = dailyCountsByDate[dayStart] ?? ProfileHeatmapActivityCounts() + var heatmapActivityCounts = dailyCountsByDate[dayStart] ?? HeatmapActivityCounts() heatmapActivityCounts.increment(kind) dailyCountsByDate[dayStart] = heatmapActivityCounts var activityEntries = activityEntriesByDate[dayStart] ?? [:] - var heatmapActivityEntry = activityEntries[todo.id] ?? ProfileHeatmapActivityEntry( + var heatmapActivityEntry = activityEntries[todo.id] ?? HeatmapActivityEntry( todo: todo, activityKinds: [] ) diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+Dependencies.swift b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+Dependencies.swift index e7619a69..50be8a1c 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+Dependencies.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+Dependencies.swift @@ -10,42 +10,42 @@ import Domain extension DependencyValues { var profileFetchUserDataUseCase: FetchUserDataUseCase { - get { self[ProfileFetchUserDataKey.self] } - set { self[ProfileFetchUserDataKey.self] = newValue } + get { self[FetchUserDataKey.self] } + set { self[FetchUserDataKey.self] = newValue } } var profileFetchImageDataUseCase: FetchProfileImageDataUseCase { - get { self[ProfileFetchImageDataKey.self] } - set { self[ProfileFetchImageDataKey.self] = newValue } + get { self[FetchImageDataKey.self] } + set { self[FetchImageDataKey.self] = newValue } } var profileFetchTodosUseCase: FetchTodosUseCase { - get { self[ProfileFetchTodosKey.self] } - set { self[ProfileFetchTodosKey.self] = newValue } + get { self[FetchTodosKey.self] } + set { self[FetchTodosKey.self] = newValue } } var profileTodoMutationEventBus: TodoMutationEventBus { - get { self[ProfileTodoMutationEventBusKey.self] } - set { self[ProfileTodoMutationEventBusKey.self] = newValue } + get { self[TodoMutationEventBusKey.self] } + set { self[TodoMutationEventBusKey.self] = newValue } } var profileUpsertStatusMessageUseCase: UpsertStatusMessageUseCase { - get { self[ProfileUpsertStatusMessageKey.self] } - set { self[ProfileUpsertStatusMessageKey.self] = newValue } + get { self[UpsertStatusMessageKey.self] } + set { self[UpsertStatusMessageKey.self] = newValue } } var profileFetchHeatmapActivityTypesUseCase: FetchHeatmapActivityTypesUseCase { - get { self[ProfileFetchHeatmapTypesKey.self] } - set { self[ProfileFetchHeatmapTypesKey.self] = newValue } + get { self[FetchHeatmapTypesKey.self] } + set { self[FetchHeatmapTypesKey.self] = newValue } } var profileUpdateHeatmapActivityTypesUseCase: UpdateHeatmapActivityTypesUseCase { - get { self[ProfileUpdateHeatmapTypesKey.self] } - set { self[ProfileUpdateHeatmapTypesKey.self] = newValue } + get { self[UpdateHeatmapTypesKey.self] } + set { self[UpdateHeatmapTypesKey.self] = newValue } } } -private enum ProfileFetchUserDataKey: DependencyKey { +private enum FetchUserDataKey: DependencyKey { static var liveValue: FetchUserDataUseCase { preconditionFailure("FetchUserDataUseCase must be provided.") } @@ -55,7 +55,7 @@ private enum ProfileFetchUserDataKey: DependencyKey { } } -private enum ProfileFetchImageDataKey: DependencyKey { +private enum FetchImageDataKey: DependencyKey { static var liveValue: FetchProfileImageDataUseCase { preconditionFailure("FetchProfileImageDataUseCase must be provided.") } @@ -65,7 +65,7 @@ private enum ProfileFetchImageDataKey: DependencyKey { } } -private enum ProfileFetchTodosKey: DependencyKey { +private enum FetchTodosKey: DependencyKey { static var liveValue: FetchTodosUseCase { preconditionFailure("FetchTodosUseCase must be provided.") } @@ -75,13 +75,13 @@ private enum ProfileFetchTodosKey: DependencyKey { } } -private enum ProfileTodoMutationEventBusKey: DependencyKey { +private enum TodoMutationEventBusKey: DependencyKey { static var liveValue: TodoMutationEventBus { preconditionFailure("TodoMutationEventBus must be provided.") } } -private enum ProfileUpsertStatusMessageKey: DependencyKey { +private enum UpsertStatusMessageKey: DependencyKey { static var liveValue: UpsertStatusMessageUseCase { preconditionFailure("UpsertStatusMessageUseCase must be provided.") } @@ -91,7 +91,7 @@ private enum ProfileUpsertStatusMessageKey: DependencyKey { } } -private enum ProfileFetchHeatmapTypesKey: DependencyKey { +private enum FetchHeatmapTypesKey: DependencyKey { static var liveValue: FetchHeatmapActivityTypesUseCase { preconditionFailure("FetchHeatmapActivityTypesUseCase must be provided.") } @@ -101,7 +101,7 @@ private enum ProfileFetchHeatmapTypesKey: DependencyKey { } } -private enum ProfileUpdateHeatmapTypesKey: DependencyKey { +private enum UpdateHeatmapTypesKey: DependencyKey { static var liveValue: UpdateHeatmapActivityTypesUseCase { preconditionFailure("UpdateHeatmapActivityTypesUseCase must be provided.") } diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+State.swift b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+State.swift index a9c9dd9b..03804c2f 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+State.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature+State.swift @@ -68,16 +68,16 @@ extension ProfileFeature.State { } var canMoveToPreviousQuarter: Bool { - ProfileHeatmapBuilder.canMoveToQuarter(offsetMonths: -3, state: self) + HeatmapBuilder.canMoveToQuarter(offsetMonths: -3, state: self) } var canMoveToNextQuarter: Bool { - ProfileHeatmapBuilder.canMoveToQuarter(offsetMonths: 3, state: self) + HeatmapBuilder.canMoveToQuarter(offsetMonths: 3, state: self) } var isViewingCurrentQuarter: Bool { guard let selectedQuarterStart, - let currentQuarterStart = ProfileHeatmapBuilder.quarterStart(for: Date()) else { + let currentQuarterStart = HeatmapBuilder.quarterStart(for: Date()) else { return false } return selectedQuarterStart == currentQuarterStart @@ -85,7 +85,7 @@ extension ProfileFeature.State { var availableQuarterYears: [Int] { guard let earliestQuarterStart, - let currentQuarterStart = ProfileHeatmapBuilder.quarterStart(for: Date()) else { + let currentQuarterStart = HeatmapBuilder.quarterStart(for: Date()) else { return [selectedQuarterPickerYear] } let earliestYear = Calendar.current.component(.year, from: earliestQuarterStart) @@ -94,12 +94,12 @@ extension ProfileFeature.State { } func quarterStartForPicker(quarter: Int) -> Date? { - ProfileHeatmapBuilder.quarterStart(year: selectedQuarterPickerYear, quarter: quarter) + HeatmapBuilder.quarterStart(year: selectedQuarterPickerYear, quarter: quarter) } func isQuarterSelectableForPicker(_ quarter: Int) -> Bool { guard let quarterStart = quarterStartForPicker(quarter: quarter) else { return false } - return ProfileHeatmapBuilder.canSelectQuarter(quarterStart, state: self) + return HeatmapBuilder.canSelectQuarter(quarterStart, state: self) } func isQuarterSelectedForPicker(_ quarter: Int) -> Bool { diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature.swift b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature.swift index 8ce94133..3b1a437b 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/ProfileFeature.swift @@ -36,7 +36,7 @@ struct ProfileFeature { var isNetworkConnected = true var statusMessage = "" var avatarURL: URL? - var avatarImageData: ProfileAvatarImageData? + var avatarImageData: AvatarImageData? var recentTodos = [RecentTodoItem]() var earliestQuarterStart: Date? var selectedQuarterStart: Date? @@ -119,11 +119,11 @@ struct ProfileFeature { ) case .fetchData, .refresh: if state.selectedQuarterStart == nil, - let quarterStart = ProfileHeatmapBuilder.quarterStart(for: Date()) { + let quarterStart = HeatmapBuilder.quarterStart(for: Date()) { state.selectedQuarterStart = quarterStart } let rawValues = fetchHeatmapActivityTypesUseCase.execute() - let settings = ProfileHeatmapBuilder.normalizeActivityKinds(rawValues) + let settings = HeatmapBuilder.normalizeActivityKinds(rawValues) if !settings.isEmpty { state.selectedActivityKinds = settings } @@ -158,11 +158,11 @@ struct ProfileFeature { } state.showQuarterPicker = true case .selectQuarter(let quarterStart): - guard ProfileHeatmapBuilder.canSelectQuarter(quarterStart, state: state) else { break } + guard HeatmapBuilder.canSelectQuarter(quarterStart, state: state) else { break } state.showQuarterPicker = false return updateSelectedQuarter(to: quarterStart, state: &state) case .moveToCurrentQuarter: - guard let currentQuarterStart = ProfileHeatmapBuilder.quarterStart(for: Date()), + guard let currentQuarterStart = HeatmapBuilder.quarterStart(for: Date()), state.selectedQuarterStart != currentQuarterStart else { break } return updateSelectedQuarter(to: currentQuarterStart, state: &state) case .moveQuarter(let delta): @@ -173,7 +173,7 @@ struct ProfileFeature { value: monthDelta, to: selectedQuarterStart ) else { break } - guard ProfileHeatmapBuilder.canSelectQuarter(nextQuarterStart, state: state) else { break } + guard HeatmapBuilder.canSelectQuarter(nextQuarterStart, state: state) else { break } return updateSelectedQuarter(to: nextQuarterStart, state: &state) case .selectDay(let day): if let day, state.selectedDay?.date == day.date { @@ -193,7 +193,7 @@ struct ProfileFeature { state.avatarImageData = nil } if state.earliestQuarterStart == nil { - state.earliestQuarterStart = ProfileHeatmapBuilder.quarterStart(for: profile.createdAt) + state.earliestQuarterStart = HeatmapBuilder.quarterStart(for: profile.createdAt) ?? Calendar.current.startOfDay(for: profile.createdAt) } if let avatarURL = profile.avatarURL { @@ -202,7 +202,7 @@ struct ProfileFeature { case .store(.setAvatarImageData(let url, let data)): guard state.avatarURL == url else { break } let id = (state.avatarImageData?.id ?? 0) + 1 - state.avatarImageData = ProfileAvatarImageData(id: id, data: data) + state.avatarImageData = AvatarImageData(id: id, data: data) case .store(.setActivityQuarter(let quarterStart, let quarter, let dayActivitiesByDate)): guard state.selectedQuarterStart == quarterStart else { break } state.activityQuarter = quarter @@ -257,7 +257,7 @@ private extension ProfileFeature { await send(.loading(.begin(target: .default, mode: .delayed))) } do { - let data = try await ProfileHeatmapBuilder.fetchQuarterActivityData( + let data = try await HeatmapBuilder.fetchQuarterActivityData( from: quarterStart, fetchTodosUseCase: fetchTodosUseCase ) diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift b/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift index b827e2c6..2d19cd10 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift @@ -39,7 +39,7 @@ public struct ProfileView: View { ScrollView { LazyVStack(alignment: .leading, spacing: 16, pinnedViews: [.sectionHeaders]) { Section { - ProfileCard(store: store, isSelected: isSelected) + Card(store: store, isSelected: isSelected) RecentActivityCard(store: store) { todoId in path.append(.recentTodo(todoId)) } @@ -350,7 +350,7 @@ public struct ProfileView: View { } } -private struct ProfileCard: View { +private struct Card: View { @Bindable var store: StoreOf @FocusState private var focused: Bool let isSelected: Bool diff --git a/Application/Presentation/ProfileTab/Sources/Structure/AvatarImageData.swift b/Application/Presentation/ProfileTab/Sources/Structure/AvatarImageData.swift new file mode 100644 index 00000000..d3fa3f41 --- /dev/null +++ b/Application/Presentation/ProfileTab/Sources/Structure/AvatarImageData.swift @@ -0,0 +1,17 @@ +// +// AvatarImageData.swift +// ProfileTab +// +// Created by opfic on 6/17/26. +// + +import Foundation + +struct AvatarImageData: Equatable { + let id: Int + let data: Data + + static func == (lhs: AvatarImageData, rhs: AvatarImageData) -> Bool { + lhs.id == rhs.id + } +} diff --git a/Application/Presentation/ProfileTab/Sources/Structure/ProfileAvatarImageData.swift b/Application/Presentation/ProfileTab/Sources/Structure/ProfileAvatarImageData.swift deleted file mode 100644 index 6491e18f..00000000 --- a/Application/Presentation/ProfileTab/Sources/Structure/ProfileAvatarImageData.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// ProfileAvatarImageData.swift -// ProfileTab -// -// Created by opfic on 6/17/26. -// - -import Foundation - -struct ProfileAvatarImageData: Equatable { - let id: Int - let data: Data - - static func == (lhs: ProfileAvatarImageData, rhs: ProfileAvatarImageData) -> Bool { - lhs.id == rhs.id - } -} diff --git a/Application/Presentation/ProfileTab/Tests/Profile/ProfileFeatureTests.swift b/Application/Presentation/ProfileTab/Tests/Profile/ProfileFeatureTests.swift index b2c0e521..8969dcbf 100644 --- a/Application/Presentation/ProfileTab/Tests/Profile/ProfileFeatureTests.swift +++ b/Application/Presentation/ProfileTab/Tests/Profile/ProfileFeatureTests.swift @@ -41,7 +41,7 @@ struct ProfileFeatureTests { preferencesSpy.preferences = [ TodoCategoryPreference(category: updatedCategory, isVisible: true) ] - let adapter = ProfileStoreTestAdapter( + let adapter = StoreTestAdapter( fetchTodosUseCase: fetchSpy, fetchPreferencesUseCase: preferencesSpy ) @@ -65,7 +65,7 @@ struct ProfileFeatureTests { ) let preferencesSpy = FetchTodoCategoryPreferencesUseCaseSpy() preferencesSpy.error = TestError() - let adapter = ProfileStoreTestAdapter( + let adapter = StoreTestAdapter( fetchTodosUseCase: fetchSpy, fetchPreferencesUseCase: preferencesSpy ) @@ -80,7 +80,7 @@ struct ProfileFeatureTests { func ProfileFeature는_Todo_변경_시_최근_목록만_다시_조회한다() async { let fetchSpy = FetchTodosUseCaseSpy() let eventBus = TodoMutationEventBusSpy() - let adapter = ProfileStoreTestAdapter( + let adapter = StoreTestAdapter( fetchTodosUseCase: fetchSpy, todoMutationEventBus: eventBus ) @@ -94,7 +94,7 @@ struct ProfileFeatureTests { @Test("ProfileFeature는 최근 Todo 로딩을 전체 화면 로딩에서 제외한다") func ProfileFeature는_최근_Todo_로딩을_전체_화면_로딩에서_제외한다() async { - let adapter = ProfileStoreTestAdapter() + let adapter = StoreTestAdapter() await adapter.beginRecentTodosLoading() @@ -106,7 +106,7 @@ struct ProfileFeatureTests { func ProfileFeature는_같은_아바타_URL을_다시_받아도_프로필_이미지_데이터를_다시_요청한다() async { let imageData = Data([1, 2, 3]) let spy = FetchProfileImageDataUseCaseSpy(data: imageData) - let adapter = ProfileStoreTestAdapter(fetchProfileImageDataUseCase: spy) + let adapter = StoreTestAdapter(fetchProfileImageDataUseCase: spy) let avatarURL = URL(string: "https://example.com/avatar.png")! let profile = UserProfile( name: "opfic", @@ -126,7 +126,7 @@ struct ProfileFeatureTests { @Test("ProfileFeature는 연결 상태일 때 상태 메시지 저장을 요청한다") func ProfileFeature는_연결_상태일_때_상태_메시지_저장을_요청한다() async { let spy = UpsertStatusMessageUseCaseSpy() - let adapter = ProfileStoreTestAdapter(upsertStatusMessageUseCase: spy) + let adapter = StoreTestAdapter(upsertStatusMessageUseCase: spy) await adapter.updateStatusMessage("working") await adapter.willUpdateStatusMessage() @@ -139,7 +139,7 @@ struct ProfileFeatureTests { let spy = UpdateHeatmapActivityTypesUseCaseSpy() let fetchSpy = FetchHeatmapActivityTypesUseCaseSpy() fetchSpy.activityTypes = ["created"] - let adapter = ProfileStoreTestAdapter( + let adapter = StoreTestAdapter( fetchHeatmapActivityTypesUseCase: fetchSpy, updateHeatmapActivityTypesUseCase: spy ) @@ -237,11 +237,11 @@ private final class UpdateHeatmapActivityTypesUseCaseSpy: UpdateHeatmapActivityT } @MainActor -private struct ProfileStoreTestAdapter { +private struct StoreTestAdapter { private let store: TestStoreOf private let todoMutationEventBus: TodoMutationEventBus - var avatarImageData: ProfileAvatarImageData? { store.state.avatarImageData } + var avatarImageData: AvatarImageData? { store.state.avatarImageData } var isAlertPresented: Bool { store.state.alert != nil } var isLoading: Bool { store.state.isLoading } var isRecentTodosLoading: Bool { store.state.isRecentTodosLoading } From 2061bb64daefdab217b09c84e5305c2cdd45e553 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 08:56:53 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20TodayTab=20=EB=82=B4=EB=B6=80?= =?UTF-8?q?=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/TodayTab/Sources/TodayFeature.swift | 6 +++--- .../Presentation/TodayTab/Tests/TodayFeatureTestSpies.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Application/Presentation/TodayTab/Sources/TodayFeature.swift b/Application/Presentation/TodayTab/Sources/TodayFeature.swift index de6c70f9..69df05fd 100644 --- a/Application/Presentation/TodayTab/Sources/TodayFeature.swift +++ b/Application/Presentation/TodayTab/Sources/TodayFeature.swift @@ -198,12 +198,12 @@ struct TodayFeature { extension DependencyValues { var todayFetchTodosUseCase: FetchTodosUseCase { - get { self[TodayFetchTodosUseCaseKey.self] } - set { self[TodayFetchTodosUseCaseKey.self] = newValue } + get { self[FetchTodosUseCaseKey.self] } + set { self[FetchTodosUseCaseKey.self] = newValue } } } -private enum TodayFetchTodosUseCaseKey: DependencyKey { +private enum FetchTodosUseCaseKey: DependencyKey { static var liveValue: FetchTodosUseCase { preconditionFailure("FetchTodosUseCase must be provided.") } diff --git a/Application/Presentation/TodayTab/Tests/TodayFeatureTestSpies.swift b/Application/Presentation/TodayTab/Tests/TodayFeatureTestSpies.swift index d5099676..6542e65e 100644 --- a/Application/Presentation/TodayTab/Tests/TodayFeatureTestSpies.swift +++ b/Application/Presentation/TodayTab/Tests/TodayFeatureTestSpies.swift @@ -14,7 +14,7 @@ final class TodayFetchTodosUseCaseSpy: FetchTodosUseCase { var pagesByFilter: [TodoQuery.DueDateFilter: TodoPage] var completedTodayPage: TodoPage var error: Error? - private let recorder = TodayFetchTodosUseCaseCallRecorder() + private let recorder = FetchTodosUseCaseCallRecorder() init( pagesByFilter: [TodoQuery.DueDateFilter: TodoPage] = [ @@ -50,7 +50,7 @@ final class TodayFetchTodosUseCaseSpy: FetchTodosUseCase { } } -private actor TodayFetchTodosUseCaseCallRecorder { +private actor FetchTodosUseCaseCallRecorder { var recordedQueries = [TodoQuery]() var recordedCursors = [TodoCursor?]() From 6574e50fbb44c63cbffcef7b52a632e839f495fb Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 08:57:41 +0900 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20Entry=20=EB=82=B4=EB=B6=80=20?= =?UTF-8?q?=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entry/Sources/Root/RootFeature.swift | 16 ++++++++-------- .../Entry/Tests/Root/RootFeatureTests.swift | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Application/Presentation/Entry/Sources/Root/RootFeature.swift b/Application/Presentation/Entry/Sources/Root/RootFeature.swift index c240444d..13edf0d5 100644 --- a/Application/Presentation/Entry/Sources/Root/RootFeature.swift +++ b/Application/Presentation/Entry/Sources/Root/RootFeature.swift @@ -141,12 +141,12 @@ struct RootFeature { } .ifLet(\.$alert, action: \.alert) .ifLet(\.$sheet, action: \.sheet) { - RootSheetFeature() + SheetFeature() } } } -private struct RootSheetFeature: Reducer { +private struct SheetFeature: Reducer { typealias State = RootFeature.SheetState typealias Action = RootFeature.Action.Sheet @@ -172,13 +172,13 @@ extension DependencyValues { } var rootNetworkConnectivityUseCase: ObserveNetworkConnectivityUseCase { - get { self[RootNetworkConnectivityUseCaseKey.self] } - set { self[RootNetworkConnectivityUseCaseKey.self] = newValue } + get { self[NetworkConnectivityUseCaseKey.self] } + set { self[NetworkConnectivityUseCaseKey.self] = newValue } } var rootSystemThemeUseCase: ObserveSystemThemeUseCase { - get { self[RootSystemThemeUseCaseKey.self] } - set { self[RootSystemThemeUseCaseKey.self] = newValue } + get { self[SystemThemeUseCaseKey.self] } + set { self[SystemThemeUseCaseKey.self] = newValue } } } @@ -217,7 +217,7 @@ private enum ObserveAuthSessionUseCaseKey: DependencyKey { } } -private enum RootNetworkConnectivityUseCaseKey: DependencyKey { +private enum NetworkConnectivityUseCaseKey: DependencyKey { static var liveValue: ObserveNetworkConnectivityUseCase { preconditionFailure("ObserveNetworkConnectivityUseCase must be provided.") } @@ -227,7 +227,7 @@ private enum RootNetworkConnectivityUseCaseKey: DependencyKey { } } -private enum RootSystemThemeUseCaseKey: DependencyKey { +private enum SystemThemeUseCaseKey: DependencyKey { static var liveValue: ObserveSystemThemeUseCase { preconditionFailure("ObserveSystemThemeUseCase must be provided.") } diff --git a/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift b/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift index 49a39fe6..d9b34f7e 100644 --- a/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift +++ b/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift @@ -123,7 +123,7 @@ struct RootFeatureTests { @Test("업데이트 확인에 실패하면 업데이트 알림을 표시하지 않는다") func 업데이트_확인에_실패하면_업데이트_알림을_표시하지_않는다() async { let checkSpy = RootCheckAppUpdateUseCaseSpy( - result: .failure(RootCheckAppUpdateUseCaseTestError.fetchFailed) + result: .failure(CheckAppUpdateUseCaseTestError.fetchFailed) ) let adapter = RootStoreTestAdapter(checkAppUpdateUseCase: checkSpy) @@ -188,6 +188,6 @@ struct RootFeatureTests { } } -private enum RootCheckAppUpdateUseCaseTestError: Error { +private enum CheckAppUpdateUseCaseTestError: Error { case fetchFailed } From 6e0d418f06380966a50853d7ff54f869b8ca4b2b Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 08:59:51 +0900 Subject: [PATCH 5/8] =?UTF-8?q?refactor:=20PresentationShared=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=20=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90?= =?UTF-8?q?=EC=96=B4=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ewModifier.swift => PreviewModifier.swift} | 20 ++++++++--------- ...ailPreviewView.swift => PreviewView.swift} | 4 ++-- .../Todo/Detail/TodoDetailFeature.swift | 8 +++---- .../Sources/Todo/List/TodoListFeature.swift | 22 +++++++++---------- 4 files changed, 27 insertions(+), 27 deletions(-) rename Application/Presentation/PresentationShared/Sources/Todo/Detail/{TodoDetailPreviewModifier.swift => PreviewModifier.swift} (86%) rename Application/Presentation/PresentationShared/Sources/Todo/Detail/{TodoDetailPreviewView.swift => PreviewView.swift} (94%) diff --git a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewModifier.swift b/Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewModifier.swift similarity index 86% rename from Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewModifier.swift rename to Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewModifier.swift index 150185df..1c16e9ed 100644 --- a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewModifier.swift +++ b/Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewModifier.swift @@ -1,5 +1,5 @@ // -// TodoDetailPreviewModifier.swift +// PreviewModifier.swift // PresentationShared // // Created by opfic on 8/11/26. @@ -11,16 +11,16 @@ import Domain public extension View { func todoDetailPreview(todoId: String) -> some View { - modifier(TodoDetailPreviewModifier(todoId: todoId)) + modifier(PreviewModifier(todoId: todoId)) } } -private struct TodoDetailPreviewModifier: ViewModifier { +private struct PreviewModifier: ViewModifier { let todoId: String func body(content: Content) -> some View { content.overlay { - TodoDetailPreviewInteractionView( + PreviewInteractionView( todoId: todoId, makePreview: makePreviewViewController ) @@ -36,16 +36,16 @@ private struct TodoDetailPreviewModifier: ViewModifier { ) { TodoDetailFeature() } - return UIHostingController(rootView: TodoDetailPreviewView(store: store)) + return UIHostingController(rootView: PreviewView(store: store)) } } -private struct TodoDetailPreviewInteractionView: UIViewRepresentable { +private struct PreviewInteractionView: UIViewRepresentable { let todoId: String let makePreview: () -> UIViewController - func makeCoordinator() -> TodoDetailPreviewInteractionCoordinator { - TodoDetailPreviewInteractionCoordinator() + func makeCoordinator() -> PreviewInteractionCoordinator { + PreviewInteractionCoordinator() } func makeUIView(context: Context) -> UIView { @@ -62,7 +62,7 @@ private struct TodoDetailPreviewInteractionView: UIViewRepresentable { } } -private final class TodoDetailPreviewInteractionCoordinator: NSObject { +private final class PreviewInteractionCoordinator: NSObject { private weak var view: UIView? private var contextMenuInteraction: UIContextMenuInteraction? private var todoId = "" @@ -90,7 +90,7 @@ private final class TodoDetailPreviewInteractionCoordinator: NSObject { } } -extension TodoDetailPreviewInteractionCoordinator: UIContextMenuInteractionDelegate { +extension PreviewInteractionCoordinator: UIContextMenuInteractionDelegate { func contextMenuInteraction( _ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint diff --git a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewView.swift b/Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewView.swift similarity index 94% rename from Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewView.swift rename to Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewView.swift index b94151b6..4d3e50ad 100644 --- a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailPreviewView.swift +++ b/Application/Presentation/PresentationShared/Sources/Todo/Detail/PreviewView.swift @@ -1,5 +1,5 @@ // -// TodoDetailPreviewView.swift +// PreviewView.swift // PresentationShared // // Created by opfic on 8/11/26. @@ -8,7 +8,7 @@ import SwiftUI import ComposableArchitecture -struct TodoDetailPreviewView: View { +struct PreviewView: View { @State var store: StoreOf var body: some View { diff --git a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailFeature.swift b/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailFeature.swift index 78a824f9..bfd1f605 100644 --- a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailFeature.swift +++ b/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailFeature.swift @@ -157,15 +157,15 @@ public struct TodoDetailFeature { } .ifLet(\.$alert, action: \.alert) .ifLet(\.$sheet, action: \.sheet) { - TodoDetailSheetFeature() + SheetFeature() } .ifLet(\.$fullScreenCover, action: \.fullScreenCover) { - TodoDetailFullScreenCoverFeature() + FullScreenCoverFeature() } } } -private struct TodoDetailFullScreenCoverFeature: Reducer { +private struct FullScreenCoverFeature: Reducer { typealias State = TodoDetailFeature.FullScreenCoverState typealias Action = TodoDetailFeature.Action.FullScreenCover @@ -177,7 +177,7 @@ private struct TodoDetailFullScreenCoverFeature: Reducer { } } -private struct TodoDetailSheetFeature: Reducer { +private struct SheetFeature: Reducer { typealias State = TodoDetailFeature.SheetState typealias Action = TodoDetailFeature.Action.Sheet diff --git a/Application/Presentation/PresentationShared/Sources/Todo/List/TodoListFeature.swift b/Application/Presentation/PresentationShared/Sources/Todo/List/TodoListFeature.swift index c4007cd4..6c5874fe 100644 --- a/Application/Presentation/PresentationShared/Sources/Todo/List/TodoListFeature.swift +++ b/Application/Presentation/PresentationShared/Sources/Todo/List/TodoListFeature.swift @@ -170,12 +170,12 @@ public struct TodoListFeature { } .ifLet(\.$alert, action: \.alert) .ifLet(\.$fullScreenCover, action: \.fullScreenCover) { - TodoListFullScreenCoverFeature() + FullScreenCoverFeature() } } } -private struct TodoListFullScreenCoverFeature: Reducer { +private struct FullScreenCoverFeature: Reducer { typealias State = TodoListFeature.FullScreenCoverState typealias Action = TodoListFeature.Action.FullScreenCover @@ -189,22 +189,22 @@ private struct TodoListFullScreenCoverFeature: Reducer { public extension DependencyValues { var todoListFetchTodosUseCase: FetchTodosUseCase { - get { self[TodoListFetchTodosUseCaseKey.self] } - set { self[TodoListFetchTodosUseCaseKey.self] = newValue } + get { self[FetchTodosUseCaseKey.self] } + set { self[FetchTodosUseCaseKey.self] = newValue } } var todoListDeleteTodoUseCase: DeleteTodoUseCase { - get { self[TodoListDeleteTodoUseCaseKey.self] } - set { self[TodoListDeleteTodoUseCaseKey.self] = newValue } + get { self[DeleteTodoUseCaseKey.self] } + set { self[DeleteTodoUseCaseKey.self] = newValue } } var todoListUndoDeleteTodoUseCase: UndoDeleteTodoUseCase { - get { self[TodoListUndoDeleteTodoUseCaseKey.self] } - set { self[TodoListUndoDeleteTodoUseCaseKey.self] = newValue } + get { self[UndoDeleteTodoUseCaseKey.self] } + set { self[UndoDeleteTodoUseCaseKey.self] = newValue } } } -private enum TodoListFetchTodosUseCaseKey: DependencyKey { +private enum FetchTodosUseCaseKey: DependencyKey { static var liveValue: FetchTodosUseCase { preconditionFailure("FetchTodosUseCase must be provided.") } @@ -214,7 +214,7 @@ private enum TodoListFetchTodosUseCaseKey: DependencyKey { } } -private enum TodoListDeleteTodoUseCaseKey: DependencyKey { +private enum DeleteTodoUseCaseKey: DependencyKey { static var liveValue: DeleteTodoUseCase { preconditionFailure("DeleteTodoUseCase must be provided.") } @@ -224,7 +224,7 @@ private enum TodoListDeleteTodoUseCaseKey: DependencyKey { } } -private enum TodoListUndoDeleteTodoUseCaseKey: DependencyKey { +private enum UndoDeleteTodoUseCaseKey: DependencyKey { static var liveValue: UndoDeleteTodoUseCase { preconditionFailure("UndoDeleteTodoUseCase must be provided.") } From 6bd866f6b784e8f7bed1d090b89ce23d6b9e71f7 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 09:03:28 +0900 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20HomeTab=20=EB=82=B4=EB=B6=80=20?= =?UTF-8?q?=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...alItem.swift => DevelopmentGoalItem.swift} | 10 +++---- ...ion.swift => DevelopmentGoalSection.swift} | 26 ++++++++-------- ...ard.swift => DevelopmentSummaryCard.swift} | 12 ++++---- .../Home/HomeFeature+Dependencies.swift | 30 +++++++++---------- .../Sources/Home/HomeFeature+Effects.swift | 16 +++++----- .../HomeTab/Sources/Home/HomeFeature.swift | 12 ++++---- .../HomeTab/Sources/Home/HomeView.swift | 6 ++-- .../Sources/HomeDependencyPreparation.swift | 12 ++++---- .../Home/HomeFeatureTestAssertions.swift | 18 +++++------ .../Tests/Home/HomeFeatureTestSpies.swift | 6 ++-- .../Tests/Home/HomeFeatureTestSupport.swift | 10 +++---- .../HomeTab/Tests/Home/HomeFeatureTests.swift | 24 +++++++-------- 12 files changed, 91 insertions(+), 91 deletions(-) rename Application/Presentation/HomeTab/Sources/Home/{HomeDevelopmentGoalItem.swift => DevelopmentGoalItem.swift} (76%) rename Application/Presentation/HomeTab/Sources/Home/{HomeDevelopmentGoalSection.swift => DevelopmentGoalSection.swift} (92%) rename Application/Presentation/HomeTab/Sources/Home/{HomeDevelopmentSummaryCard.swift => DevelopmentSummaryCard.swift} (92%) diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalItem.swift b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalItem.swift similarity index 76% rename from Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalItem.swift rename to Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalItem.swift index d511bd21..8d65c211 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalItem.swift +++ b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalItem.swift @@ -1,5 +1,5 @@ // -// HomeDevelopmentGoalItem.swift +// DevelopmentGoalItem.swift // HomeTab // // Created by opfic on 9/20/26. @@ -7,17 +7,17 @@ import Domain -struct HomeDevelopmentGoalItem: Equatable, Identifiable { +struct DevelopmentGoalItem: Equatable, Identifiable { let goal: DevelopmentGoal let recentRecord: DevelopmentRecord.Version? - let todoProgress: HomeDevelopmentGoalTodoProgress + let todoProgress: DevelopmentGoalTodoProgress var id: String { goal.id } init( goal: DevelopmentGoal, recentRecord: DevelopmentRecord.Version?, - todoProgress: HomeDevelopmentGoalTodoProgress = .empty + todoProgress: DevelopmentGoalTodoProgress = .empty ) { self.goal = goal self.recentRecord = recentRecord @@ -25,7 +25,7 @@ struct HomeDevelopmentGoalItem: Equatable, Identifiable { } } -struct HomeDevelopmentGoalTodoProgress: Equatable { +struct DevelopmentGoalTodoProgress: Equatable { let completedCount: Int let totalCount: Int diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalSection.swift b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift similarity index 92% rename from Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalSection.swift rename to Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift index cdb40e85..ffd1b7f0 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentGoalSection.swift +++ b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift @@ -1,5 +1,5 @@ // -// HomeDevelopmentGoalSection.swift +// DevelopmentGoalSection.swift // HomeTab // // Created by opfic on 9/20/26. @@ -8,13 +8,13 @@ import SwiftUI import PresentationShared -struct HomeDevelopmentGoalSection: View { - let items: [HomeDevelopmentGoalItem] +struct DevelopmentGoalSection: View { + let items: [DevelopmentGoalItem] let isLoading: Bool let hasLoaded: Bool let hasLoadFailure: Bool let onCreate: () -> Void - let onSelect: (HomeDevelopmentGoalItem) -> Void + let onSelect: (DevelopmentGoalItem) -> Void let onRetry: () -> Void var body: some View { @@ -68,7 +68,7 @@ struct HomeDevelopmentGoalSection: View { Button { onSelect(item) } label: { - HomeDevelopmentGoalCard(item: item) + DevelopmentGoalCard(item: item) } .buttonStyle(.plain) } @@ -108,13 +108,13 @@ struct HomeDevelopmentGoalSection: View { } } -private struct HomeDevelopmentGoalCard: View { - let item: HomeDevelopmentGoalItem +private struct DevelopmentGoalCard: View { + let item: DevelopmentGoalItem var body: some View { VStack(alignment: .leading, spacing: 12) { HStack(spacing: 12) { - HomeDevelopmentGoalStatusBadge() + DevelopmentGoalStatusBadge() Spacer(minLength: 12) if let recentRecord = item.recentRecord { Text(recentRecord.confirmedAt, format: .dateTime.month().day().hour().minute()) @@ -137,7 +137,7 @@ private struct HomeDevelopmentGoalCard: View { .frame(maxWidth: .infinity, alignment: .leading) } - HomeDevelopmentTodoProgressView(progress: item.todoProgress) + DevelopmentTodoProgressView(progress: item.todoProgress) Divider() @@ -164,8 +164,8 @@ private struct HomeDevelopmentGoalCard: View { } } -struct HomeDevelopmentTodoProgressView: View { - let progress: HomeDevelopmentGoalTodoProgress +struct DevelopmentTodoProgressView: View { + let progress: DevelopmentGoalTodoProgress var body: some View { if progress.isEmpty { @@ -217,7 +217,7 @@ struct HomeDevelopmentTodoProgressView: View { } } -private struct HomeDevelopmentGoalStatusBadge: View { +private struct DevelopmentGoalStatusBadge: View { var body: some View { Label { Text("development_goal_status_in_progress", bundle: PresentationResources.bundle) @@ -232,7 +232,7 @@ private struct HomeDevelopmentGoalStatusBadge: View { } } -enum HomeGoalPresentation: Identifiable { +enum GoalPresentation: Identifiable { case create case detail(String) diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentSummaryCard.swift b/Application/Presentation/HomeTab/Sources/Home/DevelopmentSummaryCard.swift similarity index 92% rename from Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentSummaryCard.swift rename to Application/Presentation/HomeTab/Sources/Home/DevelopmentSummaryCard.swift index bb1f93f9..c4498ee2 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeDevelopmentSummaryCard.swift +++ b/Application/Presentation/HomeTab/Sources/Home/DevelopmentSummaryCard.swift @@ -1,5 +1,5 @@ // -// HomeDevelopmentSummaryCard.swift +// DevelopmentSummaryCard.swift // HomeTab // // Created by opfic on 9/20/26. @@ -9,8 +9,8 @@ import Domain import SwiftUI import PresentationShared -struct HomeDevelopmentSummaryCard: View { - let items: [HomeDevelopmentGoalItem] +struct DevelopmentSummaryCard: View { + let items: [DevelopmentGoalItem] let isLoading: Bool let hasLoaded: Bool let hasLoadFailure: Bool @@ -70,7 +70,7 @@ struct HomeDevelopmentSummaryCard: View { .foregroundStyle(Color.textSecondary) } else { VStack(alignment: .leading, spacing: 8) { - HomeDevelopmentTodoProgressView(progress: todoProgress) + DevelopmentTodoProgressView(progress: todoProgress) if let recentRecord { VStack(alignment: .leading, spacing: 8) { @@ -97,8 +97,8 @@ struct HomeDevelopmentSummaryCard: View { items.compactMap(\.recentRecord).max { $0.confirmedAt < $1.confirmedAt } } - private var todoProgress: HomeDevelopmentGoalTodoProgress { - HomeDevelopmentGoalTodoProgress( + private var todoProgress: DevelopmentGoalTodoProgress { + DevelopmentGoalTodoProgress( completedCount: items.reduce(0) { $0 + $1.todoProgress.completedCount }, totalCount: items.reduce(0) { $0 + $1.todoProgress.totalCount } ) diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Dependencies.swift b/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Dependencies.swift index 0aebc592..f530eca1 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Dependencies.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Dependencies.swift @@ -10,32 +10,32 @@ import Domain extension DependencyValues { var homeFetchDevelopmentGoalsUseCase: FetchDevelopmentGoalsUseCase { - get { self[HomeFetchDevelopmentGoalsUseCaseKey.self] } - set { self[HomeFetchDevelopmentGoalsUseCaseKey.self] = newValue } + get { self[FetchDevelopmentGoalsUseCaseKey.self] } + set { self[FetchDevelopmentGoalsUseCaseKey.self] = newValue } } var homeFetchDevelopmentRecordsUseCase: FetchDevelopmentRecordsUseCase { - get { self[HomeFetchDevelopmentRecordsUseCaseKey.self] } - set { self[HomeFetchDevelopmentRecordsUseCaseKey.self] = newValue } + get { self[FetchDevelopmentRecordsUseCaseKey.self] } + set { self[FetchDevelopmentRecordsUseCaseKey.self] = newValue } } var homeFetchDevelopmentRecordVersionUseCase: FetchDevelopmentRecordVersionUseCase { - get { self[HomeFetchDevelopmentRecordVersionKey.self] } - set { self[HomeFetchDevelopmentRecordVersionKey.self] = newValue } + get { self[FetchDevelopmentRecordVersionKey.self] } + set { self[FetchDevelopmentRecordVersionKey.self] = newValue } } var homeUpdateTodoCategoryPreferencesUseCase: UpdateTodoCategoryPreferencesUseCase { - get { self[HomeUpdatePreferencesUseCaseKey.self] } - set { self[HomeUpdatePreferencesUseCaseKey.self] = newValue } + get { self[UpdatePreferencesUseCaseKey.self] } + set { self[UpdatePreferencesUseCaseKey.self] = newValue } } var homeNetworkConnectivityUseCase: ObserveNetworkConnectivityUseCase { - get { self[HomeNetworkConnectivityUseCaseKey.self] } - set { self[HomeNetworkConnectivityUseCaseKey.self] = newValue } + get { self[NetworkConnectivityUseCaseKey.self] } + set { self[NetworkConnectivityUseCaseKey.self] = newValue } } } -private enum HomeFetchDevelopmentGoalsUseCaseKey: DependencyKey { +private enum FetchDevelopmentGoalsUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentGoalsUseCase { preconditionFailure("FetchDevelopmentGoalsUseCase must be provided.") } @@ -45,7 +45,7 @@ private enum HomeFetchDevelopmentGoalsUseCaseKey: DependencyKey { } } -private enum HomeFetchDevelopmentRecordsUseCaseKey: DependencyKey { +private enum FetchDevelopmentRecordsUseCaseKey: DependencyKey { static var liveValue: FetchDevelopmentRecordsUseCase { preconditionFailure("FetchDevelopmentRecordsUseCase must be provided.") } @@ -55,7 +55,7 @@ private enum HomeFetchDevelopmentRecordsUseCaseKey: DependencyKey { } } -private enum HomeFetchDevelopmentRecordVersionKey: DependencyKey { +private enum FetchDevelopmentRecordVersionKey: DependencyKey { static var liveValue: FetchDevelopmentRecordVersionUseCase { preconditionFailure("FetchDevelopmentRecordVersionUseCase must be provided.") } @@ -65,7 +65,7 @@ private enum HomeFetchDevelopmentRecordVersionKey: DependencyKey { } } -private enum HomeUpdatePreferencesUseCaseKey: DependencyKey { +private enum UpdatePreferencesUseCaseKey: DependencyKey { static var liveValue: UpdateTodoCategoryPreferencesUseCase { preconditionFailure("UpdateTodoCategoryPreferencesUseCase must be provided.") } @@ -75,7 +75,7 @@ private enum HomeUpdatePreferencesUseCaseKey: DependencyKey { } } -private enum HomeNetworkConnectivityUseCaseKey: DependencyKey { +private enum NetworkConnectivityUseCaseKey: DependencyKey { static var liveValue: ObserveNetworkConnectivityUseCase { preconditionFailure("ObserveNetworkConnectivityUseCase must be provided.") } diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Effects.swift b/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Effects.swift index e834475b..a57173f7 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Effects.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeFeature+Effects.swift @@ -67,7 +67,7 @@ extension HomeFeature { ) let todoProgressByGoalID = Self.makeTodoProgressByGoalID((try await todos).items) let items = goalItems.map { item in - HomeDevelopmentGoalItem( + DevelopmentGoalItem( goal: item.goal, recentRecord: item.recentRecord, todoProgress: todoProgressByGoalID[item.goal.id] ?? .empty @@ -153,10 +153,10 @@ extension HomeFeature { _ goals: [DevelopmentGoal], fetchRecordsUseCase: FetchDevelopmentRecordsUseCase, fetchRecordVersionUseCase: FetchDevelopmentRecordVersionUseCase - ) async throws -> [HomeDevelopmentGoalItem] { - var items = [HomeDevelopmentGoalItem]() + ) async throws -> [DevelopmentGoalItem] { + var items = [DevelopmentGoalItem]() - try await withThrowingTaskGroup(of: HomeDevelopmentGoalItem.self) { group in + try await withThrowingTaskGroup(of: DevelopmentGoalItem.self) { group in for goal in goals { group.addTask { let records = try await fetchRecordsUseCase.execute(goalId: goal.id) @@ -165,7 +165,7 @@ extension HomeFeature { records: records, fetchRecordVersionUseCase: fetchRecordVersionUseCase ) - return HomeDevelopmentGoalItem(goal: goal, recentRecord: recentRecord) + return DevelopmentGoalItem(goal: goal, recentRecord: recentRecord) } } @@ -211,13 +211,13 @@ extension HomeFeature { static func makeTodoProgressByGoalID( _ todos: [Todo] - ) -> [String: HomeDevelopmentGoalTodoProgress] { - var progressByGoalID = [String: HomeDevelopmentGoalTodoProgress]() + ) -> [String: DevelopmentGoalTodoProgress] { + var progressByGoalID = [String: DevelopmentGoalTodoProgress]() for todo in todos { guard let goalID = todo.goalId else { continue } let currentProgress = progressByGoalID[goalID] ?? .empty - progressByGoalID[goalID] = HomeDevelopmentGoalTodoProgress( + progressByGoalID[goalID] = DevelopmentGoalTodoProgress( completedCount: currentProgress.completedCount + (todo.isCompleted ? 1 : 0), totalCount: currentProgress.totalCount + 1 ) diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift b/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift index 95ad3e68..8682a9fa 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift @@ -16,7 +16,7 @@ struct HomeFeature { @Presents var alert: AlertState? @Presents var sheet: SheetState? @Presents var fullScreenCover: FullScreenCoverState? - var developmentGoalItems = [HomeDevelopmentGoalItem]() + var developmentGoalItems = [DevelopmentGoalItem]() var hasDevelopmentGoalsLoaded = false var hasDevelopmentGoalsLoadFailure = false var preferences = [TodoCategoryItem]() @@ -69,7 +69,7 @@ struct HomeFeature { case setSheet(SheetState?) case setPresentation(Presentation, Bool) case setAlert(isPresented: Bool) - case developmentGoalsLoaded([HomeDevelopmentGoalItem]) + case developmentGoalsLoaded([DevelopmentGoalItem]) case developmentGoalsLoadFailed case setTodoCategory([TodoCategoryItem]) } @@ -190,15 +190,15 @@ struct HomeFeature { } .ifLet(\.$alert, action: \.alert) .ifLet(\.$sheet, action: \.sheet) { - HomeSheetFeature() + SheetFeature() } .ifLet(\.$fullScreenCover, action: \.fullScreenCover) { - HomeFullScreenCoverFeature() + FullScreenCoverFeature() } } } -private struct HomeFullScreenCoverFeature: Reducer { +private struct FullScreenCoverFeature: Reducer { typealias State = HomeFeature.FullScreenCoverState typealias Action = HomeFeature.FullScreenCover @@ -279,7 +279,7 @@ private extension HomeFeature { } } -private struct HomeSheetFeature: Reducer { +private struct SheetFeature: Reducer { typealias State = HomeFeature.SheetState typealias Action = HomeFeature.Sheet diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeView.swift b/Application/Presentation/HomeTab/Sources/Home/HomeView.swift index f67b457f..c7e0b687 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeView.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeView.swift @@ -19,7 +19,7 @@ public struct HomeView: View { @ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34) @ScaledMetric(relativeTo: .title2) private var categoryIconSize = CGFloat(64) @State private var path = [HomeRoute]() - @State private var goalPresentation: HomeGoalPresentation? + @State private var goalPresentation: GoalPresentation? @State private var searchStore: StoreOf @State private var store: StoreOf private let isSelected: Bool @@ -49,7 +49,7 @@ public struct HomeView: View { ScrollView { LazyVStack(alignment: .leading, spacing: 16, pinnedViews: [.sectionHeaders]) { Section { - HomeDevelopmentSummaryCard( + DevelopmentSummaryCard( items: store.developmentGoalItems, isLoading: store.isDevelopmentGoalsLoading, hasLoaded: store.hasDevelopmentGoalsLoaded, @@ -59,7 +59,7 @@ public struct HomeView: View { } header: { topBar } - HomeDevelopmentGoalSection( + DevelopmentGoalSection( items: store.developmentGoalItems, isLoading: store.isDevelopmentGoalsLoading, hasLoaded: store.hasDevelopmentGoalsLoaded, diff --git a/Application/Presentation/HomeTab/Sources/HomeDependencyPreparation.swift b/Application/Presentation/HomeTab/Sources/HomeDependencyPreparation.swift index 40e57a0a..56c13e1b 100644 --- a/Application/Presentation/HomeTab/Sources/HomeDependencyPreparation.swift +++ b/Application/Presentation/HomeTab/Sources/HomeDependencyPreparation.swift @@ -50,23 +50,23 @@ public enum HomeDependencyPreparation { extension DependencyValues { var homeFetchTodosUseCase: FetchTodosUseCase { - get { self[HomeFetchTodosUseCaseKey.self] } - set { self[HomeFetchTodosUseCaseKey.self] = newValue } + get { self[FetchTodosUseCaseKey.self] } + set { self[FetchTodosUseCaseKey.self] = newValue } } var homeFetchRecentSearchQueriesUseCase: FetchRecentSearchQueriesUseCase { - get { self[HomeFetchRecentSearchQueriesUseCaseKey.self] } - set { self[HomeFetchRecentSearchQueriesUseCaseKey.self] = newValue } + get { self[FetchRecentSearchQueriesUseCaseKey.self] } + set { self[FetchRecentSearchQueriesUseCaseKey.self] = newValue } } } -private enum HomeFetchTodosUseCaseKey: DependencyKey { +private enum FetchTodosUseCaseKey: DependencyKey { static var liveValue: FetchTodosUseCase { preconditionFailure("FetchTodosUseCase must be provided.") } } -private enum HomeFetchRecentSearchQueriesUseCaseKey: DependencyKey { +private enum FetchRecentSearchQueriesUseCaseKey: DependencyKey { static var liveValue: FetchRecentSearchQueriesUseCase { preconditionFailure("FetchRecentSearchQueriesUseCase must be provided.") } diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestAssertions.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestAssertions.swift index 4486d4c4..a3bb70dc 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestAssertions.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestAssertions.swift @@ -13,7 +13,7 @@ import PresentationShared @MainActor func verifyHomeFetchData( - adapter: HomeStoreTestAdapter + adapter: StoreTestAdapter ) async throws { await adapter.fetchData() @@ -26,7 +26,7 @@ func verifyHomeFetchData( @MainActor func verifyHomeTapTodoCategory( - adapter: HomeStoreTestAdapter + adapter: StoreTestAdapter ) async throws { await adapter.setPresentation(.contentPicker, true) await adapter.tapTodoCategory(.system(.feature)) @@ -37,7 +37,7 @@ func verifyHomeTapTodoCategory( @MainActor func verifyHomeOrderTodoCategory( - adapter: HomeStoreTestAdapter, + adapter: StoreTestAdapter, updatePreferencesUseCaseSpy: UpdateTodoCategoryPreferencesUseCaseSpy ) async throws { await adapter.fetchData() @@ -67,7 +67,7 @@ func verifyHomeOrderTodoCategory( #expect(!adapter.showCategoryManage) } -struct HomeFetchDataContext { +struct FetchDataContext { let fetchPreferencesUseCaseSpy: FetchTodoCategoryPreferencesUseCaseSpy } @@ -142,7 +142,7 @@ func makeHomeTodo( ) } -func makeHomeFetchDataContext() -> HomeFetchDataContext { +func makeHomeFetchDataContext() -> FetchDataContext { let fetchPreferencesUseCaseSpy = FetchTodoCategoryPreferencesUseCaseSpy() fetchPreferencesUseCaseSpy.todoCategoryPreferences = [ TodoCategoryPreference(category: .system(.feature), isVisible: true), @@ -158,19 +158,19 @@ func makeHomeFetchDataContext() -> HomeFetchDataContext { ) ] - return HomeFetchDataContext( + return FetchDataContext( fetchPreferencesUseCaseSpy: fetchPreferencesUseCaseSpy ) } -struct HomeOrderContext { +struct OrderContext { let fetchPreferencesUseCaseSpy: FetchTodoCategoryPreferencesUseCaseSpy let updatePreferencesUseCaseSpy: UpdateTodoCategoryPreferencesUseCaseSpy } -func makeHomeOrderContext() -> HomeOrderContext { +func makeHomeOrderContext() -> OrderContext { let fetchContext = makeHomeFetchDataContext() - return HomeOrderContext( + return OrderContext( fetchPreferencesUseCaseSpy: fetchContext.fetchPreferencesUseCaseSpy, updatePreferencesUseCaseSpy: UpdateTodoCategoryPreferencesUseCaseSpy() ) diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSpies.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSpies.swift index 32cccdfe..32c407b4 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSpies.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSpies.swift @@ -75,11 +75,11 @@ final class FetchDevelopmentRecordVersionUseCaseSpy: FetchDevelopmentRecordVersi recordId: String, versionId: String ) async throws -> DevelopmentRecord.Version { - try resultByRecordID[recordId, default: .failure(HomeDevelopmentGoalTestError.notFound)].get() + try resultByRecordID[recordId, default: .failure(DevelopmentGoalTestError.notFound)].get() } } -final class HomeFetchTodosUseCaseSpy: FetchTodosUseCase { +final class FetchTodosUseCaseSpy: FetchTodosUseCase { private(set) var queries = [TodoQuery]() var page = TodoPage(items: [], nextCursor: nil) @@ -89,7 +89,7 @@ final class HomeFetchTodosUseCaseSpy: FetchTodosUseCase { } } -enum HomeDevelopmentGoalTestError: Error { +enum DevelopmentGoalTestError: Error { case failed case notFound } diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift index 83ab1904..cf2135dc 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift @@ -14,13 +14,13 @@ import PresentationShared import Foundation @MainActor -struct HomeStoreTestAdapter { +struct StoreTestAdapter { private let store: TestStoreOf private let clock: TestClock var preferences: [TodoCategoryItem] { store.state.preferences } var isTodoCategoryExpanded: Bool { store.state.isTodoCategoryExpanded } - var developmentGoalItems: [HomeDevelopmentGoalItem] { store.state.developmentGoalItems } + var developmentGoalItems: [DevelopmentGoalItem] { store.state.developmentGoalItems } var hasDevelopmentGoalsLoaded: Bool { store.state.hasDevelopmentGoalsLoaded } var hasDevelopmentGoalsLoadFailure: Bool { store.state.hasDevelopmentGoalsLoadFailure } var isNetworkConnected: Bool { store.state.isNetworkConnected } @@ -38,8 +38,8 @@ struct HomeStoreTestAdapter { fetchDevelopmentRecordsUseCase: FetchDevelopmentRecordsUseCase = FetchDevelopmentRecordsUseCaseSpy(), fetchDevelopmentRecordVersionUseCase: FetchDevelopmentRecordVersionUseCase = FetchDevelopmentRecordVersionUseCaseSpy(), - fetchTodosUseCase: FetchTodosUseCase = HomeFetchTodosUseCaseSpy(), - trackAnalyticsEventUseCase: TrackAnalyticsEventUseCase = HomeTrackAnalyticsEventUseCaseSpy(), + fetchTodosUseCase: FetchTodosUseCase = FetchTodosUseCaseSpy(), + trackAnalyticsEventUseCase: TrackAnalyticsEventUseCase = TrackAnalyticsEventUseCaseSpy(), configureDependencies: ((inout DependencyValues) -> Void)? = nil ) { let clock = TestClock() @@ -112,7 +112,7 @@ struct HomeStoreTestAdapter { } } -final class HomeTrackAnalyticsEventUseCaseSpy: TrackAnalyticsEventUseCase { +final class TrackAnalyticsEventUseCaseSpy: TrackAnalyticsEventUseCase { private(set) var events = [AnalyticsEvent]() var hasTrackedTodoCreate: Bool { events.contains { diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift index e01610be..73ec662f 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift @@ -16,7 +16,7 @@ struct HomeFeatureTests { @Test("HomeFeature fetchData는 홈 상태를 갱신한다") func HomeFeature_fetchData는_홈_상태를_갱신한다() async throws { let context = makeHomeFetchDataContext() - let adapter = HomeStoreTestAdapter( + let adapter = StoreTestAdapter( fetchPreferencesUseCase: context.fetchPreferencesUseCaseSpy ) @@ -55,7 +55,7 @@ struct HomeFeatureTests { let versionsSpy = FetchDevelopmentRecordVersionUseCaseSpy() versionsSpy.resultByRecordID[olderRecord.id] = .success(olderVersion) versionsSpy.resultByRecordID[recentRecord.id] = .success(recentVersion) - let adapter = HomeStoreTestAdapter( + let adapter = StoreTestAdapter( fetchDevelopmentGoalsUseCase: goalsSpy, fetchDevelopmentRecordsUseCase: recordsSpy, fetchDevelopmentRecordVersionUseCase: versionsSpy @@ -73,7 +73,7 @@ struct HomeFeatureTests { @Test("HomeFeature fetchData는 연결 Todo 완료 수로 목표 진행률을 계산한다") func HomeFeature_fetchData는_연결_Todo_완료_수로_목표_진행률을_계산한다() async throws { let goal = try makeDevelopmentGoal(id: "goal", createdAt: 1) - let todosSpy = HomeFetchTodosUseCaseSpy() + let todosSpy = FetchTodosUseCaseSpy() todosSpy.page = TodoPage( items: [ makeHomeTodo(id: "completed", goalID: goal.id, isCompleted: true), @@ -84,7 +84,7 @@ struct HomeFeatureTests { ) let goalsSpy = FetchDevelopmentGoalsUseCaseSpy() goalsSpy.result = .success([goal]) - let adapter = HomeStoreTestAdapter( + let adapter = StoreTestAdapter( fetchDevelopmentGoalsUseCase: goalsSpy, fetchTodosUseCase: todosSpy ) @@ -107,8 +107,8 @@ struct HomeFeatureTests { @Test("HomeFeature fetchData 실패 뒤 재시도는 진행 중 목표를 갱신한다") func HomeFeature_fetchData_실패_뒤_재시도는_진행_중_목표를_갱신한다() async throws { let goalsSpy = FetchDevelopmentGoalsUseCaseSpy() - goalsSpy.result = .failure(HomeDevelopmentGoalTestError.failed) - let adapter = HomeStoreTestAdapter(fetchDevelopmentGoalsUseCase: goalsSpy) + goalsSpy.result = .failure(DevelopmentGoalTestError.failed) + let adapter = StoreTestAdapter(fetchDevelopmentGoalsUseCase: goalsSpy) await adapter.fetchData() @@ -125,14 +125,14 @@ struct HomeFeatureTests { @Test("HomeFeature tapTodoCategory는 editor를 지연 표시한다") func HomeFeature_tapTodoCategory는_editor를_지연_표시한다() async throws { - let adapter = HomeStoreTestAdapter() + let adapter = StoreTestAdapter() try await verifyHomeTapTodoCategory(adapter: adapter) } @Test("HomeFeature 카테고리 펼침 버튼은 펼침 상태를 전환한다") func HomeFeature_카테고리_펼침_버튼은_펼침_상태를_전환한다() async { - let adapter = HomeStoreTestAdapter() + let adapter = StoreTestAdapter() await adapter.tapTodoCategoryExpansionButton() @@ -142,8 +142,8 @@ struct HomeFeatureTests { @Test("TodoEditor 생성 delegate는 editor를 닫고 홈 데이터를 다시 조회한다") func TodoEditor_생성_delegate는_editor를_닫고_홈_데이터를_다시_조회한다() async throws { let context = makeHomeFetchDataContext() - let trackSpy = HomeTrackAnalyticsEventUseCaseSpy() - let adapter = HomeStoreTestAdapter( + let trackSpy = TrackAnalyticsEventUseCaseSpy() + let adapter = StoreTestAdapter( fetchPreferencesUseCase: context.fetchPreferencesUseCaseSpy, trackAnalyticsEventUseCase: trackSpy ) @@ -162,7 +162,7 @@ struct HomeFeatureTests { @Test("HomeFeature orderTodoCategory는 카테고리 설정을 저장한다") func HomeFeature_orderTodoCategory는_카테고리_설정을_저장한다() async throws { let context = makeHomeOrderContext() - let adapter = HomeStoreTestAdapter( + let adapter = StoreTestAdapter( fetchPreferencesUseCase: context.fetchPreferencesUseCaseSpy, updatePreferencesUseCase: context.updatePreferencesUseCaseSpy ) @@ -176,7 +176,7 @@ struct HomeFeatureTests { @Test("HomeFeature startObserving은 네트워크 연결 상태를 반영한다") func HomeFeature_startObserving은_네트워크_연결_상태를_반영한다() async { let networkUseCaseSpy = ObserveNetworkConnectivityUseCaseSpy() - let adapter = HomeStoreTestAdapter(networkConnectivityUseCase: networkUseCaseSpy) + let adapter = StoreTestAdapter(networkConnectivityUseCase: networkUseCaseSpy) await adapter.startObserving() From 651e2449ef8da8f15257185e314974277935ac10 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 09:25:38 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20Entry=20Root=20=EC=8B=9D?= =?UTF-8?q?=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Root/{RootFeature.swift => Feature.swift} | 10 ++++---- .../Entry/Sources/Root/RootView.swift | 6 ++--- ...Support.swift => FeatureTestSupport.swift} | 8 +++---- ...tFeatureTests.swift => FeatureTests.swift} | 24 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) rename Application/Presentation/Entry/Sources/Root/{RootFeature.swift => Feature.swift} (98%) rename Application/Presentation/Entry/Tests/Root/{RootFeatureTestSupport.swift => FeatureTestSupport.swift} (98%) rename Application/Presentation/Entry/Tests/Root/{RootFeatureTests.swift => FeatureTests.swift} (85%) diff --git a/Application/Presentation/Entry/Sources/Root/RootFeature.swift b/Application/Presentation/Entry/Sources/Root/Feature.swift similarity index 98% rename from Application/Presentation/Entry/Sources/Root/RootFeature.swift rename to Application/Presentation/Entry/Sources/Root/Feature.swift index 13edf0d5..9a57f614 100644 --- a/Application/Presentation/Entry/Sources/Root/RootFeature.swift +++ b/Application/Presentation/Entry/Sources/Root/Feature.swift @@ -1,5 +1,5 @@ // -// RootFeature.swift +// Feature.swift // Entry // // Created by opfic on 6/17/26. @@ -12,7 +12,7 @@ import Domain import Foundation @Reducer -struct RootFeature { +struct Feature { private enum CancelID: Hashable { case networkConnectivity case session @@ -147,8 +147,8 @@ struct RootFeature { } private struct SheetFeature: Reducer { - typealias State = RootFeature.SheetState - typealias Action = RootFeature.Action.Sheet + typealias State = Feature.SheetState + typealias Action = Feature.Action.Sheet var body: some ReducerOf { EmptyReducer() @@ -237,7 +237,7 @@ private enum SystemThemeUseCaseKey: DependencyKey { } } -private extension RootFeature { +private extension Feature { func checkAppUpdateEffect() -> Effect { .run { [checkAppUpdateUseCase] send in let isRequired = (try? await checkAppUpdateUseCase.execute()) ?? false diff --git a/Application/Presentation/Entry/Sources/Root/RootView.swift b/Application/Presentation/Entry/Sources/Root/RootView.swift index 73dbf43e..1c239d70 100644 --- a/Application/Presentation/Entry/Sources/Root/RootView.swift +++ b/Application/Presentation/Entry/Sources/Root/RootView.swift @@ -10,7 +10,7 @@ import Combine import PresentationShared public struct RootView: View { - @State private var store: StoreOf + @State private var store: StoreOf private let widgetURLTab: (URL) -> MainTab? private let windowEvent: TodoEditorWindowEvent private let pushNotificationTodoIdPublisher: AnyPublisher @@ -22,8 +22,8 @@ public struct RootView: View { pushNotificationTodoIdPublisher: AnyPublisher, clearPushNotificationRoute: @escaping () -> Void ) { - self._store = State(initialValue: Store(initialState: RootFeature.State()) { - RootFeature() + self._store = State(initialValue: Store(initialState: Feature.State()) { + Feature() }) self.widgetURLTab = widgetURLTab self.windowEvent = windowEvent diff --git a/Application/Presentation/Entry/Tests/Root/RootFeatureTestSupport.swift b/Application/Presentation/Entry/Tests/Root/FeatureTestSupport.swift similarity index 98% rename from Application/Presentation/Entry/Tests/Root/RootFeatureTestSupport.swift rename to Application/Presentation/Entry/Tests/Root/FeatureTestSupport.swift index 1009c3ef..861ac674 100644 --- a/Application/Presentation/Entry/Tests/Root/RootFeatureTestSupport.swift +++ b/Application/Presentation/Entry/Tests/Root/FeatureTestSupport.swift @@ -1,5 +1,5 @@ // -// RootFeatureTestSupport.swift +// FeatureTestSupport.swift // EntryTests // // Created by opfic on 6/17/26. @@ -41,7 +41,7 @@ struct RootStateSnapshot: Equatable { @MainActor struct RootStoreTestAdapter: RootStateDriving { - private let store: TestStoreOf + private let store: TestStoreOf var snapshot: RootStateSnapshot { RootStateSnapshot( @@ -69,8 +69,8 @@ struct RootStoreTestAdapter: RootStateDriving { openURLSpy: RootOpenURLSpy = RootOpenURLSpy(), badgeCountSpy: RootApplicationBadgeCountSpy = RootApplicationBadgeCountSpy() ) { - store = TestStore(initialState: RootFeature.State()) { - RootFeature() + store = TestStore(initialState: Feature.State()) { + Feature() } withDependencies: { $0.observeAuthSessionUseCase = sessionUseCase $0.rootNetworkConnectivityUseCase = networkConnectivityUseCase diff --git a/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift b/Application/Presentation/Entry/Tests/Root/FeatureTests.swift similarity index 85% rename from Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift rename to Application/Presentation/Entry/Tests/Root/FeatureTests.swift index d9b34f7e..8ed25c58 100644 --- a/Application/Presentation/Entry/Tests/Root/RootFeatureTests.swift +++ b/Application/Presentation/Entry/Tests/Root/FeatureTests.swift @@ -1,5 +1,5 @@ // -// RootFeatureTests.swift +// FeatureTests.swift // EntryTests // // Created by opfic on 6/17/26. @@ -11,29 +11,29 @@ import PresentationShared import Testing @MainActor -struct RootFeatureTests { - @Test("RootFeature networkStatusChanged는 기존 Root 상태관리처럼 alert 문구와 표시 상태를 갱신한다") +struct FeatureTests { + @Test("Feature networkStatusChanged는 기존 Root 상태관리처럼 alert 문구와 표시 상태를 갱신한다") func RootFeature_networkStatusChanged는_기존_Root_상태관리처럼_alert_문구와_표시_상태를_갱신한다() async { let adapter = RootStoreTestAdapter() await verifyNetworkDisconnectedAlert(adapter: adapter) } - @Test("RootFeature setAlert(false)는 기존 Root 상태관리처럼 alert 문구를 유지한 채 표시 상태를 해제한다") + @Test("Feature setAlert(false)는 기존 Root 상태관리처럼 alert 문구를 유지한 채 표시 상태를 해제한다") func RootFeature_setAlert_false는_기존_Root_상태관리처럼_alert_문구를_유지한_채_표시_상태를_해제한다() async { let adapter = RootStoreTestAdapter() await verifySetAlert(adapter: adapter) } - @Test("RootFeature setTheme은 기존 Root 상태관리처럼 테마 상태를 갱신한다") + @Test("Feature setTheme은 기존 Root 상태관리처럼 테마 상태를 갱신한다") func RootFeature_setTheme은_기존_Root_상태관리처럼_테마_상태를_갱신한다() async { let adapter = RootStoreTestAdapter() await verifyThemeUpdate(adapter: adapter) } - @Test("RootFeature didLogined(false)는 기존 Root 상태관리처럼 signIn 상태를 갱신하고 login 화면 추적을 요청한다") + @Test("Feature didLogined(false)는 기존 Root 상태관리처럼 signIn 상태를 갱신하고 login 화면 추적을 요청한다") func RootFeature_didLogined_false는_기존_Root_상태관리처럼_signIn_상태를_갱신하고_login_화면_추적을_요청한다() async { let trackSpy = RootTrackAnalyticsEventUseCaseSpy() let adapter = RootStoreTestAdapter(trackAnalyticsEventUseCase: trackSpy) @@ -41,7 +41,7 @@ struct RootFeatureTests { await verifyDidLoginedFalse(adapter: adapter, trackAnalyticsEventUseCaseSpy: trackSpy) } - @Test("RootFeature didLogined(false)는 앱 badge 초기화를 요청한다") + @Test("Feature didLogined(false)는 앱 badge 초기화를 요청한다") func RootFeature_didLogined_false는_앱_badge_초기화를_요청한다() async { let badgeSpy = RootApplicationBadgeCountSpy() let adapter = RootStoreTestAdapter(badgeCountSpy: badgeSpy) @@ -54,7 +54,7 @@ struct RootFeatureTests { #expect(badgeSpy.counts == [0]) } - @Test("RootFeature didLogined(true)는 기존 Root 상태관리처럼 signIn 상태를 true로 갱신하고 selectedMainTab을 home으로 되돌린다") + @Test("Feature didLogined(true)는 기존 Root 상태관리처럼 signIn 상태를 true로 갱신하고 selectedMainTab을 home으로 되돌린다") func RootFeature_didLogined_true는_기존_Root_상태관리처럼_signIn_상태를_true로_갱신하고_selectedMainTab을_home으로_되돌린다() async { let trackSpy = RootTrackAnalyticsEventUseCaseSpy() let adapter = RootStoreTestAdapter(trackAnalyticsEventUseCase: trackSpy) @@ -62,7 +62,7 @@ struct RootFeatureTests { await verifyDidLoginedTrue(adapter: adapter, trackAnalyticsEventUseCaseSpy: trackSpy) } - @Test("RootFeature onAppear는 기존 Root 상태관리처럼 session, network, theme 관찰을 한 번만 시작한다") + @Test("Feature onAppear는 기존 Root 상태관리처럼 session, network, theme 관찰을 한 번만 시작한다") func RootFeature_onAppear는_기존_Root_상태관리처럼_session_network_theme_관찰을_한_번만_시작한다() async { let sessionSpy = ObserveAuthSessionUseCaseSpy(currentValue: true) let networkSpy = RootObserveNetworkConnectivityUseCaseSpy(currentValue: true) @@ -81,7 +81,7 @@ struct RootFeatureTests { #expect(themeSpy.observeCallCount == 1) } - @Test("RootFeature onAppear는 기존 Root 상태관리처럼 초기 publisher 값으로 signIn, network, theme 상태를 반영한다") + @Test("Feature onAppear는 기존 Root 상태관리처럼 초기 publisher 값으로 signIn, network, theme 상태를 반영한다") func RootFeature_onAppear는_기존_Root_상태관리처럼_초기_publisher_값으로_signIn_network_theme_상태를_반영한다() async { let adapter = RootStoreTestAdapter( sessionUseCase: ObserveAuthSessionUseCaseSpy(currentValue: false), @@ -92,7 +92,7 @@ struct RootFeatureTests { await verifyObservedInitialValues(adapter: adapter) } - @Test("RootFeature onAppear는 앱 badge 초기화를 요청한다") + @Test("Feature onAppear는 앱 badge 초기화를 요청한다") func RootFeature_onAppear는_앱_badge_초기화를_요청한다() async { let badgeSpy = RootApplicationBadgeCountSpy() let adapter = RootStoreTestAdapter(badgeCountSpy: badgeSpy) @@ -106,7 +106,7 @@ struct RootFeatureTests { #expect(badgeSpy.counts == [0, 0]) } - @Test("RootFeature onAppear는 로그인 상태와 무관하게 업데이트를 한 번만 확인한다") + @Test("Feature onAppear는 로그인 상태와 무관하게 업데이트를 한 번만 확인한다") func RootFeature_onAppear는_로그인_상태와_무관하게_업데이트를_한_번만_확인한다() async { let checkSpy = RootCheckAppUpdateUseCaseSpy() let adapter = RootStoreTestAdapter( From 6c376f21f2ad02d2700abbc16a708f937f5e5f57 Mon Sep 17 00:00:00 2001 From: opficdev Date: Mon, 21 Sep 2026 09:25:53 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20PresentationShared=20Todo=20?= =?UTF-8?q?=EC=8B=9D=EB=B3=84=EC=9E=90=20=EC=A0=91=EB=91=90=EC=96=B4=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Todo/Detail/TodoDetailView.swift | 4 ++-- .../Tests/Todo/TodoDetailFeatureTests.swift | 22 +++++++++---------- .../Todo/TodoListFeatureTestDoubles.swift | 4 ++-- .../Tests/Todo/TodoListFeatureTests.swift | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailView.swift b/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailView.swift index 4934e89d..f97292ba 100644 --- a/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailView.swift +++ b/Application/Presentation/PresentationShared/Sources/Todo/Detail/TodoDetailView.swift @@ -122,7 +122,7 @@ public struct TodoDetailView: View { switch sheetStore.state { case .info: if let todo = store.todo { - TodoDetailInfoSheetView(todo: todo) { + InfoSheetView(todo: todo) { sheetStore.send(.tapCloseButton) } } @@ -143,7 +143,7 @@ public struct TodoDetailView: View { } } -private struct TodoDetailInfoSheetView: View { +private struct InfoSheetView: View { let todo: Todo let onClose: () -> Void private let calendar = Calendar.current diff --git a/Application/Presentation/PresentationShared/Tests/Todo/TodoDetailFeatureTests.swift b/Application/Presentation/PresentationShared/Tests/Todo/TodoDetailFeatureTests.swift index 608f3bbd..a64ecc75 100644 --- a/Application/Presentation/PresentationShared/Tests/Todo/TodoDetailFeatureTests.swift +++ b/Application/Presentation/PresentationShared/Tests/Todo/TodoDetailFeatureTests.swift @@ -17,7 +17,7 @@ struct TodoDetailFeatureTests { let todo = makeTodo(id: "todo-1", content: "content") let fetchSpy = FetchTodoByIdUseCaseSpy(todo: todo) let referenceSpy = FetchReferenceItemsUseCaseSpy() - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: referenceSpy, todoId: "todo-1" @@ -51,7 +51,7 @@ struct TodoDetailFeatureTests { 3: reference3, 5: reference5 ]) - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: referenceSpy, todoId: todo.id @@ -73,7 +73,7 @@ struct TodoDetailFeatureTests { let reference7 = makeTodoReference(id: "todo-7", title: "Reference 7") let fetchSpy = FetchTodoByIdUseCaseSpy(todo: makeTodo()) let referenceSpy = FetchReferenceItemsUseCaseSpy(references: [7: reference7]) - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: referenceSpy, todoId: "todo-1" @@ -96,7 +96,7 @@ struct TodoDetailFeatureTests { let clock = TestClock() let fetchSpy = FetchTodoByIdUseCaseSpy(todo: makeTodo()) fetchSpy.shouldSuspend = true - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: FetchReferenceItemsUseCaseSpy(), todoId: "todo-1", @@ -133,8 +133,8 @@ struct TodoDetailFeatureTests { @Test("Todo 조회 실패 시 공통 에러 알림 상태를 설정한다") func Todo_조회_실패_시_공통_에러_알림_상태를_설정한다() async { let fetchSpy = FetchTodoByIdUseCaseSpy(todo: makeTodo()) - fetchSpy.error = TodoDetailTestError.failure - let adapter = TodoDetailStoreTestAdapter( + fetchSpy.error = DetailTestError.failure + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: FetchReferenceItemsUseCaseSpy(), todoId: "todo-1" @@ -157,7 +157,7 @@ struct TodoDetailFeatureTests { todo: makeTodo(id: "todo-2", content: "- refs #7") ) let referenceSpy = FetchReferenceItemsUseCaseSpy(references: [7: reference]) - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: fetchSpy, referenceUseCase: referenceSpy, todoId: "todo-1", @@ -198,7 +198,7 @@ struct TodoDetailFeatureTests { func TodoEditor_수정_delegate는_editor를_닫고_Todo_상세_상태를_갱신한다() async { let reference = makeTodoReference(id: "todo-7", title: "Reference 7") let referenceSpy = FetchReferenceItemsUseCaseSpy(references: [7: reference]) - let adapter = TodoDetailStoreTestAdapter( + let adapter = DetailStoreTestAdapter( fetchUseCase: FetchTodoByIdUseCaseSpy(todo: makeTodo()), referenceUseCase: referenceSpy, todoId: "todo-1" @@ -226,7 +226,7 @@ struct TodoDetailFeatureTests { } @MainActor -private protocol TodoDetailTestAdapter { +private protocol DetailTestAdapter { var todoId: String { get } var showEditButton: Bool { get } var todo: Todo? { get } @@ -249,7 +249,7 @@ private protocol TodoDetailTestAdapter { } @MainActor -private struct TodoDetailStoreTestAdapter: TodoDetailTestAdapter { +private struct DetailStoreTestAdapter: DetailTestAdapter { private let store: StoreOf var todoId: String { store.todoId } @@ -404,7 +404,7 @@ private final class FetchReferenceItemsUseCaseSpy: FetchReferenceItemsUseCase { } } -private enum TodoDetailTestError: Error { +private enum DetailTestError: Error { case failure } diff --git a/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTestDoubles.swift b/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTestDoubles.swift index 77ae8cf9..d8c69f4d 100644 --- a/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTestDoubles.swift +++ b/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTestDoubles.swift @@ -200,7 +200,7 @@ final class TodoListFetchTodosUseCaseSpy: FetchTodosUseCase { } } -actor TodoListDelayedFirstFetchTodosUseCaseSpy: FetchTodosUseCase { +actor DelayedFirstFetchTodosUseCaseSpy: FetchTodosUseCase { private let pages: [TodoPage] private var queries = [TodoQuery]() private var cursors = [TodoCursor?]() @@ -352,7 +352,7 @@ final class TodoListTrackAnalyticsEventUseCaseSpy: TrackAnalyticsEventUseCase { } } -enum TodoListTestError: Error { +enum ListTestError: Error { case failure } diff --git a/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTests.swift b/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTests.swift index 382f3100..bc6c1f73 100644 --- a/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTests.swift +++ b/Application/Presentation/PresentationShared/Tests/Todo/TodoListFeatureTests.swift @@ -66,7 +66,7 @@ struct TodoListFeatureTests { func 새_목록_조회는_이전_요청을_취소하고_마지막_응답만_반영한다() async { let firstTodo = makeTodoListTodo(id: "todo-first", number: 1) let secondTodo = makeTodoListTodo(id: "todo-second", number: 2) - let fetchSpy = TodoListDelayedFirstFetchTodosUseCaseSpy(pages: [ + let fetchSpy = DelayedFirstFetchTodosUseCaseSpy(pages: [ TodoPage(items: [firstTodo], nextCursor: nil), TodoPage(items: [secondTodo], nextCursor: nil) ]) @@ -257,7 +257,7 @@ struct TodoListFeatureTests { @Test("Todo 조회 실패 시 공통 에러 알림 상태를 표시한다") func Todo_조회_실패_시_공통_에러_알림_상태를_표시한다() async { let fetchSpy = TodoListFetchTodosUseCaseSpy() - fetchSpy.error = TodoListTestError.failure + fetchSpy.error = ListTestError.failure let adapter = TodoListStoreTestAdapter(fetchUseCase: fetchSpy) await adapter.onAppear()