From f22aea0f950604adcaf09c380a94f1dfac9f220a Mon Sep 17 00:00:00 2001 From: songyc macbook Date: Tue, 14 Jul 2026 00:17:42 +0900 Subject: [PATCH] feat(onboarding): actionable empty state on the main tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 첫 실행의 빈 모음 탭이 안내 문구뿐이던 것을 개선: - 도메인 개념 한 줄 소개 + '첫 행동 만들기'(행동 추가 시트 직행) - '예시 행동으로 시작해 보기' — 즉시 써 볼 수 있는 예시 세트 (꼬리표 생활·건강 + 독서/운동/물 마시기) 생성. 행동 추가와 같은 경로(LocalPrefs 배치 등록 + DataChange.commit)를 쓰며 언제든 수정·삭제 가능 깨끗한 설치 상태 스크린샷으로 확인. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_013yKDMhuF39GVYy3FMcGHh7 --- myApp/HaruDanim/IOS/Views/MainView.swift | 52 +++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/myApp/HaruDanim/IOS/Views/MainView.swift b/myApp/HaruDanim/IOS/Views/MainView.swift index 0a00cc2..e5754ed 100644 --- a/myApp/HaruDanim/IOS/Views/MainView.swift +++ b/myApp/HaruDanim/IOS/Views/MainView.swift @@ -43,6 +43,7 @@ struct MainView: View { #endif }() @State private var draggingAction: Action? + @State private var showingAddAction = false @State private var settingsEditingAction: Action? @State private var recordsAction: Action? @State private var deletingAction: Action? @@ -94,6 +95,9 @@ struct MainView: View { .sheet(item: $settingsEditingAction) { action in ActionEditorView(action: action) } + .sheet(isPresented: $showingAddAction) { + ActionEditorView(action: nil) + } .sheet(item: $recordsAction) { action in ActionRecordsSheet(action: action, startWithAdd: true) } @@ -348,14 +352,60 @@ struct MainView: View { .foregroundStyle(.tertiary) Text("아직 등록된 행동이 없어요") .font(.headline) - Text("행동 탭에서 추적할 행동을 추가해 보세요.") + Text("습관이나 할 일을 '행동'으로 등록하면\n버튼 한 번으로 시간과 횟수를 기록할 수 있어요.") .font(.subheadline) .foregroundStyle(.secondary) + .multilineTextAlignment(.center) + VStack(spacing: 10) { + Button { + showingAddAction = true + } label: { + Label("첫 행동 만들기", systemImage: "plus") + .padding(.horizontal, 10) + } + .buttonStyle(.borderedProminent) + .buttonBorderShape(.capsule) + .tint(AppTheme.green) + Button { + createStarterPack() + } label: { + Text("예시 행동으로 시작해 보기") + .font(.subheadline) + } + .tint(AppTheme.green) + } + .padding(.top, 8) } .frame(maxWidth: .infinity) .padding(.vertical, 60) } + /// 빈 상태에서 바로 써 볼 수 있는 예시 세트 (실사용 가능한 구성 — 언제든 수정·삭제 가능) + private func createStarterPack() { + guard actions.isEmpty else { return } + let life = Tag(name: String(localized: "생활"), colorHex: "#2F6B4F") + let health = Tag(name: String(localized: "건강"), colorHex: "#4A7A9D") + life.sortOrder = 0 + health.sortOrder = 1 + context.insert(life) + context.insert(health) + + let reading = Action(name: String(localized: "독서"), symbolName: "book.fill", + trackingType: .time, sortOrder: 0) + reading.tags = [life] + let workout = Action(name: String(localized: "운동"), symbolName: "figure.run", + trackingType: .time, sortOrder: 1) + workout.tags = [health] + let water = Action(name: String(localized: "물 마시기"), symbolName: "drop.fill", + trackingType: .count, sortOrder: 2) + water.tags = [health] + for action in [reading, workout, water] { + context.insert(action) + LocalPrefs.appendActionToOrder(action.uuid) + } + DataChange.commit(context: context) + } + // MARK: 동작 private func handleTap(_ action: Action) {