로그인 없이 사용하는 개인용 캘린더 다이어리 앱입니다.
날짜 단위로 기록을 남기고 사진을 함께 보관할 수 있습니다.
Calendar
Home Widget
날짜 기반 기록 앱이므로 선택 날짜 가 전 화면에서 일관되게 동기화되도록 설계
여러 진입점(일반 실행/위젯/딥링크)을 단일 내비게이션 파이프라인 으로 통합
화면 이동과 상태 변경을 순수 리듀서 로 분리해 예측 가능한 흐름 유지
계층 분리: presentation / domain / data
domain은 use case 중심 으로 의존성을 정리하고, data는 Room/DAO/Repository로 구현
Hilt로 ViewModel/Repository/DB 주입
DataStore로 위젯 커버/배경 설정 저장
Navigation 구조 (Navigation3 + Reducer)
Navigation3 기반 NavDisplay 사용
NavigationRoot 가 모든 이벤트를 받아 reducer(reduceMainNav)로 상태를 계산
reducer는 NavigationState와 NavEffect를 분리해 상태와 부수효과를 분리
딥링크 진입 시 백스택을 Calendar → Diary로 재구성하여 뒤로가기 동작을 일관되게 보장
일반 실행: MainActivity → NavigationRoot
위젯 클릭: 위젯 날짜 → start_date → 딥링크 변환 → NavigationRoot
딥링크: app://picday.co/diary/{yyyy-MM-dd} 형식으로 처리
동일 딥링크 반복 호출에도 동작하도록 timestamp를 덧붙여 이벤트를 강제 갱신
화면 상태는 ViewModel의 StateFlow로 관리
선택 날짜는 SharedViewModel에서 전역 공유
내비게이션 상태는 reducer가 단일 소스로 관리
CalendarWidgetProvider + RemoteViewsService 구성
월 상태는 SharedPreferences에 저장, 월 변경 시 데이터 갱신
데이터는 Room DB 에서 직접 조회, 커버 사진은 DataStore 우선 적용
썸네일 로딩은 Coil 사용 (allowHardware(false)로 RemoteViews 호환)
PicDay
├── presentation/ # UI 및 상태 관리 계층
│ ├── navigation/ # 내비게이션 로직 및 그래프
│ │ ├── MainNavGraph.kt
│ │ └── NavigationRoot.kt
│ ├── calendar/ # 캘린더 화면
│ │ ├── CalendarScreen.kt
│ │ ├── CalendarUiState.kt
│ │ └── CalendarViewModel.kt
│ ├── diary/ # 일기 목록 화면
│ │ ├── DiaryScreen.kt
│ │ ├── DiaryUiState.kt
│ │ └── DiaryViewModel.kt
│ ├── write/ # 일기 작성/수정 화면
│ │ ├── WriteScreen.kt
│ │ ├── WriteUiState.kt
│ │ └── WriteViewModel.kt
│ ├── main/ # 메인 화면 및 공통 UI
│ │ ├── MainScreen.kt
│ │ └── MainNavReducer.kt
│ ├── component/ # 재사용 가능한 공통 UI 컴포넌트
│ │ ├── DiaryItemCard.kt
│ │ └── WriteTopBar.kt
│ └── common/ # 여러 화면에서 공유하는 ViewModel
│ └── SharedViewModel.kt
│
├── domain/ # 핵심 비즈니스 로직 계층
│ ├── usecase/ # 비즈니스 로직 (UseCase)
│ │ ├── calendar/
│ │ │ └── GetDiariesUseCase.kt
│ │ ├── diary/
│ │ │ ├── AddDiaryUseCase.kt
│ │ │ ├── DeleteDiaryUseCase.kt
│ │ │ └── UpdateDiaryUseCase.kt
│ │ └── settings/
│ │ └── GetSettingsUseCase.kt
│ ├── repository/ # 리포지토리 인터페이스
│ │ ├── DiaryRepository.kt
│ │ └── SettingsRepository.kt
│ ├── model/ # 순수 비즈니스 모델
│ │ ├── Diary.kt
│ │ ├── DiaryCoverPhoto.kt
│ │ └── DiaryPhoto.kt
│ └── updater/ # 외부 알림 인터페이스
│ └── CalendarWidgetUpdater.kt
│
├── data/ # 데이터 소스 및 처리 계층
│ ├── diary/
│ │ ├── repository/
│ │ │ └── DiaryRepositoryImpl.kt
│ │ ├── dao/
│ │ │ └── DiaryDao.kt
│ │ ├── entity/
│ │ │ ├── DiaryEntity.kt
│ │ │ └── DiaryPhotoEntity.kt
│ │ └── database/
│ │ └── DiaryDatabase.kt
│ ├── repository/
│ │ └── SettingsRepositoryImpl.kt
│ ├── di/ # Hilt 의존성 주입
│ │ ├── DiaryModule.kt
│ │ ├── SettingsModule.kt
│ │ └── WidgetModule.kt
│ └── widget/ # 앱 위젯
│ ├── CalendarWidgetProvider.kt
│ ├── CalendarWidgetUpdaterImpl.kt
│ └── CalendarRemoteViewsFactory.kt
항목
값
언어
Kotlin
UI
Jetpack Compose
Navigation
Navigation3
DB
Room
설정 저장
DataStore
이미지 로딩
Coil
DI
Hilt
minSdk
24
targetSdk
36
Java
11
편집 모드 사진 diff 처리 로직 정리
썸네일 캐싱/리사이징 파이프라인 개선
Room 마이그레이션 전략 정의
작성/편집 오류 처리 및 빈 상태 UX 보강