From b0d4c98735dee4972db3b3c46aafa4d9b65a2e36 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 14:16:09 +0900 Subject: [PATCH 01/12] =?UTF-8?q?[#31]=20=ED=8F=B4=EB=8D=94=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Feature/AddFolder/AddFolderView.swift | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Mark-In/Sources/Feature/AddFolder/AddFolderView.swift diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift new file mode 100644 index 0000000..453fc6a --- /dev/null +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -0,0 +1,65 @@ +// +// AddFolderView.swift +// Mark-In +// +// Created by 이정동 on 5/8/25. +// + +import SwiftUI + +import DesignSystem + +struct AddFolderView: View { + @Environment(\.dismiss) private var dismiss + @State private var title: String = "" + + var body: some View { + VStack(spacing: 0) { + Text("폴더를 추가:") + .frame(maxWidth: .infinity, alignment: .leading) + + TextField("", text: $title, prompt: Text("제목")) + .textFieldStyle(.roundedBorder) + .padding(.top, 14) + + HStack { + Button { + dismiss() + } label: { + Text("취소") + .padding(.vertical, 4) + .padding(.horizontal, 14) + .foregroundStyle(.markBlack) + .background(.markWhite) + .clipShape(RoundedRectangle(cornerRadius: 6)) + .overlay { + RoundedRectangle(cornerRadius: 6) + .stroke(.markBlack10, lineWidth: 0.5) + } + } + + Button { + // TODO: 폴더 추가 로직 + dismiss() + } label: { + Text("추가") + .padding(.vertical, 4) + .padding(.horizontal, 14) + .foregroundStyle(.markWhite) + .background(.markPoint) + .clipShape(RoundedRectangle(cornerRadius: 6)) + } + } + .frame(maxWidth: .infinity, alignment: .trailing) + .padding(.top, 18) + .font(.pretendard(size: 14, weight: .medium)) + .buttonStyle(.plain) + } + .padding(20) + .frame(width: 400) + } +} + +#Preview { + AddFolderView() +} From 2352ed19d47332ad99058237a0748d30d9ce0e4d Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 14:16:31 +0900 Subject: [PATCH 02/12] =?UTF-8?q?[#31]=20=EB=A7=81=ED=81=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=ED=99=94=EB=A9=B4=20=EB=94=94=EC=9E=90=EC=9D=B8=20?= =?UTF-8?q?=EC=83=89=EC=83=81=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mark-In/Sources/Feature/AddLink/AddLinkView.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mark-In/Sources/Feature/AddLink/AddLinkView.swift b/Mark-In/Sources/Feature/AddLink/AddLinkView.swift index 74634fd..121b29c 100644 --- a/Mark-In/Sources/Feature/AddLink/AddLinkView.swift +++ b/Mark-In/Sources/Feature/AddLink/AddLinkView.swift @@ -63,12 +63,12 @@ struct AddLinkView: View { Text("취소") .padding(.vertical, 4) .padding(.horizontal, 14) - .foregroundStyle(.black) - .background(.white) + .foregroundStyle(.markBlack) + .background(.markWhite) .clipShape(RoundedRectangle(cornerRadius: 6)) .overlay { RoundedRectangle(cornerRadius: 6) - .stroke(.gray, lineWidth: 0.5) + .stroke(.markBlack10, lineWidth: 0.5) } } @@ -79,8 +79,8 @@ struct AddLinkView: View { Text("추가") .padding(.vertical, 4) .padding(.horizontal, 14) - .foregroundStyle(.white) - .background(.blue) + .foregroundStyle(.markWhite) + .background(.markPoint) .clipShape(RoundedRectangle(cornerRadius: 6)) } } From fb0fc158fe9cd1904f19ebc0a3fabaa360237b8f Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 15:41:20 +0900 Subject: [PATCH 03/12] =?UTF-8?q?[#31]=20AddFolderViewModel=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddFolder/AddFolderViewModel.swift | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift new file mode 100644 index 0000000..e46b063 --- /dev/null +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift @@ -0,0 +1,58 @@ +// +// AddFolderViewModel.swift +// Mark-In +// +// Created by 이정동 on 5/8/25. +// + +import Foundation + +@Observable @MainActor +final class AddFolderViewModel: Reducer { + struct State { + var createdFolder: Folder? + var isSaving: Bool = false + } + + enum Action { + case addLinkButtonTapped(title: String) + case completeSave(Folder) + } + + private(set) var state: State = .init() + + func send(_ action: Action) { + let effect = reduce(state: &state, action: action) + handleEffect(effect) + } + + func reduce(state: inout State, action: Action) -> Effect { + switch action { + case .addLinkButtonTapped(let title): + state.isSaving = true + + // TODO: 실제 저장 과정 구현 예정 + return .run { + try? await Task.sleep(nanoseconds: 3_000_000_000) + return .completeSave(.init(id: "", name: title, createdBy: .now)) + } + case .completeSave(let folder): + state.isSaving = false + state.createdFolder = folder + return .none + } + } + + private func handleEffect(_ effect: Effect) { + switch effect { + case .none: + break + case .run(let action): + Task.detached { [weak self] in + let newAction = await action() + await self?.send(newAction) + } + } + } +} + From fe8e1d2ae987c7cf30640e7db5d4e64bfab41aa8 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 15:43:35 +0900 Subject: [PATCH 04/12] =?UTF-8?q?[#31]=20AddFolderViewModel=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Feature/AddFolder/AddFolderView.swift | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift index 453fc6a..5090840 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -11,8 +11,11 @@ import DesignSystem struct AddFolderView: View { @Environment(\.dismiss) private var dismiss + @State private var viewModel = AddFolderViewModel() @State private var title: String = "" + let completion: (Folder) -> () + var body: some View { VStack(spacing: 0) { Text("폴더를 추가:") @@ -39,8 +42,7 @@ struct AddFolderView: View { } Button { - // TODO: 폴더 추가 로직 - dismiss() + viewModel.send(.addLinkButtonTapped(title: title)) } label: { Text("추가") .padding(.vertical, 4) @@ -49,6 +51,7 @@ struct AddFolderView: View { .background(.markPoint) .clipShape(RoundedRectangle(cornerRadius: 6)) } + .disabled(title.isEmpty) } .frame(maxWidth: .infinity, alignment: .trailing) .padding(.top, 18) @@ -57,9 +60,24 @@ struct AddFolderView: View { } .padding(20) .frame(width: 400) + .overlay(content: { + if viewModel.state.isSaving { + ProgressView() + .frame(maxWidth: .infinity, maxHeight: .infinity) + .contentShape(Rectangle()) + .background(.gray.opacity(0.5)) + } + }) + .onChange(of: viewModel.state.createdFolder) { + guard let folder = $1 else { return } + completion(folder) + dismiss() + } } } #Preview { - AddFolderView() + AddFolderView() { + print($0) + } } From 8dfb7e53cecf88b1453bbda10c078c7c2f4ae132 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 15:50:00 +0900 Subject: [PATCH 05/12] =?UTF-8?q?[#31]=20TestFolder=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=20=EB=B0=8F=20Folder=20Entity=EC=97=90=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=86=A0=EC=BD=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mark-In/Sources/Domain/Entities/Folder.swift | 2 +- Mark-In/Sources/Feature/Common/SidebarTab.swift | 2 +- Mark-In/Sources/Feature/Main/MainViewModel.swift | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Mark-In/Sources/Domain/Entities/Folder.swift b/Mark-In/Sources/Domain/Entities/Folder.swift index 9028315..56f8579 100644 --- a/Mark-In/Sources/Domain/Entities/Folder.swift +++ b/Mark-In/Sources/Domain/Entities/Folder.swift @@ -7,7 +7,7 @@ import Foundation -struct Folder { +struct Folder: Equatable, Hashable { var id: String var name: String var createdBy: Date diff --git a/Mark-In/Sources/Feature/Common/SidebarTab.swift b/Mark-In/Sources/Feature/Common/SidebarTab.swift index 3aa2c60..33f5cdb 100644 --- a/Mark-In/Sources/Feature/Common/SidebarTab.swift +++ b/Mark-In/Sources/Feature/Common/SidebarTab.swift @@ -11,7 +11,7 @@ enum SidebarTab: Hashable { case total case pin case nonRead - case folder(TestFolder) + case folder(Folder) var title: String { switch self { diff --git a/Mark-In/Sources/Feature/Main/MainViewModel.swift b/Mark-In/Sources/Feature/Main/MainViewModel.swift index 6aaed15..04b6f0a 100644 --- a/Mark-In/Sources/Feature/Main/MainViewModel.swift +++ b/Mark-In/Sources/Feature/Main/MainViewModel.swift @@ -61,8 +61,4 @@ final class MainViewModel: Reducer { } } -// TODO: 이후 제거 예정 -struct TestFolder: Hashable { - var id: String - var name: String -} + From 35dd0247b51159781989e9a687438573923be4a1 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 15:53:43 +0900 Subject: [PATCH 06/12] =?UTF-8?q?[#31]=20=EC=82=AC=EC=9D=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B0=94=20=EA=B8=B0=EB=B3=B8=20=ED=83=AD,=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=20=ED=83=AD=20=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=20?= =?UTF-8?q?=EA=B5=AC=EB=B6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mark-In/Sources/Feature/Common/SidebarTab.swift | 5 ----- Mark-In/Sources/Feature/Main/MainViewModel.swift | 8 ++++++-- Mark-In/Sources/Feature/Main/SideBar.swift | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Mark-In/Sources/Feature/Common/SidebarTab.swift b/Mark-In/Sources/Feature/Common/SidebarTab.swift index 33f5cdb..38efb35 100644 --- a/Mark-In/Sources/Feature/Common/SidebarTab.swift +++ b/Mark-In/Sources/Feature/Common/SidebarTab.swift @@ -30,9 +30,4 @@ enum SidebarTab: Hashable { case .folder(_): "folder" } } - - var isFolder: Bool { - if case .folder(_) = self { true } - else { false } - } } diff --git a/Mark-In/Sources/Feature/Main/MainViewModel.swift b/Mark-In/Sources/Feature/Main/MainViewModel.swift index 04b6f0a..0a6fe7a 100644 --- a/Mark-In/Sources/Feature/Main/MainViewModel.swift +++ b/Mark-In/Sources/Feature/Main/MainViewModel.swift @@ -12,7 +12,8 @@ final class MainViewModel: Reducer { struct State { var isLoading: Bool = true - var tabs: [SidebarTab] = [.total, .pin, .nonRead] + var defaultTabs: [SidebarTab] = [.total, .pin, .nonRead] + var folderTabs: [SidebarTab] = [] var selectedTab: SidebarTab? = .total } @@ -38,7 +39,10 @@ final class MainViewModel: Reducer { } case .refresh: - (1...3).forEach { state.tabs.append(.folder(.init(id: "\($0)", name: "\($0)"))) } + // TODO: 실제 데이터 가져오는 작업 구현 필요 + (1...3).forEach { + state.folderTabs.append(.folder(.init(id: "\($0)", name: "\($0)", createdBy: .now))) + } state.isLoading = false return .none diff --git a/Mark-In/Sources/Feature/Main/SideBar.swift b/Mark-In/Sources/Feature/Main/SideBar.swift index 8d8ba3e..9a5ca25 100644 --- a/Mark-In/Sources/Feature/Main/SideBar.swift +++ b/Mark-In/Sources/Feature/Main/SideBar.swift @@ -21,7 +21,7 @@ struct SideBar: View { ) { Section("기본") { ForEach( - viewModel.state.tabs.filter { !$0.isFolder }, + viewModel.state.defaultTabs, id: \.self ) { tab in NavigationLink(value: tab) { @@ -32,7 +32,7 @@ struct SideBar: View { Section("저장된 폴더") { ForEach( - viewModel.state.tabs.filter { $0.isFolder }, + viewModel.state.folderTabs, id: \.self ) { tab in NavigationLink(value: tab) { @@ -47,7 +47,7 @@ struct SideBar: View { Divider() .padding(.horizontal, 10) - .foregroundStyle(.blue) + .foregroundStyle(.markBlack20) Button(action: { // TODO: 구현 예정 From 8235c4c95da5edb80a0ed0fb67e39b7a26060ba2 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 15:55:12 +0900 Subject: [PATCH 07/12] =?UTF-8?q?[#31]=20=ED=8F=B4=EB=8D=94=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=99=94=EB=A9=B4=20=EB=9D=84=EC=9A=B0=EA=B8=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EC=83=9D=EC=84=B1=EB=90=9C=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mark-In/Sources/Feature/Main/MainView.swift | 22 ++++++++++++++---- .../Sources/Feature/Main/MainViewModel.swift | 23 ++++++++++++++++++- Mark-In/Sources/Feature/Main/SideBar.swift | 2 +- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/Mark-In/Sources/Feature/Main/MainView.swift b/Mark-In/Sources/Feature/Main/MainView.swift index a6afaab..aec1496 100644 --- a/Mark-In/Sources/Feature/Main/MainView.swift +++ b/Mark-In/Sources/Feature/Main/MainView.swift @@ -12,7 +12,6 @@ import DesignSystem struct MainView: View { @State private var viewModel = MainViewModel() @State private var searchText: String = "" - @State private var isAddMode: Bool = false var body: some View { ZStack { @@ -43,8 +42,12 @@ struct MainView: View { .onAppear { viewModel.send(.onAppear) } - .sheet(isPresented: $isAddMode) { - AddLinkView() + .sheet(item: .init( + get: { viewModel.state.isPresentedSheet }, + set: { viewModel.send(.presentSheet($0)) + } + )) { type in + buildSheet(type) } } @@ -79,7 +82,6 @@ struct MainView: View { Spacer() Button { // TODO: 구현 예정 - isAddMode = true } label: { Image(systemName: "plus") } @@ -99,6 +101,18 @@ struct MainView: View { } } } + + @ViewBuilder + private func buildSheet(_ type: MainViewModel.SheetType) -> some View { + switch type { + case .addLink: + AddLinkView() + case .addFolder: + AddFolderView() { + viewModel.send(.didCreateFolder($0)) + } + } + } } #Preview { diff --git a/Mark-In/Sources/Feature/Main/MainViewModel.swift b/Mark-In/Sources/Feature/Main/MainViewModel.swift index 0a6fe7a..0d8d135 100644 --- a/Mark-In/Sources/Feature/Main/MainViewModel.swift +++ b/Mark-In/Sources/Feature/Main/MainViewModel.swift @@ -15,12 +15,18 @@ final class MainViewModel: Reducer { var defaultTabs: [SidebarTab] = [.total, .pin, .nonRead] var folderTabs: [SidebarTab] = [] var selectedTab: SidebarTab? = .total + + var isPresentedSheet: SheetType? } enum Action { case onAppear case refresh case changeTab(SidebarTab?) + + case presentSheet(SheetType?) + + case didCreateFolder(Folder) } private(set) var state: State = .init() @@ -49,6 +55,14 @@ final class MainViewModel: Reducer { case .changeTab(let tab): state.selectedTab = tab return .none + + case .presentSheet(let sheetType): + state.isPresentedSheet = sheetType + return .none + + case .didCreateFolder(let folder): + state.folderTabs.append(.folder(folder)) + return .none } } @@ -65,4 +79,11 @@ final class MainViewModel: Reducer { } } - +extension MainViewModel { + enum SheetType: Identifiable { + case addLink + case addFolder + + var id: String { String(describing: self) } + } +} diff --git a/Mark-In/Sources/Feature/Main/SideBar.swift b/Mark-In/Sources/Feature/Main/SideBar.swift index 9a5ca25..ce2b051 100644 --- a/Mark-In/Sources/Feature/Main/SideBar.swift +++ b/Mark-In/Sources/Feature/Main/SideBar.swift @@ -50,7 +50,7 @@ struct SideBar: View { .foregroundStyle(.markBlack20) Button(action: { - // TODO: 구현 예정 + viewModel.send(.presentSheet(.addFolder)) }, label: { Label("새로운 폴더 만들기", systemImage: "plus") .lineLimit(1) From 6977b54b2cb7f32d6973304e812ef30240aac390 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 16:13:37 +0900 Subject: [PATCH 08/12] =?UTF-8?q?[#31]=20GenerateFolderUseCase=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../GenerateFolderUseCaseImpl.swift | 27 +++++++++++++++++++ .../Interfaces/GenerateFolderUseCase.swift | 12 +++++++++ 2 files changed, 39 insertions(+) create mode 100644 Mark-In/Sources/Domain/UseCases/Implements/GenerateFolderUseCaseImpl.swift create mode 100644 Mark-In/Sources/Domain/UseCases/Interfaces/GenerateFolderUseCase.swift diff --git a/Mark-In/Sources/Domain/UseCases/Implements/GenerateFolderUseCaseImpl.swift b/Mark-In/Sources/Domain/UseCases/Implements/GenerateFolderUseCaseImpl.swift new file mode 100644 index 0000000..1299dfc --- /dev/null +++ b/Mark-In/Sources/Domain/UseCases/Implements/GenerateFolderUseCaseImpl.swift @@ -0,0 +1,27 @@ +// +// GenerateFolderUseCaseImpl.swift +// Mark-In +// +// Created by 이정동 on 5/8/25. +// + +import Foundation + +struct GenerateFolderUseCaseImpl: GenerateFolderUseCase { + + private let folderRepository: FolderRepository + + init(folderRepository: FolderRepository) { + self.folderRepository = folderRepository + } + + func execute(name: String) async throws -> Folder { + let writeFolder = WriteFolder(name: name) + + // TODO: #29번 PR 머지 후 AuthManager를 통해 현재 로그인 유저 정보 가져옴 + let user = "123" + + let newFolder = try await folderRepository.create(userID: user, folder: writeFolder) + return newFolder + } +} diff --git a/Mark-In/Sources/Domain/UseCases/Interfaces/GenerateFolderUseCase.swift b/Mark-In/Sources/Domain/UseCases/Interfaces/GenerateFolderUseCase.swift new file mode 100644 index 0000000..50def6e --- /dev/null +++ b/Mark-In/Sources/Domain/UseCases/Interfaces/GenerateFolderUseCase.swift @@ -0,0 +1,12 @@ +// +// GenerateFolderUseCase.swift +// Mark-In +// +// Created by 이정동 on 5/8/25. +// + +import Foundation + +protocol GenerateFolderUseCase { + func execute(name: String) async throws -> Folder +} From 77b9c95d564072e157c9015df777e0232362cce7 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 18:09:17 +0900 Subject: [PATCH 09/12] =?UTF-8?q?[#31]=20ViewModel=EC=97=90=20UseCase=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AddFolder/AddFolderViewModel.swift | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift index e46b063..fdacd9b 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift @@ -12,15 +12,24 @@ final class AddFolderViewModel: Reducer { struct State { var createdFolder: Folder? var isSaving: Bool = false + var isError: Bool = false } enum Action { case addLinkButtonTapped(title: String) case completeSave(Folder) + case occurError(Bool) } + private let generateFolderUseCase: GenerateFolderUseCase + private(set) var state: State = .init() + init() { + // TODO: DIContainer PR 머지 이후 DIContainer를 통해 의존성 주입 + self.generateFolderUseCase = GenerateFolderUseCaseImpl(folderRepository: FolderRepositoryImpl()) + } + func send(_ action: Action) { let effect = reduce(state: &state, action: action) handleEffect(effect) @@ -31,15 +40,24 @@ final class AddFolderViewModel: Reducer { case .addLinkButtonTapped(let title): state.isSaving = true - // TODO: 실제 저장 과정 구현 예정 return .run { - try? await Task.sleep(nanoseconds: 3_000_000_000) - return .completeSave(.init(id: "", name: title, createdBy: .now)) + do { + let result = try await self.generateFolderUseCase.execute(name: title) + return .completeSave(result) + } catch { + return .occurError(true) + } } + case .completeSave(let folder): state.isSaving = false state.createdFolder = folder return .none + + case .occurError(let bool): + state.isSaving = false + state.isError = bool + return .none } } From 2a3d67fb6a23a7fa2a48bdb3a7b45db61959e2c0 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 8 May 2025 18:09:43 +0900 Subject: [PATCH 10/12] =?UTF-8?q?[#31]=20View=EC=97=90=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Feature/AddFolder/AddFolderView.swift | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift index 5090840..d0968fc 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -14,6 +14,10 @@ struct AddFolderView: View { @State private var viewModel = AddFolderViewModel() @State private var title: String = "" + private var isSaving: Bool { + viewModel.state.isSaving + } + let completion: (Folder) -> () var body: some View { @@ -24,8 +28,15 @@ struct AddFolderView: View { TextField("", text: $title, prompt: Text("제목")) .textFieldStyle(.roundedBorder) .padding(.top, 14) + .disabled(isSaving) HStack { + if isSaving { + ProgressView() + .frame(width: 12, height: 12) + .scaleEffect(0.4, anchor: .center) + } + Button { dismiss() } label: { @@ -40,6 +51,7 @@ struct AddFolderView: View { .stroke(.markBlack10, lineWidth: 0.5) } } + .disabled(title.isEmpty || isSaving) Button { viewModel.send(.addLinkButtonTapped(title: title)) @@ -51,7 +63,7 @@ struct AddFolderView: View { .background(.markPoint) .clipShape(RoundedRectangle(cornerRadius: 6)) } - .disabled(title.isEmpty) + .disabled(title.isEmpty || isSaving) } .frame(maxWidth: .infinity, alignment: .trailing) .padding(.top, 18) @@ -60,19 +72,23 @@ struct AddFolderView: View { } .padding(20) .frame(width: 400) - .overlay(content: { - if viewModel.state.isSaving { - ProgressView() - .frame(maxWidth: .infinity, maxHeight: .infinity) - .contentShape(Rectangle()) - .background(.gray.opacity(0.5)) - } - }) .onChange(of: viewModel.state.createdFolder) { guard let folder = $1 else { return } completion(folder) dismiss() } + .alert( + "폴더 생성에 실패했습니다.", + isPresented: .init( + get: { viewModel.state.isError }, + set: { viewModel.send(.occurError($0)) } + ) + ) { + Button(role: .cancel) { + } label: { + Text("확인") + } + } } } From f5694d8d58cda635fe052357a2aabf855242a448 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 15 May 2025 13:31:53 +0900 Subject: [PATCH 11/12] =?UTF-8?q?[#31]=20isSaving=20->=20isLoading?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mark-In/Sources/Feature/AddFolder/AddFolderView.swift | 2 +- .../Sources/Feature/AddFolder/AddFolderViewModel.swift | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift index d0968fc..72f7e77 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -15,7 +15,7 @@ struct AddFolderView: View { @State private var title: String = "" private var isSaving: Bool { - viewModel.state.isSaving + viewModel.state.isLoading } let completion: (Folder) -> () diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift index fdacd9b..b595c77 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift @@ -11,7 +11,7 @@ import Foundation final class AddFolderViewModel: Reducer { struct State { var createdFolder: Folder? - var isSaving: Bool = false + var isLoading: Bool = false var isError: Bool = false } @@ -38,7 +38,7 @@ final class AddFolderViewModel: Reducer { func reduce(state: inout State, action: Action) -> Effect { switch action { case .addLinkButtonTapped(let title): - state.isSaving = true + state.isLoading = true return .run { do { @@ -50,12 +50,12 @@ final class AddFolderViewModel: Reducer { } case .completeSave(let folder): - state.isSaving = false + state.isLoading = false state.createdFolder = folder return .none case .occurError(let bool): - state.isSaving = false + state.isLoading = false state.isError = bool return .none } From e75c9e6a7d247251986e886a7bd2a62672f9dda6 Mon Sep 17 00:00:00 2001 From: Jeong Dong Date: Thu, 15 May 2025 13:44:52 +0900 Subject: [PATCH 12/12] =?UTF-8?q?[#31]=20Action=20case=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Feature/AddFolder/AddFolderView.swift | 4 ++-- .../Feature/AddFolder/AddFolderViewModel.swift | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift index 72f7e77..fdc8f66 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderView.swift @@ -54,7 +54,7 @@ struct AddFolderView: View { .disabled(title.isEmpty || isSaving) Button { - viewModel.send(.addLinkButtonTapped(title: title)) + viewModel.send(.didTapAddLinkButton(title: title)) } label: { Text("추가") .padding(.vertical, 4) @@ -81,7 +81,7 @@ struct AddFolderView: View { "폴더 생성에 실패했습니다.", isPresented: .init( get: { viewModel.state.isError }, - set: { viewModel.send(.occurError($0)) } + set: { viewModel.send(.updateErrorState($0)) } ) ) { Button(role: .cancel) { diff --git a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift index b595c77..4908601 100644 --- a/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift +++ b/Mark-In/Sources/Feature/AddFolder/AddFolderViewModel.swift @@ -16,9 +16,9 @@ final class AddFolderViewModel: Reducer { } enum Action { - case addLinkButtonTapped(title: String) - case completeSave(Folder) - case occurError(Bool) + case didTapAddLinkButton(title: String) + case didCompleteSave(Folder) + case updateErrorState(Bool) } private let generateFolderUseCase: GenerateFolderUseCase @@ -37,24 +37,24 @@ final class AddFolderViewModel: Reducer { func reduce(state: inout State, action: Action) -> Effect { switch action { - case .addLinkButtonTapped(let title): + case .didTapAddLinkButton(let title): state.isLoading = true return .run { do { let result = try await self.generateFolderUseCase.execute(name: title) - return .completeSave(result) + return .didCompleteSave(result) } catch { - return .occurError(true) + return .updateErrorState(true) } } - case .completeSave(let folder): + case .didCompleteSave(let folder): state.isLoading = false state.createdFolder = folder return .none - case .occurError(let bool): + case .updateErrorState(let bool): state.isLoading = false state.isError = bool return .none