From f8aace915a95c3d5286de24063ede7bf7246c2cb Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 6 Mar 2026 20:54:40 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EA=B8=B0=EC=A1=B4=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EC=99=80=20=EC=83=88=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=EB=A5=BC=20=EB=B9=84=EA=B5=90=ED=95=98=EC=97=AC=20dis?= =?UTF-8?q?abled=20=EB=B0=8F=20=EC=9E=90=EC=B2=B4=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=97=90=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModel/TodoEditorViewModel.swift | 35 ++++++++++++++++++- DevLog/UI/Home/TodoEditorView.swift | 33 +++++------------ 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift b/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift index 0d215c3c..55a40aed 100644 --- a/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift +++ b/DevLog/Presentation/ViewModel/TodoEditorViewModel.swift @@ -10,6 +10,27 @@ import OrderedCollections @Observable final class TodoEditorViewModel: Store { + private struct Draft: Equatable { + let title: String + let content: String + let dueDate: Date? + let tags: [String] + + init(todo: Todo) { + self.title = todo.title + self.content = todo.content + self.dueDate = todo.dueDate + self.tags = todo.tags + } + + init(state: State) { + self.title = state.title + self.content = state.content + self.dueDate = state.dueDate + self.tags = Array(state.tags) + } + } + struct State: Equatable { var title: String = "" var content: String = "" @@ -52,6 +73,16 @@ final class TodoEditorViewModel: Store { private let createdAt: Date? private let completedAt: Date? private let kind: TodoKind + private let originalDraft: Draft? + + var hasChanges: Bool { + guard let originalDraft else { return true } + return originalDraft != Draft(state: state) + } + + var isReadyToSubmit: Bool { + state.isValidToSave && hasChanges + } // 새로운 Todo 생성용 생성자 init(kind: TodoKind) { @@ -63,6 +94,7 @@ final class TodoEditorViewModel: Store { self.createdAt = nil self.completedAt = nil self.kind = kind + self.originalDraft = nil } // 기존 Todo 편집용 생성자 @@ -75,6 +107,7 @@ final class TodoEditorViewModel: Store { self.createdAt = todo.createdAt self.completedAt = todo.completedAt self.kind = todo.kind + self.originalDraft = Draft(todo: todo) state.title = todo.title state.content = todo.content state.dueDate = todo.dueDate @@ -134,7 +167,7 @@ extension TodoEditorViewModel { } } - func upsertTodo() -> Todo { + func makeTodo() -> Todo { let date = Date() return Todo( id: self.id, diff --git a/DevLog/UI/Home/TodoEditorView.swift b/DevLog/UI/Home/TodoEditorView.swift index e47e1997..1a12ee3a 100644 --- a/DevLog/UI/Home/TodoEditorView.swift +++ b/DevLog/UI/Home/TodoEditorView.swift @@ -47,14 +47,11 @@ struct TodoEditorView: View { .navigationBarTitleDisplayMode(.inline) .toolbarBackground(.background, for: .navigationBar) .toolbar { - ToolbarLeadingButton { - dismiss() - } + ToolbarLeadingButton { dismiss() } ToolbarTrailingButton { - onSubmit?(viewModel.upsertTodo()) - dismiss() + submit() } - .disabled(!viewModel.state.isValidToSave) + .disabled(!viewModel.isReadyToSubmit) } } } @@ -166,25 +163,11 @@ struct TodoEditorView: View { } } - @ToolbarContentBuilder - private var toolBar: some ToolbarContent { - ToolbarItem(placement: .topBarLeading) { - Button { - dismiss() - } label: { - Image(systemName: "xmark") - .bold() - } - } - ToolbarItem(placement: .topBarTrailing) { - Button(action: { - onSubmit?(viewModel.upsertTodo()) - dismiss() - }) { - Text("추가") - } - .disabled(!viewModel.state.isValidToSave) - } + private func submit() { + if !viewModel.isReadyToSubmit { return } + let todo = viewModel.makeTodo() + onSubmit?(todo) + dismiss() } private enum Field: Hashable { From 51c415377cfbf50e19a0bf8f939a58782d17519e Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 6 Mar 2026 21:03:18 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=EC=A4=91=EB=B3=B5=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DevLog/UI/Home/TodoEditorView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/DevLog/UI/Home/TodoEditorView.swift b/DevLog/UI/Home/TodoEditorView.swift index 1a12ee3a..72e9c4be 100644 --- a/DevLog/UI/Home/TodoEditorView.swift +++ b/DevLog/UI/Home/TodoEditorView.swift @@ -164,7 +164,6 @@ struct TodoEditorView: View { } private func submit() { - if !viewModel.isReadyToSubmit { return } let todo = viewModel.makeTodo() onSubmit?(todo) dismiss()