From 64476548d1b66ed89f8e2f300cd5b2cc5f106dbd Mon Sep 17 00:00:00 2001 From: taetae98coding Date: Mon, 25 Nov 2024 22:28:12 +0900 Subject: [PATCH] 1.2.2 feat: app - TagDetail TagMemo Tab feat: app - preferred width 500 --- .github/workflows/build.yml | 36 +- .github/workflows/check_code_style.yml | 6 +- .github/workflows/dependency_guard.yml | 6 +- .../workflows/firebase_app_distribution.yml | 52 +-- .github/workflows/test.yml | 51 +++ Diary/Diary.xcodeproj/project.pbxproj | 22 +- Diary/ExportOptions.plist | 4 +- .../datastore/AccountDataStorePreferences.kt | 4 +- .../database/room/dao/MemoBackupRoomDao.kt | 4 +- .../database/room/dao/TagBackupRoomDao.kt | 4 +- .../diary/core/calendar/compose/Calendar.kt | 28 +- .../calendar/compose/color/CalendarColors.kt | 9 +- .../compose/day/CalendarDayOfMonth.kt | 6 +- .../compose/day/CalendarDayOfMonthState.kt | 7 +- .../compose/item/CalendarItemUiState.kt | 14 +- .../compose/month/CalendarMonthState.kt | 5 +- .../calendar/compose/state/CalendarState.kt | 4 +- .../calendar/compose/topbar/CalendarTopBar.kt | 3 +- .../core/calendar/compose/topbar/TodayIcon.kt | 3 +- .../compose/week/CalendarItemVerticalGrid.kt | 3 +- .../compose/week/CalendarWeekState.kt | 6 +- .../core/calendar/compose/week/WeekItem.kt | 17 +- .../core/calendar/compose/week/WeekItemRow.kt | 9 +- .../core/compose/runtime/SkipProperty.kt | 4 +- .../compose/swipe/FinishAndDeleteSwipeBox.kt | 6 +- .../core/design/system/color/DiaryColor.kt | 8 +- .../design/system/color/DiaryColorPicker.kt | 3 +- .../system/color/DiaryColorPickerDialog.kt | 3 +- .../system/color/DiaryColorPickerState.kt | 4 +- .../system/diary/color/DiaryColorState.kt | 4 +- .../system/diary/component/DiaryComponent.kt | 6 +- .../diary/component/DiaryComponentState.kt | 15 +- .../design/system/diary/date/DiaryDate.kt | 3 +- .../system/diary/date/DiaryDateState.kt | 5 +- .../core/design/system/dimen/DiaryDimen.kt | 8 +- .../core/design/system/theme/DiaryTheme.kt | 6 +- .../system/typography/DiaryTypography.kt | 10 +- .../diary/database/room/dao/MemoRoomDao.kt | 5 +- .../diary/database/room/dao/MemoTagRoomDao.kt | 4 +- .../diary/database/room/dao/TagEntityDao.kt | 37 +- .../diary/database/room/dao/TagRoomDao.kt | 94 ++-- .../diary/database/room/mapper/MemoMapper.kt | 14 +- .../diary/database/room/mapper/TagMapper.kt | 10 +- .../diary/core/diary/database/TagDao.kt | 5 +- .../room/dao/CalendarFilterRoomDao.kt | 4 +- .../room/entity/CalendarFilterEntity.kt | 5 +- .../holiday/database/room/HolidayRoomDao.kt | 4 +- .../datastore/HolidayDataStorePreferences.kt | 5 +- .../core/holiday/service/HolidayService.kt | 5 +- .../diary/core/model/account/Account.kt | 5 +- .../diary/core/model/account/AccountToken.kt | 5 +- .../diary/core/model/holiday/Holiday.kt | 6 +- .../diary/core/model/memo/Memo.kt | 10 +- .../diary/core/model/memo/MemoAndTagIds.kt | 5 +- .../diary/core/model/memo/MemoDetail.kt | 8 +- .../diary/core/model/memo/MemoDto.kt | 11 +- .../diary/core/model/tag/Tag.kt | 9 +- .../diary/core/model/tag/TagDetail.kt | 6 +- .../diary/core/model/tag/TagDto.kt | 10 +- .../navigation/memo/MemoAddDestination.kt | 12 +- .../repository/AccountRepositoryImpl.kt | 4 +- .../repository/MemoBackupRepositoryImpl.kt | 6 +- .../repository/TagBackupRepositoryImpl.kt | 6 +- .../repository/CalendarRepositoryImpl.kt | 4 +- .../repository/CredentialRepositoryImpl.kt | 5 +- .../data/fcm/repository/FCMRepositoryImpl.kt | 5 +- .../repository/MemoFetchRepositoryImpl.kt | 5 +- .../repository/TagFetchRepositoryImpl.kt | 5 +- .../repository/HolidayRepositoryImpl.kt | 6 +- .../memo/repository/MemoRepositoryImpl.kt | 4 +- .../memo/repository/MemoTagRepositoryImpl.kt | 4 +- .../data/tag/repository/TagRepositoryImpl.kt | 65 +-- .../account/usecase/GetAccountUseCase.kt | 4 +- .../domain/account/GetAccountUseCaseTest.kt | 56 +++ .../domain/backup/usecase/BackupUseCase.kt | 6 +- .../usecase/PushMemoBackupQueueUseCase.kt | 7 +- .../usecase/PushTagBackupQueueUseCase.kt | 7 +- .../diary/domain/backup/BackupUseCaseTest.kt | 77 ++++ .../backup/PushMemoBackupQueueUseCaseTest.kt | 122 +++++ .../backup/PushTagBackupQueueUseCaseTest.kt | 118 +++++ .../calendar/entity/CalendarTagFilter.kt | 5 +- .../usecase/DeleteCalendarTagUseCase.kt | 9 +- .../usecase/FindCalendarFilterTagUseCase.kt | 57 --- .../usecase/FindCalendarMemoUseCase.kt | 26 +- .../FindCalendarSelectedTagFilterUseCase.kt | 34 ++ .../usecase/FindCalendarTagFilterUseCase.kt | 49 ++ .../usecase/HasCalendarFilterUseCase.kt | 12 +- .../usecase/UpsertCalendarTagUseCase.kt | 5 +- .../calendar/DeleteCalendarTagUseCaseTest.kt | 78 ++++ .../calendar/FindCalendarMemoUseCaseTest.kt | 114 +++++ ...indCalendarSelectedTagFilterUseCaseTest.kt | 69 +++ .../domain/credential/usecase/JoinUseCase.kt | 4 +- .../domain/credential/usecase/LoginUseCase.kt | 7 +- .../credential/usecase/LogoutUseCase.kt | 6 +- .../fcm/usecase/UpdateFCMTokenUseCase.kt | 5 +- .../domain/fetch/usecase/FetchUseCase.kt | 7 +- .../holiday/usecase/FindHolidayUseCase.kt | 4 +- .../diary/domain/memo/entity/MemoTag.kt | 6 +- .../domain/memo/usecase/AddMemoUseCase.kt | 11 +- .../usecase/DeleteMemoPrimaryTagUseCase.kt | 5 +- .../domain/memo/usecase/DeleteMemoUseCase.kt | 5 +- .../domain/memo/usecase/FindMemoTagUseCase.kt | 7 +- .../domain/memo/usecase/FindMemoUseCase.kt | 4 +- .../domain/memo/usecase/FinishMemoUseCase.kt | 5 +- .../domain/memo/usecase/RestartMemoUseCase.kt | 5 +- .../domain/memo/usecase/RestoreMemoUseCase.kt | 20 + .../memo/usecase/SelectMemoTagUseCase.kt | 5 +- .../memo/usecase/UnselectMemoTagUseCase.kt | 7 +- .../usecase/UpdateMemoPrimaryTagUseCase.kt | 5 +- .../domain/memo/usecase/UpdateMemoUseCase.kt | 5 +- .../domain/tag/repository/TagRepository.kt | 5 +- .../diary/domain/tag/usecase/AddTagUseCase.kt | 11 +- .../domain/tag/usecase/DeleteTagUseCase.kt | 5 +- .../domain/tag/usecase/FindTagUseCase.kt | 4 +- .../domain/tag/usecase/FinishTagUseCase.kt | 5 +- .../domain/tag/usecase/PageTagMemoUseCase.kt | 26 ++ .../domain/tag/usecase/PageTagUseCase.kt | 5 +- .../domain/tag/usecase/RestartTagUseCase.kt | 5 +- .../domain/tag/usecase/RestoreTagUseCase.kt | 5 +- .../domain/tag/usecase/UpdateTagUseCase.kt | 5 +- .../feature/account/common/BottomBarButton.kt | 3 +- .../diary/feature/account/join/JoinScreen.kt | 3 +- .../feature/account/join/JoinViewModel.kt | 5 +- .../account/join/state/JoinScreenState.kt | 4 +- .../feature/account/join/state/JoinUiState.kt | 9 +- .../feature/account/login/LoginScreen.kt | 3 +- .../feature/account/login/LoginViewModel.kt | 4 +- .../account/login/state/LoginScreenState.kt | 4 +- .../account/login/state/LoginUiState.kt | 9 +- .../feature/calendar/CalendarNavigation.kt | 44 +- .../calendar/filter/CalendarFilterDialog.kt | 9 +- .../filter/CalendarFilterTagViewModel.kt | 10 +- .../feature/calendar/filter/TagUiState.kt | 8 +- .../home/CalendarHomeHolidayViewModel.kt | 4 +- .../calendar/home/CalendarHomeScreen.kt | 3 +- .../calendar/home/CalendarHomeScreenState.kt | 4 +- .../calendar/home/CalendarHomeViewModel.kt | 5 +- .../diary/feature/calendar/home/MemoKey.kt | 4 +- .../diary/feature/memo/MemoNavigation.kt | 53 ++- .../diary/feature/memo/add/MemoAddRoute.kt | 2 +- .../feature/memo/add/MemoAddViewModel.kt | 8 +- .../memo/detail/MemoDetailActionButton.kt | 6 +- .../memo/detail/MemoDetailFloatingButton.kt | 4 +- .../memo/detail/MemoDetailNavigationButton.kt | 4 +- .../feature/memo/detail/MemoDetailRoute.kt | 3 +- .../feature/memo/detail/MemoDetailScreen.kt | 15 +- .../memo/detail/MemoDetailScreenState.kt | 16 +- .../memo/detail/MemoDetailScreenUiState.kt | 10 +- .../memo/detail/MemoDetailViewModel.kt | 12 +- .../RememberMemoDetailScreenDetailState.kt | 1 + .../memo/tag/MemoTagNavigationButton.kt | 4 +- .../diary/feature/memo/tag/MemoTagScreen.kt | 15 +- .../diary/feature/memo/tag/TagFlow.kt | 3 +- .../diary/feature/memo/tag/TagUiState.kt | 9 +- .../diary/feature/more/MoreScreen.kt | 6 +- .../diary/feature/more/account/MoreAccount.kt | 6 +- .../more/account/state/MoreAccountUiState.kt | 5 +- .../more/viewmodel/MoreAccountViewModel.kt | 5 +- app/feature/tag/build.gradle.kts | 1 + .../tag/detail/TagDetailScreenPreview.kt | 1 + .../feature/tag/memo/TagMemoScreenPreview.kt | 68 +++ .../diary/feature/tag/TagNavigate.kt | 4 +- .../diary/feature/tag/TagNavigation.kt | 52 ++- .../diary/feature/tag/TagRoute.kt | 425 ++++++++++-------- .../diary/feature/tag/add/TagAddRoute.kt | 3 +- .../diary/feature/tag/add/TagAddViewModel.kt | 4 +- .../RememberTagDetailScreenDetailState.kt | 2 + .../tag/detail/TagDetailActionButton.kt | 6 +- .../tag/detail/TagDetailFloatingButton.kt | 4 +- .../tag/detail/TagDetailNavigationButton.kt | 4 +- .../feature/tag/detail/TagDetailRoute.kt | 114 +++-- .../feature/tag/detail/TagDetailScreen.kt | 31 +- .../tag/detail/TagDetailScreenState.kt | 17 +- .../tag/detail/TagDetailScreenUiState.kt | 10 +- .../feature/tag/detail/TagDetailViewModel.kt | 10 +- .../feature/tag/list/TagListFloatingButton.kt | 4 +- .../feature/tag/list/TagListItemUiState.kt | 7 +- .../diary/feature/tag/list/TagListScreen.kt | 277 ++++++------ .../feature/tag/list/TagListScreenState.kt | 4 +- .../feature/tag/list/TagListScreenUiState.kt | 9 +- .../feature/tag/list/TagListViewModel.kt | 20 +- .../feature/tag/memo/MemoListItemUiState.kt | 12 + .../tag/memo/RememberTagMemoScreenState.kt | 14 + .../feature/tag/memo/TagMemoNavigateButton.kt | 9 + .../diary/feature/tag/memo/TagMemoScreen.kt | 207 +++++++++ .../feature/tag/memo/TagMemoScreenState.kt | 45 ++ .../feature/tag/memo/TagMemoScreenUiState.kt | 12 + .../feature/tag/memo/TagMemoViewModel.kt | 114 +++++ app/platform/android/build.gradle.kts | 4 +- .../DefaultNotificationManager.kt | 6 +- .../io/github/taetae98coding/diary/app/App.kt | 9 +- .../diary/app/manager/BackupManager.kt | 4 +- .../diary/app/manager/FCMManager.kt | 4 +- .../diary/app/manager/FetchManager.kt | 4 +- .../diary/app/navigation/AppNavigation.kt | 5 +- .../diary/app/state/AppState.kt | 4 +- app/platform/jvm/build.gradle.kts | 2 +- .../plugin/convention/AppDomainPlugin.kt | 4 + .../kotlin/plugin/kotest/KotestJvmPlugin.kt | 41 ++ build.gradle.kts | 1 + .../diary/common/exception/ApiException.kt | 5 +- .../common/exception/NetworkException.kt | 5 +- .../account/AccountNotFoundException.kt | 5 +- .../exception/account/ExistEmailException.kt | 5 +- .../account/InvalidEmailException.kt | 5 +- .../exception/memo/MemoTitleBlankException.kt | 5 +- .../common/model/response/DiaryResponse.kt | 6 +- gradle/libs.versions.toml | 18 + .../diary/library/coroutines/FlowExt.kt | 2 +- .../koin/datastore/DataStoreExt.jvm.kt | 2 +- .../diary/library/koin/room/RoomExt.jvm.kt | 2 +- .../diary/plugin/ContentNegotiationPlugin.kt | 6 +- .../diary/core/model/Account.kt | 6 +- .../taetae98coding/diary/core/model/Memo.kt | 14 +- .../diary/core/model/MemoAndTagIds.kt | 5 +- .../taetae98coding/diary/core/model/Tag.kt | 11 +- .../account/usecase/FindAccountUseCase.kt | 5 +- .../account/usecase/HashingPasswordUseCase.kt | 2 +- .../domain/account/usecase/JoinUseCase.kt | 7 +- .../fcm/usecase/DeleteFCMTokenUseCase.kt | 4 +- .../fcm/usecase/UpsertFCMTokenUseCase.kt | 4 +- .../domain/memo/usecase/FetchMemoUseCase.kt | 4 +- .../domain/memo/usecase/UpsertMemoUseCase.kt | 18 +- .../domain/tag/usecase/FetchTagUseCase.kt | 4 +- .../domain/tag/usecase/UpsertTagUseCase.kt | 12 +- 225 files changed, 2989 insertions(+), 913 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 app/domain/account/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/account/GetAccountUseCaseTest.kt create mode 100644 app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/BackupUseCaseTest.kt create mode 100644 app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushMemoBackupQueueUseCaseTest.kt create mode 100644 app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushTagBackupQueueUseCaseTest.kt delete mode 100644 app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarFilterTagUseCase.kt create mode 100644 app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarSelectedTagFilterUseCase.kt create mode 100644 app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarTagFilterUseCase.kt create mode 100644 app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/DeleteCalendarTagUseCaseTest.kt create mode 100644 app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarMemoUseCaseTest.kt create mode 100644 app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarSelectedTagFilterUseCaseTest.kt create mode 100644 app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestoreMemoUseCase.kt create mode 100644 app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagMemoUseCase.kt create mode 100644 app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenPreview.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/MemoListItemUiState.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/RememberTagMemoScreenState.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoNavigateButton.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreen.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenState.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenUiState.kt create mode 100644 app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoViewModel.kt create mode 100644 build-logic/src/main/kotlin/plugin/kotest/KotestJvmPlugin.kt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbfbf9ae..c9422715 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: Build -on: [ pull_request ] +on: + pull_request: + push: + branches: + - main jobs: Linux-Build: @@ -8,8 +12,8 @@ jobs: strategy: matrix: command: [ - './gradlew :app:platform:jvm:assemble', - './gradlew :app:platform:android:assembleRealRelease', + './gradlew :app:platform:jvm:packageReleaseDistributionForCurrentOS', + './gradlew :app:platform:android:bundleRealRelease', ] steps: - name: Checkout repository @@ -83,35 +87,35 @@ jobs: echo '${{ secrets.APPLE_REAL_DEBUG_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealDebug/GoogleService-Info.plist echo '${{ secrets.APPLE_REAL_RELEASE_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealRelease/GoogleService-Info.plist - - name: Install the build certificate and provisioning profile + - name: Install the build Apple certificate and build provisioning profile env: - BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_BUILD_CERTIFICATE }} - BUILD_P12_PASSWORD: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }} - BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_BUILD_PROFILE }} - KEYCHAIN_PASSWORD: ${{ secrets.APPLE_TEMPORARY_KEYCHAIN_PASSWORD }} + CERTIFICATE_BASE64: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.APPLE_BUILD_P12_PASSWORD }} + PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_BUILD_PROVISION_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.APPLE_BUILD_KEYCHAIN_PASSWORD }} run: | # create variables - BUILD_CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 - BUILD_PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision KEYCHAIN_PATH=$RUNNER_TEMP/build_app-signing.keychain-db # import certificate and provisioning profile from secrets - echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $BUILD_CERTIFICATE_PATH - echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $BUILD_PP_PATH + echo -n "$CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH # create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - # import build certificate to keychain - security import $BUILD_CERTIFICATE_PATH -P "$BUILD_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + # apply provisioning profile mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - cp $BUILD_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles - name: Build Cocoapods run: ./gradlew buildCocoapods diff --git a/.github/workflows/check_code_style.yml b/.github/workflows/check_code_style.yml index 304533d1..e129e136 100644 --- a/.github/workflows/check_code_style.yml +++ b/.github/workflows/check_code_style.yml @@ -1,6 +1,10 @@ name: Check Code Style -on: [ pull_request ] +on: + pull_request: + push: + branches: + - main jobs: Spotless: diff --git a/.github/workflows/dependency_guard.yml b/.github/workflows/dependency_guard.yml index f8d9d26e..4c7dbb92 100644 --- a/.github/workflows/dependency_guard.yml +++ b/.github/workflows/dependency_guard.yml @@ -1,6 +1,10 @@ name: Dependency Guard -on: [ pull_request ] +on: + pull_request: + push: + branches: + - main jobs: Dependency-Guard: diff --git a/.github/workflows/firebase_app_distribution.yml b/.github/workflows/firebase_app_distribution.yml index bc4b6fad..202b850c 100644 --- a/.github/workflows/firebase_app_distribution.yml +++ b/.github/workflows/firebase_app_distribution.yml @@ -91,35 +91,35 @@ jobs: echo '${{ secrets.APPLE_REAL_DEBUG_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealDebug/GoogleService-Info.plist echo '${{ secrets.APPLE_REAL_RELEASE_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealRelease/GoogleService-Info.plist - - name: Install the build certificate and provisioning profile + - name: Install the build Apple certificate and build provisioning profile env: - BUILD_CERTIFICATE_BASE64: ${{ secrets.APPLE_BUILD_CERTIFICATE }} - BUILD_P12_PASSWORD: ${{ secrets.APPLE_BUILD_CERTIFICATE_PASSWORD }} - BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_BUILD_PROFILE }} - KEYCHAIN_PASSWORD: ${{ secrets.APPLE_TEMPORARY_KEYCHAIN_PASSWORD }} + CERTIFICATE_BASE64: ${{ secrets.APPLE_BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.APPLE_BUILD_P12_PASSWORD }} + PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_BUILD_PROVISION_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.APPLE_BUILD_KEYCHAIN_PASSWORD }} run: | # create variables - BUILD_CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 - BUILD_PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + PP_PATH=$RUNNER_TEMP/build_pp.mobileprovision KEYCHAIN_PATH=$RUNNER_TEMP/build_app-signing.keychain-db # import certificate and provisioning profile from secrets - echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $BUILD_CERTIFICATE_PATH - echo -n "$BUILD_PROVISION_PROFILE_BASE64" | base64 --decode -o $BUILD_PP_PATH + echo -n "$CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH # create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - # import build certificate to keychain - security import $BUILD_CERTIFICATE_PATH -P "$BUILD_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + # apply provisioning profile mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - cp $BUILD_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles - name: Build Cocoapods run: ./gradlew buildCocoapods @@ -127,35 +127,35 @@ jobs: - name: Archive xcarchive run: xcodebuild -project Diary/Diary.xcodeproj -scheme RealRelease archive -archivePath Diary/build/Diary.xcarchive -allowProvisioningUpdates - - name: Install the export certificate and provisioning profile + - name: Install the export Apple certificate and export provisioning profile env: - EXPORT_CERTIFICATE_BASE64: ${{ secrets.APPLE_EXPORT_CERTIFICATE }} - EXPORT_P12_PASSWORD: ${{ secrets.APPLE_EXPORT_CERTIFICATE_PASSWORD }} - EXPORT_PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_EXPORT_PROFILE }} - KEYCHAIN_PASSWORD: ${{ secrets.APPLE_TEMPORARY_KEYCHAIN_PASSWORD }} + CERTIFICATE_BASE64: ${{ secrets.APPLE_EXPORT_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.APPLE_EXPORT_P12_PASSWORD }} + PROVISION_PROFILE_BASE64: ${{ secrets.APPLE_EXPORT_PROVISION_PROFILE_BASE64 }} + KEYCHAIN_PASSWORD: ${{ secrets.APPLE_EXPORT_KEYCHAIN_PASSWORD }} run: | # create variables - EXPORT_CERTIFICATE_PATH=$RUNNER_TEMP/export_certificate.p12 - EXPORT_PP_PATH=$RUNNER_TEMP/export_pp.mobileprovision + CERTIFICATE_PATH=$RUNNER_TEMP/export_certificate.p12 + PP_PATH=$RUNNER_TEMP/export_pp.mobileprovision KEYCHAIN_PATH=$RUNNER_TEMP/export_app-signing.keychain-db # import certificate and provisioning profile from secrets - echo -n "$EXPORT_CERTIFICATE_BASE64" | base64 --decode -o $EXPORT_CERTIFICATE_PATH - echo -n "$EXPORT_PROVISION_PROFILE_BASE64" | base64 --decode -o $EXPORT_PP_PATH + echo -n "$CERTIFICATE_BASE64" | base64 --decode -o $CERTIFICATE_PATH + echo -n "$PROVISION_PROFILE_BASE64" | base64 --decode -o $PP_PATH # create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - # import build certificate to keychain - security import $EXPORT_CERTIFICATE_PATH -P "$EXPORT_P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + # import certificate to keychain + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + # apply provisioning profile mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - cp $EXPORT_PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles + cp $PP_PATH ~/Library/MobileDevice/Provisioning\ Profiles - name: Export ipa run: xcodebuild -exportArchive -archivePath Diary/build/Diary.xcarchive -exportPath Diary/build -exportOptionsPlist Diary/ExportOptions.plist -allowProvisioningUpdates diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..b6e50905 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,51 @@ +name: Test + +on: + pull_request: + push: + branches: + - main + +jobs: + Linux-Build: + runs-on: ubuntu-latest + strategy: + matrix: + command: [ + './gradlew jvmTest', + ] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: CI setup + uses: './.github/actions/ci-setup' + + - name: Set local.properties + run: | + echo diary.dev.api.base.url=${{ secrets.DIARY_DEV_API_BASE_URL }} >> local.properties + echo diary.real.api.base.url=${{ secrets.DIARY_REAL_API_BASE_URL }} >> local.properties + echo holiday.dev.api.url=${{ secrets.HOLIDAY_DEV_API_URL }} >> local.properties + echo holiday.dev.api.key=${{ secrets.HOLIDAY_DEV_API_KEY }} >> local.properties + echo holiday.real.api.url=${{ secrets.HOLIDAY_REAL_API_URL }} >> local.properties + echo holiday.real.api.key=${{ secrets.HOLIDAY_REAL_API_KEY }} >> local.properties + echo android.dev.store.password=${{ secrets.ANDROID_DEV_STORE_PASSWORD }} >> local.properties + echo android.dev.key.alias=${{ secrets.ANDROID_DEV_KEY_ALIAS }} >> local.properties + echo android.dev.key.password=${{ secrets.ANDROID_DEV_KEY_PASSWORD }} >> local.properties + echo android.real.store.password=${{ secrets.ANDROID_REAL_STORE_PASSWORD }} >> local.properties + echo android.real.key.alias=${{ secrets.ANDROID_REAL_KEY_ALIAS }} >> local.properties + echo android.real.key.password=${{ secrets.ANDROID_REAL_KEY_PASSWORD }} >> local.properties + + - name: Set Android google-services.json + run: | + echo '${{ secrets.ANDROID_DEV_GOOGLE_SERVICES_JSON }}' >> app/platform/android/src/dev/google-services.json + echo '${{ secrets.ANDROID_REAL_GOOGLE_SERVICES_JSON }}' >> app/platform/android/src/real/google-services.json + + - name: Set Apple GoogleService-Info.plist + run: | + echo '${{ secrets.APPLE_DEV_DEBUG_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/DevDebug/GoogleService-Info.plist + echo '${{ secrets.APPLE_DEV_RELEASE_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/DevRelease/GoogleService-Info.plist + echo '${{ secrets.APPLE_REAL_DEBUG_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealDebug/GoogleService-Info.plist + echo '${{ secrets.APPLE_REAL_RELEASE_GOOGLE_SERVICE_INFO_PLIST }}' >> Diary/Secret/RealRelease/GoogleService-Info.plist + - name: Build ${{ matrix.command }} + run: ${{ matrix.command }} \ No newline at end of file diff --git a/Diary/Diary.xcodeproj/project.pbxproj b/Diary/Diary.xcodeproj/project.pbxproj index aec03382..ef308e00 100644 --- a/Diary/Diary.xcodeproj/project.pbxproj +++ b/Diary/Diary.xcodeproj/project.pbxproj @@ -272,10 +272,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Diary/Diary.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Diary/Preview Content\""; - DEVELOPMENT_TEAM = 4TV6L66XZ8; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -292,7 +292,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = io.github.taetae98coding.diary.debug; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -388,11 +388,11 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = io.github.taetae98coding.diary; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = RealReleaseBuild; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = DiaryBuild; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -470,10 +470,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Diary/Diary.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Diary/Preview Content\""; - DEVELOPMENT_TEAM = 4TV6L66XZ8; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -490,7 +490,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = io.github.taetae98coding.diary.dev.debug; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -564,10 +564,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = Diary/Diary.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_ASSET_PATHS = "\"Diary/Preview Content\""; - DEVELOPMENT_TEAM = 4TV6L66XZ8; + DEVELOPMENT_TEAM = ""; ENABLE_PREVIEWS = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -584,7 +584,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.1; + MARKETING_VERSION = 1.2.2; PRODUCT_BUNDLE_IDENTIFIER = io.github.taetae98coding.diary.dev; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; diff --git a/Diary/ExportOptions.plist b/Diary/ExportOptions.plist index 05fe0a40..51502ea9 100644 --- a/Diary/ExportOptions.plist +++ b/Diary/ExportOptions.plist @@ -9,10 +9,10 @@ provisioningProfiles io.github.taetae98coding.diary - DiaryRealReleaseAdHoc + DiaryExport signingCertificate - FB549459D90CDC28F248EDA3AE6246EB856E77F9 + 68893A355C74683A1B64C16C2D460AA4AC8C2B94 signingStyle manual stripSwiftSymbols diff --git a/app/core/account-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/account/preferences/datastore/AccountDataStorePreferences.kt b/app/core/account-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/account/preferences/datastore/AccountDataStorePreferences.kt index 48c5cb8a..c669ff29 100644 --- a/app/core/account-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/account/preferences/datastore/AccountDataStorePreferences.kt +++ b/app/core/account-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/account/preferences/datastore/AccountDataStorePreferences.kt @@ -10,7 +10,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.mapLatest @OptIn(ExperimentalCoroutinesApi::class) -internal class AccountDataStorePreferences(private val dataStore: DataStore) : AccountPreferences { +internal class AccountDataStorePreferences( + private val dataStore: DataStore, +) : AccountPreferences { override suspend fun save(email: String, uid: String, token: String) { dataStore.edit { it[stringPreferencesKey(EMAIL)] = email diff --git a/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/MemoBackupRoomDao.kt b/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/MemoBackupRoomDao.kt index 68bd7c9d..970bbda3 100644 --- a/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/MemoBackupRoomDao.kt +++ b/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/MemoBackupRoomDao.kt @@ -7,7 +7,9 @@ import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory @Factory -internal class MemoBackupRoomDao(private val database: BackupDatabase) : MemoBackupDao { +internal class MemoBackupRoomDao( + private val database: BackupDatabase, +) : MemoBackupDao { override suspend fun upsert(uid: String, id: String) { database.memo().upsert(MemoBackupEntity(memoId = id, uid = uid)) } diff --git a/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/TagBackupRoomDao.kt b/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/TagBackupRoomDao.kt index c57b538c..063a044e 100644 --- a/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/TagBackupRoomDao.kt +++ b/app/core/backup-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/backup/database/room/dao/TagBackupRoomDao.kt @@ -7,7 +7,9 @@ import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory @Factory -internal class TagBackupRoomDao(private val database: BackupDatabase) : TagBackupDao { +internal class TagBackupRoomDao( + private val database: BackupDatabase, +) : TagBackupDao { override suspend fun upsert(uid: String, id: String) { database.tag().upsert(TagBackupEntity(tagId = id, uid = uid)) } diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/Calendar.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/Calendar.kt index fd48d077..726dcbb8 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/Calendar.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/Calendar.kt @@ -39,22 +39,22 @@ public fun Calendar( val coroutineScope = rememberCoroutineScope() Surface( - modifier = modifier.onPreviewKeyEvent { - when { - !state.pagerState.isScrollInProgress && it.key == Key.DirectionRight -> { - coroutineScope.launch { state.animateScrollToForward() } - true - } + modifier = modifier + .onPreviewKeyEvent { + when { + !state.pagerState.isScrollInProgress && it.key == Key.DirectionRight -> { + coroutineScope.launch { state.animateScrollToForward() } + true + } - !state.pagerState.isScrollInProgress && it.key == Key.DirectionLeft -> { - coroutineScope.launch { state.animateScrollToBackward() } - true - } + !state.pagerState.isScrollInProgress && it.key == Key.DirectionLeft -> { + coroutineScope.launch { state.animateScrollToBackward() } + true + } - else -> false - } - } - .focusRequester(state.focusRequester) + else -> false + } + }.focusRequester(state.focusRequester) .focusable(), color = DiaryTheme.color.background, ) { diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/color/CalendarColors.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/color/CalendarColors.kt index 38be6659..91ff5d59 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/color/CalendarColors.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/color/CalendarColors.kt @@ -2,4 +2,11 @@ package io.github.taetae98coding.diary.core.calendar.compose.color import androidx.compose.ui.graphics.Color -public data class CalendarColors(val sundayColor: Color, val saturdayColor: Color, val dayColor: Color, val primaryColor: Color, val onPrimaryColor: Color, val selectColor: Color) +public data class CalendarColors( + val sundayColor: Color, + val saturdayColor: Color, + val dayColor: Color, + val primaryColor: Color, + val onPrimaryColor: Color, + val selectColor: Color, +) diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonth.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonth.kt index 2ada4e0d..33b8b72c 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonth.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonth.kt @@ -53,11 +53,13 @@ internal fun CalendarDayOfMonth( ) } val size = with(LocalDensity.current) { - DiaryTheme.typography.labelMedium.fontSize.toDp() + 16.dp + DiaryTheme.typography.labelMedium.fontSize + .toDp() + 16.dp } Box( - modifier = Modifier.size(size) + modifier = Modifier + .size(size) .run { if (isPrimary) { background(color = colors.primaryColor, shape = CircleShape) diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonthState.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonthState.kt index 207e5c9a..c4c6ca26 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonthState.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/day/CalendarDayOfMonthState.kt @@ -5,7 +5,12 @@ import kotlinx.datetime.DayOfWeek import kotlinx.datetime.LocalDate import kotlinx.datetime.Month -internal class CalendarDayOfMonthState(val year: Int, val month: Month, val weekOfMonth: Int, val dayOfWeek: DayOfWeek) { +internal class CalendarDayOfMonthState( + val year: Int, + val month: Month, + val weekOfMonth: Int, + val dayOfWeek: DayOfWeek, +) { val localDate = LocalDate(year, month, weekOfMonth, dayOfWeek) val isInMonth = year == localDate.year && month == localDate.month } diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/item/CalendarItemUiState.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/item/CalendarItemUiState.kt index a309185f..373161dc 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/item/CalendarItemUiState.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/item/CalendarItemUiState.kt @@ -8,11 +8,21 @@ public sealed class CalendarItemUiState : public abstract val key: Any public abstract val text: String - public data class Holiday(override val text: String, override val start: LocalDate, override val endInclusive: LocalDate) : CalendarItemUiState() { + public data class Holiday( + override val text: String, + override val start: LocalDate, + override val endInclusive: LocalDate, + ) : CalendarItemUiState() { override val key: String = "$text($start~$endInclusive)" } - public data class Text(override val key: Any, override val text: String, val color: Int, override val start: LocalDate, override val endInclusive: LocalDate) : CalendarItemUiState() + public data class Text( + override val key: Any, + override val text: String, + val color: Int, + override val start: LocalDate, + override val endInclusive: LocalDate, + ) : CalendarItemUiState() override fun compareTo(other: CalendarItemUiState): Int { if (start != other.start) { diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/month/CalendarMonthState.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/month/CalendarMonthState.kt index 016b22a7..e252ac29 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/month/CalendarMonthState.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/month/CalendarMonthState.kt @@ -6,7 +6,10 @@ import androidx.compose.runtime.setValue import kotlinx.datetime.LocalDate import kotlinx.datetime.Month -internal class CalendarMonthState(val year: Int, val month: Month) { +internal class CalendarMonthState( + val year: Int, + val month: Month, +) { var selectedDateRange: ClosedRange? by mutableStateOf(null) private set diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/state/CalendarState.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/state/CalendarState.kt index 2a4e2257..f2080665 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/state/CalendarState.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/state/CalendarState.kt @@ -10,7 +10,9 @@ import kotlinx.datetime.LocalDate import kotlinx.datetime.Month import kotlinx.datetime.plus -public class CalendarState internal constructor(internal val pagerState: PagerState) { +public class CalendarState internal constructor( + internal val pagerState: PagerState, +) { internal val focusRequester = FocusRequester() internal val localDate: LocalDate diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/CalendarTopBar.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/CalendarTopBar.kt index 84f20573..499ec995 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/CalendarTopBar.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/CalendarTopBar.kt @@ -39,7 +39,8 @@ public fun CalendarTopBar( var isDialogVisible by rememberSaveable { mutableStateOf(false) } Row( - modifier = Modifier.clip(CircleShape) + modifier = Modifier + .clip(CircleShape) .clickable { isDialogVisible = true } .padding(horizontal = 8.dp, vertical = 4.dp) .padding(start = 8.dp), diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/TodayIcon.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/TodayIcon.kt index 8b32a5d8..b15fd1e4 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/TodayIcon.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/topbar/TodayIcon.kt @@ -25,7 +25,8 @@ public fun TodayIcon( modifier: Modifier = Modifier, ) { Box( - modifier = modifier.size(24.dp) + modifier = modifier + .size(24.dp) .border( width = 1.dp, color = LocalContentColor.current, diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarItemVerticalGrid.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarItemVerticalGrid.kt index 80e6e9b3..f21ce0ee 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarItemVerticalGrid.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarItemVerticalGrid.kt @@ -33,7 +33,8 @@ internal fun CalendarItemVerticalGrid( addAll(textItemListProvider()) }.filter { it.isOverlap(state.dateRange) - }.sorted().toMutableList() + }.sorted() + .toMutableList() buildList { while (itemList.isNotEmpty()) { diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarWeekState.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarWeekState.kt index 07673114..fee273f1 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarWeekState.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/CalendarWeekState.kt @@ -9,7 +9,11 @@ import kotlinx.datetime.DayOfWeek import kotlinx.datetime.LocalDate import kotlinx.datetime.Month -internal class CalendarWeekState(val year: Int, val month: Month, val weekOfMonth: Int) { +internal class CalendarWeekState( + val year: Int, + val month: Month, + val weekOfMonth: Int, +) { val dateRange = LocalDate(year, month, weekOfMonth, DayOfWeek.SUNDAY)..LocalDate(year, month, weekOfMonth, DayOfWeek.SATURDAY) var selectedDateRange: ClosedRange? by mutableStateOf(null) diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItem.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItem.kt index 2983e197..ebddef7b 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItem.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItem.kt @@ -5,9 +5,20 @@ import androidx.compose.ui.graphics.Color internal sealed class WeekItem { abstract val weight: Float - data class Space(override val weight: Float) : WeekItem() + data class Space( + override val weight: Float, + ) : WeekItem() - data class Holiday(val key: Any, val name: String, override val weight: Float) : WeekItem() + data class Holiday( + val key: Any, + val name: String, + override val weight: Float, + ) : WeekItem() - data class Text(val key: Any, val name: String, val color: Color, override val weight: Float) : WeekItem() + data class Text( + val key: Any, + val name: String, + val color: Color, + override val weight: Float, + ) : WeekItem() } diff --git a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItemRow.kt b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItemRow.kt index 3c68d558..d352fd46 100644 --- a/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItemRow.kt +++ b/app/core/calendar-compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/calendar/compose/week/WeekItemRow.kt @@ -47,7 +47,8 @@ internal fun WeekItemRow( WeekTextItem( text = it.name, color = colors.sundayColor, - modifier = Modifier.weight(it.weight) + modifier = Modifier + .weight(it.weight) .fillMaxHeight() .padding(horizontal = 1.dp) .clip(RoundedCornerShape(4.dp)), @@ -60,7 +61,8 @@ internal fun WeekItemRow( WeekTextItem( text = it.name, color = it.color, - modifier = Modifier.weight(it.weight) + modifier = Modifier + .weight(it.weight) .fillMaxHeight() .padding(horizontal = 1.dp) .clip(RoundedCornerShape(4.dp)) @@ -85,7 +87,8 @@ private fun WeekTextItem( ) { Text( text = text, - modifier = Modifier.basicMarquee(iterations = Int.MAX_VALUE) + modifier = Modifier + .basicMarquee(iterations = Int.MAX_VALUE) .padding(2.dp), color = color.toContrastColor(), textAlign = TextAlign.Center, diff --git a/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/runtime/SkipProperty.kt b/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/runtime/SkipProperty.kt index 75765ce4..a917ed00 100644 --- a/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/runtime/SkipProperty.kt +++ b/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/runtime/SkipProperty.kt @@ -3,7 +3,9 @@ package io.github.taetae98coding.diary.core.compose.runtime import androidx.compose.runtime.Immutable @Immutable -public class SkipProperty(public val value: T) { +public class SkipProperty( + public val value: T, +) { override fun equals(other: Any?): Boolean = true override fun hashCode(): Int = 0 diff --git a/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/swipe/FinishAndDeleteSwipeBox.kt b/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/swipe/FinishAndDeleteSwipeBox.kt index ae3ecd27..8a49690a 100644 --- a/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/swipe/FinishAndDeleteSwipeBox.kt +++ b/app/core/compose/src/commonMain/kotlin/io/github/taetae98coding/diary/core/compose/swipe/FinishAndDeleteSwipeBox.kt @@ -53,7 +53,8 @@ public fun FinishAndDeleteSwipeBox( ) Box( - modifier = Modifier.align(Alignment.CenterStart) + modifier = Modifier + .align(Alignment.CenterStart) .padding(horizontal = 4.dp) .graphicsLayer { scaleX = scale @@ -68,7 +69,8 @@ public fun FinishAndDeleteSwipeBox( } Box( - modifier = Modifier.align(Alignment.CenterEnd) + modifier = Modifier + .align(Alignment.CenterEnd) .padding(horizontal = 4.dp) .graphicsLayer { scaleX = scale diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColor.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColor.kt index 033aa7e3..5225f4b2 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColor.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColor.kt @@ -2,4 +2,10 @@ package io.github.taetae98coding.diary.core.design.system.color import androidx.compose.ui.graphics.Color -public data class DiaryColor(val primary: Color, val onPrimary: Color, val secondary: Color, val background: Color, val onSurface: Color) +public data class DiaryColor( + val primary: Color, + val onPrimary: Color, + val secondary: Color, + val background: Color, + val onSurface: Color, +) diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPicker.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPicker.kt index 88efa534..168effc3 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPicker.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPicker.kt @@ -36,7 +36,8 @@ public fun DiaryColorPicker( ColorBox( state = state, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .height(200.dp), ) diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerDialog.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerDialog.kt index 7d21d2b6..7acc3bce 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerDialog.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerDialog.kt @@ -39,7 +39,8 @@ public fun DiaryColorPickerDialog( DiaryColorPicker(state = state) Row( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .padding(horizontal = 6.dp), horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.End), ) { diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerState.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerState.kt index b1c2615f..92ac5878 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerState.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/color/DiaryColorPickerState.kt @@ -10,7 +10,9 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import io.github.taetae98coding.diary.library.color.randomArgb -public class DiaryColorPickerState internal constructor(initialColor: Color) { +public class DiaryColorPickerState internal constructor( + initialColor: Color, +) { public var color: Color by mutableStateOf(initialColor) private set diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/color/DiaryColorState.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/color/DiaryColorState.kt index 2ca545aa..d5f98c9d 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/color/DiaryColorState.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/color/DiaryColorState.kt @@ -8,7 +8,9 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb -public class DiaryColorState(initialColor: Color) { +public class DiaryColorState( + initialColor: Color, +) { public var color: Color by mutableStateOf(initialColor) private set diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponent.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponent.kt index 8837d3bf..81c956d3 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponent.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponent.kt @@ -33,7 +33,8 @@ public fun DiaryComponent( ClearTextField( valueProvider = { state.title }, onValueChange = state::onTitleChange, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .focusRequester(state.titleFocusRequester), label = { Text(text = "제목") }, errorProvider = { state.isTitleError }, @@ -95,7 +96,8 @@ private fun DescriptionPager( 1 -> { Column( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .verticalScroll(rememberScrollState()) .padding(DiaryTheme.dimen.diaryPaddingValues), ) { diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponentState.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponentState.kt index 7850f2c3..05bdc55c 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponentState.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/component/DiaryComponentState.kt @@ -8,7 +8,10 @@ import androidx.compose.runtime.saveable.listSaver import androidx.compose.runtime.setValue import androidx.compose.ui.focus.FocusRequester -public class DiaryComponentState internal constructor(initialTitle: String, initialDescription: String) { +public class DiaryComponentState internal constructor( + initialTitle: String, + initialDescription: String, +) { internal var isTitleError by mutableStateOf(false) private set public var title: String by mutableStateOf(initialTitle) @@ -19,11 +22,11 @@ public class DiaryComponentState internal constructor(initialTitle: String, init internal val pagerState = PagerState( currentPage = - if (initialDescription.isBlank()) { - 0 - } else { - 1 - }, + if (initialDescription.isBlank()) { + 0 + } else { + 1 + }, ) { 2 } diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDate.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDate.kt index f9dcc6e3..1cafb19d 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDate.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDate.kt @@ -56,7 +56,8 @@ private fun Title( modifier: Modifier = Modifier, ) { Row( - modifier = Modifier.toggleable(value = state.hasDate, onValueChange = state::onHasDateChange) + modifier = Modifier + .toggleable(value = state.hasDate, onValueChange = state::onHasDateChange) .then(modifier), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDateState.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDateState.kt index e45a3cad..fe504658 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDateState.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/diary/date/DiaryDateState.kt @@ -8,7 +8,10 @@ import androidx.compose.runtime.setValue import io.github.taetae98coding.diary.library.datetime.todayIn import kotlinx.datetime.LocalDate -public class DiaryDateState internal constructor(initialStart: LocalDate?, initialEndInclusive: LocalDate?) : ClosedRange { +public class DiaryDateState internal constructor( + initialStart: LocalDate?, + initialEndInclusive: LocalDate?, +) : ClosedRange { public var hasDate: Boolean by mutableStateOf(initialStart != null && initialEndInclusive != null) private set override var start: LocalDate by mutableStateOf(initialStart ?: LocalDate.todayIn()) diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/dimen/DiaryDimen.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/dimen/DiaryDimen.kt index e792ddfe..28ab1f23 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/dimen/DiaryDimen.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/dimen/DiaryDimen.kt @@ -4,7 +4,13 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -public data class DiaryDimen(val screenHorizontalPadding: Dp = 12.dp, val screenVerticalPadding: Dp = 12.dp, val diaryHorizontalPadding: Dp = 16.dp, val diaryVerticalPadding: Dp = 8.dp, val itemSpace: Dp = 4.dp) { +public data class DiaryDimen( + val screenHorizontalPadding: Dp = 12.dp, + val screenVerticalPadding: Dp = 12.dp, + val diaryHorizontalPadding: Dp = 16.dp, + val diaryVerticalPadding: Dp = 8.dp, + val itemSpace: Dp = 4.dp, +) { val screenPaddingValues: PaddingValues = PaddingValues( horizontal = screenHorizontalPadding, diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/theme/DiaryTheme.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/theme/DiaryTheme.kt index 6252f15f..5b46bd65 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/theme/DiaryTheme.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/theme/DiaryTheme.kt @@ -44,9 +44,11 @@ public fun DiaryTheme( ), LocalDiaryTypography provides DiaryTypography( headlineMedium = MaterialTheme.typography.headlineMedium, - labelSmall = MaterialTheme.typography.labelSmall, - labelMedium = MaterialTheme.typography.labelMedium, + titleLarge = MaterialTheme.typography.titleLarge, + titleMedium = MaterialTheme.typography.titleMedium, labelLarge = MaterialTheme.typography.labelLarge, + labelMedium = MaterialTheme.typography.labelMedium, + labelSmall = MaterialTheme.typography.labelSmall, bodySmall = MaterialTheme.typography.bodySmall, ), LocalDiaryDimen provides DiaryDimen(), diff --git a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/typography/DiaryTypography.kt b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/typography/DiaryTypography.kt index 27748793..8ade938e 100644 --- a/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/typography/DiaryTypography.kt +++ b/app/core/design-system/src/commonMain/kotlin/io/github/taetae98coding/diary/core/design/system/typography/DiaryTypography.kt @@ -2,4 +2,12 @@ package io.github.taetae98coding.diary.core.design.system.typography import androidx.compose.ui.text.TextStyle -public data class DiaryTypography(val headlineMedium: TextStyle, val labelSmall: TextStyle, val labelMedium: TextStyle, val labelLarge: TextStyle, val bodySmall: TextStyle) +public data class DiaryTypography( + val headlineMedium: TextStyle, + val titleLarge: TextStyle, + val titleMedium: TextStyle, + val labelLarge: TextStyle, + val labelMedium: TextStyle, + val labelSmall: TextStyle, + val bodySmall: TextStyle, +) diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoRoomDao.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoRoomDao.kt index f0cd5bc7..d4d672b3 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoRoomDao.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoRoomDao.kt @@ -18,7 +18,10 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class MemoRoomDao(private val clock: Clock, private val database: DiaryDatabase) : MemoDao { +internal class MemoRoomDao( + private val clock: Clock, + private val database: DiaryDatabase, +) : MemoDao { override suspend fun upsert(dto: MemoAndTagIds) { database.memo().upsertMemoAndTagIds(dto) } diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoTagRoomDao.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoTagRoomDao.kt index 71485865..06557a79 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoTagRoomDao.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/MemoTagRoomDao.kt @@ -10,7 +10,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class MemoTagRoomDao(private val database: DiaryDatabase) : MemoTagDao { +internal class MemoTagRoomDao( + private val database: DiaryDatabase, +) : MemoTagDao { override fun findTagIdsByMemoId(memoId: String): Flow> = database .memoTag() diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagEntityDao.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagEntityDao.kt index 028d595a..e1cfbc91 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagEntityDao.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagEntityDao.kt @@ -2,6 +2,7 @@ package io.github.taetae98coding.diary.core.diary.database.room.dao import androidx.room.Dao import androidx.room.Query +import io.github.taetae98coding.diary.core.diary.database.room.entity.MemoEntity import io.github.taetae98coding.diary.core.diary.database.room.entity.TagEntity import io.github.taetae98coding.diary.library.room.dao.EntityDao import kotlinx.coroutines.flow.Flow @@ -50,6 +51,18 @@ internal abstract class TagEntityDao : EntityDao() { ) abstract suspend fun updateDelete(tagId: String, isDelete: Boolean, updateAt: Instant) + @Query( + """ + SELECT * + FROM TagEntity + WHERE isDelete = 0 + AND isFinish = 0 + AND (owner = :owner OR (owner IS NULL AND :owner IS NULL)) + ORDER BY title + """, + ) + abstract fun page(owner: String?): Flow> + @Query( """ SELECT * @@ -70,17 +83,19 @@ internal abstract class TagEntityDao : EntityDao() { ) abstract fun findByIds(tagIds: Set, filterNotDelete: Boolean): Flow> - @Query( - """ - SELECT * - FROM TagEntity - WHERE isDelete = 0 - AND isFinish = 0 - AND (owner = :owner OR (owner IS NULL AND :owner IS NULL)) - ORDER BY title - """, - ) - abstract fun page(owner: String?): Flow> + @Query(""" + SELECT * + FROM MemoEntity + WHERE isDelete = 0 + AND isFinish = 0 + AND id IN ( + SELECT memoId + FROM MemoTagEntity + WHERE tagId = :tagId + ) + ORDER BY title + """) + abstract fun findMemoByTagId(tagId: String): Flow> @Query("SELECT MAX(serverUpdateAt) FROM TagEntity WHERE owner = :owner") abstract fun getLastUpdateAt(owner: String?): Flow diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagRoomDao.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagRoomDao.kt index 11a40461..4d41ba16 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagRoomDao.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/dao/TagRoomDao.kt @@ -2,9 +2,11 @@ package io.github.taetae98coding.diary.core.diary.database.room.dao import io.github.taetae98coding.diary.core.diary.database.TagDao import io.github.taetae98coding.diary.core.diary.database.room.DiaryDatabase +import io.github.taetae98coding.diary.core.diary.database.room.entity.MemoEntity import io.github.taetae98coding.diary.core.diary.database.room.entity.TagEntity import io.github.taetae98coding.diary.core.diary.database.room.mapper.toDto import io.github.taetae98coding.diary.core.diary.database.room.mapper.toEntity +import io.github.taetae98coding.diary.core.model.memo.MemoDto import io.github.taetae98coding.diary.core.model.tag.TagDetail import io.github.taetae98coding.diary.core.model.tag.TagDto import io.github.taetae98coding.diary.library.coroutines.mapCollectionLatest @@ -17,46 +19,54 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class TagRoomDao(private val clock: Clock, private val database: DiaryDatabase) : TagDao { - override suspend fun upsert(tag: TagDto) { - database.tag().upsert(tag.toEntity()) - } - - override suspend fun upsert(tagList: List) { - database.tag().upsert(tagList.map(TagDto::toEntity)) - } - - override suspend fun update(tagId: String, detail: TagDetail) { - database.tag().update( - tagId = tagId, - title = detail.title, - description = detail.description, - color = detail.color, - updateAt = clock.now(), - ) - } - - override suspend fun updateFinish(tagId: String, isFinish: Boolean) { - database.tag().updateFinish(tagId, isFinish, clock.now()) - } - - override suspend fun updateDelete(tagId: String, isDelete: Boolean) { - database.tag().updateDelete(tagId, isDelete, clock.now()) - } - - override fun find(tagId: String, filterNotDelete: Boolean): Flow = database.tag().find(tagId, filterNotDelete).mapLatest { it?.toDto() } - - override fun findByIds(tagIds: Set, filterNotDelete: Boolean): Flow> = - database - .tag() - .findByIds(tagIds, filterNotDelete) - .mapCollectionLatest(TagEntity::toDto) - - override fun page(owner: String?): Flow> = - database - .tag() - .page(owner) - .mapCollectionLatest(TagEntity::toDto) - - override fun getLastServerUpdateAt(owner: String?): Flow = database.tag().getLastUpdateAt(owner) +internal class TagRoomDao( + private val clock: Clock, + private val database: DiaryDatabase, +) : TagDao { + override suspend fun upsert(tag: TagDto) { + database.tag().upsert(tag.toEntity()) + } + + override suspend fun upsert(tagList: List) { + database.tag().upsert(tagList.map(TagDto::toEntity)) + } + + override suspend fun update(tagId: String, detail: TagDetail) { + database.tag().update( + tagId = tagId, + title = detail.title, + description = detail.description, + color = detail.color, + updateAt = clock.now(), + ) + } + + override suspend fun updateFinish(tagId: String, isFinish: Boolean) { + database.tag().updateFinish(tagId, isFinish, clock.now()) + } + + override suspend fun updateDelete(tagId: String, isDelete: Boolean) { + database.tag().updateDelete(tagId, isDelete, clock.now()) + } + + override fun page(owner: String?): Flow> = + database + .tag() + .page(owner) + .mapCollectionLatest(TagEntity::toDto) + + override fun find(tagId: String, filterNotDelete: Boolean): Flow = database.tag().find(tagId, filterNotDelete).mapLatest { it?.toDto() } + + override fun findByIds(tagIds: Set, filterNotDelete: Boolean): Flow> = + database + .tag() + .findByIds(tagIds, filterNotDelete) + .mapCollectionLatest(TagEntity::toDto) + + override fun findMemoByTagId(tagId: String): Flow> { + return database.tag().findMemoByTagId(tagId) + .mapCollectionLatest(MemoEntity::toDto) + } + + override fun getLastServerUpdateAt(owner: String?): Flow = database.tag().getLastUpdateAt(owner) } diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/MemoMapper.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/MemoMapper.kt index 611723a9..a8972059 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/MemoMapper.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/MemoMapper.kt @@ -24,13 +24,13 @@ internal fun MemoEntity.toDto(): MemoDto = MemoDto( id = id, detail = - MemoDetail( - title = title, - description = description, - start = start, - endInclusive = endInclusive, - color = color, - ), + MemoDetail( + title = title, + description = description, + start = start, + endInclusive = endInclusive, + color = color, + ), owner = owner, primaryTag = primaryTag, isFinish = isFinish, diff --git a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/TagMapper.kt b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/TagMapper.kt index c7102241..0600bcf1 100644 --- a/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/TagMapper.kt +++ b/app/core/diary-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/room/mapper/TagMapper.kt @@ -21,11 +21,11 @@ internal fun TagEntity.toDto(): TagDto = TagDto( id = id, detail = - TagDetail( - title = title, - description = description, - color = color, - ), + TagDetail( + title = title, + description = description, + color = color, + ), owner = owner, isFinish = isFinish, isDelete = isDelete, diff --git a/app/core/diary-database/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/TagDao.kt b/app/core/diary-database/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/TagDao.kt index fa0da69d..bcc546bb 100644 --- a/app/core/diary-database/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/TagDao.kt +++ b/app/core/diary-database/src/commonMain/kotlin/io/github/taetae98coding/diary/core/diary/database/TagDao.kt @@ -1,5 +1,6 @@ package io.github.taetae98coding.diary.core.diary.database +import io.github.taetae98coding.diary.core.model.memo.MemoDto import io.github.taetae98coding.diary.core.model.tag.TagDetail import io.github.taetae98coding.diary.core.model.tag.TagDto import kotlinx.coroutines.flow.Flow @@ -16,11 +17,13 @@ public interface TagDao { public suspend fun updateDelete(tagId: String, isDelete: Boolean) + public fun page(owner: String?): Flow> + public fun find(tagId: String, filterNotDelete: Boolean): Flow public fun findByIds(tagIds: Set, filterNotDelete: Boolean): Flow> - public fun page(owner: String?): Flow> + public fun findMemoByTagId(tagId: String): Flow> public fun getLastServerUpdateAt(owner: String?): Flow } diff --git a/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/dao/CalendarFilterRoomDao.kt b/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/dao/CalendarFilterRoomDao.kt index 989bcf92..7dc0fd70 100644 --- a/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/dao/CalendarFilterRoomDao.kt +++ b/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/dao/CalendarFilterRoomDao.kt @@ -10,7 +10,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class CalendarFilterRoomDao(private val database: FilterDatabase) : CalendarFilterDao { +internal class CalendarFilterRoomDao( + private val database: FilterDatabase, +) : CalendarFilterDao { override suspend fun upsert(uid: String?, tagId: String) { database.calendar().upsert(CalendarFilterEntity(uid.orEmpty(), tagId)) } diff --git a/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/entity/CalendarFilterEntity.kt b/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/entity/CalendarFilterEntity.kt index aec4af29..c002fe0e 100644 --- a/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/entity/CalendarFilterEntity.kt +++ b/app/core/filter-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/filter/database/room/entity/CalendarFilterEntity.kt @@ -5,4 +5,7 @@ import androidx.room.Entity @Entity( primaryKeys = ["uid", "tagId"], ) -internal data class CalendarFilterEntity(val uid: String, val tagId: String) +internal data class CalendarFilterEntity( + val uid: String, + val tagId: String, +) diff --git a/app/core/holiday-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/database/room/HolidayRoomDao.kt b/app/core/holiday-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/database/room/HolidayRoomDao.kt index 8664e3e6..ebed1c65 100644 --- a/app/core/holiday-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/database/room/HolidayRoomDao.kt +++ b/app/core/holiday-database-room/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/database/room/HolidayRoomDao.kt @@ -9,7 +9,9 @@ import kotlinx.datetime.number import org.koin.core.annotation.Factory @Factory -internal class HolidayRoomDao(private val database: HolidayDatabase) : HolidayDao { +internal class HolidayRoomDao( + private val database: HolidayDatabase, +) : HolidayDao { override fun findHoliday(year: Int, month: Month): Flow> = database .holidayDao() diff --git a/app/core/holiday-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/preferences/datastore/HolidayDataStorePreferences.kt b/app/core/holiday-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/preferences/datastore/HolidayDataStorePreferences.kt index dee54ce2..5634b1f9 100644 --- a/app/core/holiday-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/preferences/datastore/HolidayDataStorePreferences.kt +++ b/app/core/holiday-preferences-datastore/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/preferences/datastore/HolidayDataStorePreferences.kt @@ -16,7 +16,10 @@ import kotlinx.datetime.Month import kotlinx.datetime.monthsUntil import kotlinx.datetime.number -internal class HolidayDataStorePreferences(private val clock: Clock, private val dataStore: DataStore) : HolidayPreferences { +internal class HolidayDataStorePreferences( + private val clock: Clock, + private val dataStore: DataStore, +) : HolidayPreferences { private val memoryDirtyStore = mutableMapOf, MutableStateFlow>() override fun isDirty(year: Int, month: Month): Flow { diff --git a/app/core/holiday-service/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/service/HolidayService.kt b/app/core/holiday-service/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/service/HolidayService.kt index f36e1608..cf424e02 100644 --- a/app/core/holiday-service/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/service/HolidayService.kt +++ b/app/core/holiday-service/src/commonMain/kotlin/io/github/taetae98coding/diary/core/holiday/service/HolidayService.kt @@ -16,7 +16,10 @@ import kotlinx.datetime.number import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromJsonElement -public class HolidayService internal constructor(private val client: HttpClient, private val json: Json) { +public class HolidayService internal constructor( + private val client: HttpClient, + private val json: Json, +) { public suspend fun findHoliday(year: Int, month: Month): List { val response = client.get("getRestDeInfo") { diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/Account.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/Account.kt index 8330c4f2..c0e3445f 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/Account.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/Account.kt @@ -7,5 +7,8 @@ public sealed class Account { override val uid: String? = null } - public data class Member(val email: String, override val uid: String) : Account() + public data class Member( + val email: String, + override val uid: String, + ) : Account() } diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/AccountToken.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/AccountToken.kt index 62d19e85..c2cd6187 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/AccountToken.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/account/AccountToken.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.core.model.account -public data class AccountToken(val uid: String, val token: String) +public data class AccountToken( + val uid: String, + val token: String, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/holiday/Holiday.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/holiday/Holiday.kt index 06f17b82..05965d1b 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/holiday/Holiday.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/holiday/Holiday.kt @@ -2,4 +2,8 @@ package io.github.taetae98coding.diary.core.model.holiday import kotlinx.datetime.LocalDate -public data class Holiday(val name: String, override val start: LocalDate, override val endInclusive: LocalDate) : ClosedRange +public data class Holiday( + val name: String, + override val start: LocalDate, + override val endInclusive: LocalDate, +) : ClosedRange diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/Memo.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/Memo.kt index bf233629..d1c1c2fa 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/Memo.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/Memo.kt @@ -2,4 +2,12 @@ package io.github.taetae98coding.diary.core.model.memo import kotlinx.datetime.Instant -public data class Memo(val id: String, val detail: MemoDetail, val primaryTag: String?, val owner: String?, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant) +public data class Memo( + val id: String, + val detail: MemoDetail, + val primaryTag: String?, + val owner: String?, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoAndTagIds.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoAndTagIds.kt index e87e8156..82a34e4f 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoAndTagIds.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoAndTagIds.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.core.model.memo -public data class MemoAndTagIds(val memo: MemoDto, val tagIds: Set) +public data class MemoAndTagIds( + val memo: MemoDto, + val tagIds: Set, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDetail.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDetail.kt index 4f12bbad..a89e8667 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDetail.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDetail.kt @@ -2,4 +2,10 @@ package io.github.taetae98coding.diary.core.model.memo import kotlinx.datetime.LocalDate -public data class MemoDetail(val title: String, val description: String, val start: LocalDate?, val endInclusive: LocalDate?, val color: Int) +public data class MemoDetail( + val title: String, + val description: String, + val start: LocalDate?, + val endInclusive: LocalDate?, + val color: Int, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDto.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDto.kt index cf865255..33ef40ad 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDto.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/memo/MemoDto.kt @@ -2,4 +2,13 @@ package io.github.taetae98coding.diary.core.model.memo import kotlinx.datetime.Instant -public data class MemoDto(val id: String, val detail: MemoDetail, val owner: String?, val primaryTag: String?, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant, val serverUpdateAt: Instant?) +public data class MemoDto( + val id: String, + val detail: MemoDetail, + val owner: String?, + val primaryTag: String?, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, + val serverUpdateAt: Instant?, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/Tag.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/Tag.kt index 99f03896..83fc2fe7 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/Tag.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/Tag.kt @@ -2,4 +2,11 @@ package io.github.taetae98coding.diary.core.model.tag import kotlinx.datetime.Instant -public data class Tag(val id: String, val detail: TagDetail, val owner: String?, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant) +public data class Tag( + val id: String, + val detail: TagDetail, + val owner: String?, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDetail.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDetail.kt index 2689f024..8db387c1 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDetail.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDetail.kt @@ -1,3 +1,7 @@ package io.github.taetae98coding.diary.core.model.tag -public data class TagDetail(val title: String, val description: String, val color: Int) +public data class TagDetail( + val title: String, + val description: String, + val color: Int, +) diff --git a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDto.kt b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDto.kt index 7530e4c6..94a50c2b 100644 --- a/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDto.kt +++ b/app/core/model/src/commonMain/kotlin/io/github/taetae98coding/diary/core/model/tag/TagDto.kt @@ -2,4 +2,12 @@ package io.github.taetae98coding.diary.core.model.tag import kotlinx.datetime.Instant -public data class TagDto(val id: String, val detail: TagDetail, val owner: String?, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant, val serverUpdateAt: Instant?) +public data class TagDto( + val id: String, + val detail: TagDetail, + val owner: String?, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, + val serverUpdateAt: Instant?, +) diff --git a/app/core/navigation/src/commonMain/kotlin/io/github/taetae98coding/diary/core/navigation/memo/MemoAddDestination.kt b/app/core/navigation/src/commonMain/kotlin/io/github/taetae98coding/diary/core/navigation/memo/MemoAddDestination.kt index 834e606e..0c9e75c6 100644 --- a/app/core/navigation/src/commonMain/kotlin/io/github/taetae98coding/diary/core/navigation/memo/MemoAddDestination.kt +++ b/app/core/navigation/src/commonMain/kotlin/io/github/taetae98coding/diary/core/navigation/memo/MemoAddDestination.kt @@ -6,8 +6,14 @@ import kotlinx.serialization.Serializable @Serializable public data class MemoAddDestination( - @SerialName("start") + @SerialName("start") val start: LocalDate? = null, - @SerialName("endInclusive") + @SerialName("endInclusive") val endInclusive: LocalDate? = null, -) + @SerialName(SELECTED_TAG) + val selectedTag: String? = null, +) { + public companion object { + public const val SELECTED_TAG: String = "selectedTag" + } +} diff --git a/app/data/account/src/commonMain/kotlin/io/github/taetae98coding/diary/data/account/repository/AccountRepositoryImpl.kt b/app/data/account/src/commonMain/kotlin/io/github/taetae98coding/diary/data/account/repository/AccountRepositoryImpl.kt index a35c1039..3fdea4ae 100644 --- a/app/data/account/src/commonMain/kotlin/io/github/taetae98coding/diary/data/account/repository/AccountRepositoryImpl.kt +++ b/app/data/account/src/commonMain/kotlin/io/github/taetae98coding/diary/data/account/repository/AccountRepositoryImpl.kt @@ -6,7 +6,9 @@ import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory @Factory -internal class AccountRepositoryImpl(private val preferencesDataSource: AccountPreferences) : AccountRepository { +internal class AccountRepositoryImpl( + private val preferencesDataSource: AccountPreferences, +) : AccountRepository { override fun getEmail(): Flow = preferencesDataSource.getEmail() override fun getUid(): Flow = preferencesDataSource.getUid() diff --git a/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/MemoBackupRepositoryImpl.kt b/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/MemoBackupRepositoryImpl.kt index 41c2003f..77db2f0c 100644 --- a/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/MemoBackupRepositoryImpl.kt +++ b/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/MemoBackupRepositoryImpl.kt @@ -10,7 +10,11 @@ import kotlinx.coroutines.sync.withLock import org.koin.core.annotation.Factory @Factory -internal class MemoBackupRepositoryImpl(private val memoDao: MemoDao, private val memoBackupDao: MemoBackupDao, private val memoService: MemoService) : MemoBackupRepository { +internal class MemoBackupRepositoryImpl( + private val memoDao: MemoDao, + private val memoBackupDao: MemoBackupDao, + private val memoService: MemoService, +) : MemoBackupRepository { override suspend fun backup(uid: String) { mutex.withLock { while (true) { diff --git a/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/TagBackupRepositoryImpl.kt b/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/TagBackupRepositoryImpl.kt index 3e1e1cc3..f34b76d3 100644 --- a/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/TagBackupRepositoryImpl.kt +++ b/app/data/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/data/backup/repository/TagBackupRepositoryImpl.kt @@ -10,7 +10,11 @@ import kotlinx.coroutines.sync.withLock import org.koin.core.annotation.Factory @Factory -internal class TagBackupRepositoryImpl(private val tagDao: TagDao, private val tagBackupDao: TagBackupDao, private val tagService: TagService) : TagBackupRepository { +internal class TagBackupRepositoryImpl( + private val tagDao: TagDao, + private val tagBackupDao: TagBackupDao, + private val tagService: TagService, +) : TagBackupRepository { override suspend fun backup(uid: String) { mutex.withLock { while (true) { diff --git a/app/data/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/data/calendar/repository/CalendarRepositoryImpl.kt b/app/data/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/data/calendar/repository/CalendarRepositoryImpl.kt index c98cebaa..70b4fe9f 100644 --- a/app/data/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/data/calendar/repository/CalendarRepositoryImpl.kt +++ b/app/data/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/data/calendar/repository/CalendarRepositoryImpl.kt @@ -6,7 +6,9 @@ import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory @Factory -internal class CalendarRepositoryImpl(private val localDataSource: CalendarFilterDao) : CalendarRepository { +internal class CalendarRepositoryImpl( + private val localDataSource: CalendarFilterDao, +) : CalendarRepository { override suspend fun upsert(uid: String?, tagId: String) { localDataSource.upsert(uid, tagId) } diff --git a/app/data/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/data/credential/repository/CredentialRepositoryImpl.kt b/app/data/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/data/credential/repository/CredentialRepositoryImpl.kt index 73dcbeb7..7f871154 100644 --- a/app/data/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/data/credential/repository/CredentialRepositoryImpl.kt +++ b/app/data/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/data/credential/repository/CredentialRepositoryImpl.kt @@ -9,7 +9,10 @@ import kotlinx.coroutines.flow.flow import org.koin.core.annotation.Factory @Factory -internal class CredentialRepositoryImpl(private val preferencesDataSource: AccountPreferences, private val remoteDataSource: AccountService) : CredentialRepository { +internal class CredentialRepositoryImpl( + private val preferencesDataSource: AccountPreferences, + private val remoteDataSource: AccountService, +) : CredentialRepository { override suspend fun join(email: String, password: String) { remoteDataSource.join(email, password) } diff --git a/app/data/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fcm/repository/FCMRepositoryImpl.kt b/app/data/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fcm/repository/FCMRepositoryImpl.kt index aeacbc20..65f63c10 100644 --- a/app/data/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fcm/repository/FCMRepositoryImpl.kt +++ b/app/data/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fcm/repository/FCMRepositoryImpl.kt @@ -6,7 +6,10 @@ import io.github.taetae98coding.diary.library.firebase.messaging.KFirebaseMessag import org.koin.core.annotation.Factory @Factory -internal class FCMRepositoryImpl(private val messaging: KFirebaseMessaging, private val remoteDataSource: FCMService) : FCMRepository { +internal class FCMRepositoryImpl( + private val messaging: KFirebaseMessaging, + private val remoteDataSource: FCMService, +) : FCMRepository { override suspend fun upsert() { remoteDataSource.upsert(messaging.getToken()) } diff --git a/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/MemoFetchRepositoryImpl.kt b/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/MemoFetchRepositoryImpl.kt index 2c1fbb6f..00594185 100644 --- a/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/MemoFetchRepositoryImpl.kt +++ b/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/MemoFetchRepositoryImpl.kt @@ -10,7 +10,10 @@ import kotlinx.datetime.Instant import org.koin.core.annotation.Factory @Factory -internal class MemoFetchRepositoryImpl(private val localDataSource: MemoDao, private val remoteDataSource: MemoService) : MemoFetchRepository { +internal class MemoFetchRepositoryImpl( + private val localDataSource: MemoDao, + private val remoteDataSource: MemoService, +) : MemoFetchRepository { override suspend fun fetch(uid: String) { mutex.withLock { while (true) { diff --git a/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/TagFetchRepositoryImpl.kt b/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/TagFetchRepositoryImpl.kt index cea97815..d4ad3140 100644 --- a/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/TagFetchRepositoryImpl.kt +++ b/app/data/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/data/fetch/repository/TagFetchRepositoryImpl.kt @@ -10,7 +10,10 @@ import kotlinx.datetime.Instant import org.koin.core.annotation.Factory @Factory -internal class TagFetchRepositoryImpl(private val localDataSource: TagDao, private val remoteDataSource: TagService) : TagFetchRepository { +internal class TagFetchRepositoryImpl( + private val localDataSource: TagDao, + private val remoteDataSource: TagService, +) : TagFetchRepository { override suspend fun fetch(uid: String) { mutex.withLock { while (true) { diff --git a/app/data/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/data/holiday/repository/HolidayRepositoryImpl.kt b/app/data/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/data/holiday/repository/HolidayRepositoryImpl.kt index 5c6d12c1..977c6931 100644 --- a/app/data/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/data/holiday/repository/HolidayRepositoryImpl.kt +++ b/app/data/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/data/holiday/repository/HolidayRepositoryImpl.kt @@ -30,7 +30,11 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class HolidayRepositoryImpl(private val preferencesDataSource: HolidayPreferences, private val localDataSource: HolidayDao, private val remoteDataSource: HolidayService) : HolidayRepository { +internal class HolidayRepositoryImpl( + private val preferencesDataSource: HolidayPreferences, + private val localDataSource: HolidayDao, + private val remoteDataSource: HolidayService, +) : HolidayRepository { override fun findHoliday(year: Int, month: Month): Flow> { val localDate = LocalDate(year, month, 1) val list = IntRange(-1, 1).map { localDate.plus(it, DateTimeUnit.MONTH) } diff --git a/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoRepositoryImpl.kt b/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoRepositoryImpl.kt index 308841ef..ca915e51 100644 --- a/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoRepositoryImpl.kt +++ b/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoRepositoryImpl.kt @@ -17,7 +17,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class MemoRepositoryImpl(private val localDataSource: MemoDao) : MemoRepository { +internal class MemoRepositoryImpl( + private val localDataSource: MemoDao, +) : MemoRepository { override suspend fun upsert(memo: Memo, tagIds: Set) { localDataSource.upsert(MemoAndTagIds(memo.toDto(), tagIds)) } diff --git a/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoTagRepositoryImpl.kt b/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoTagRepositoryImpl.kt index 84cf34a1..b9886e6a 100644 --- a/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoTagRepositoryImpl.kt +++ b/app/data/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/data/memo/repository/MemoTagRepositoryImpl.kt @@ -6,7 +6,9 @@ import kotlinx.coroutines.flow.Flow import org.koin.core.annotation.Factory @Factory -internal class MemoTagRepositoryImpl(private val localDataSource: MemoTagDao) : MemoTagRepository { +internal class MemoTagRepositoryImpl( + private val localDataSource: MemoTagDao, +) : MemoTagRepository { override fun findTagIdsByMemoId(memoId: String): Flow> = localDataSource.findTagIdsByMemoId(memoId) override suspend fun upsert(memoId: String, tagId: String) { diff --git a/app/data/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/data/tag/repository/TagRepositoryImpl.kt b/app/data/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/data/tag/repository/TagRepositoryImpl.kt index 6ae1f704..d0cc28ef 100644 --- a/app/data/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/data/tag/repository/TagRepositoryImpl.kt +++ b/app/data/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/data/tag/repository/TagRepositoryImpl.kt @@ -2,7 +2,10 @@ package io.github.taetae98coding.diary.data.tag.repository import io.github.taetae98coding.diary.core.diary.database.TagDao import io.github.taetae98coding.diary.core.model.mapper.toDto +import io.github.taetae98coding.diary.core.model.mapper.toMemo import io.github.taetae98coding.diary.core.model.mapper.toTag +import io.github.taetae98coding.diary.core.model.memo.Memo +import io.github.taetae98coding.diary.core.model.memo.MemoDto import io.github.taetae98coding.diary.core.model.tag.Tag import io.github.taetae98coding.diary.core.model.tag.TagDetail import io.github.taetae98coding.diary.core.model.tag.TagDto @@ -15,32 +18,38 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -internal class TagRepositoryImpl(private val localDataSource: TagDao) : TagRepository { - override suspend fun upsert(tag: Tag) { - localDataSource.upsert(tag.toDto()) - } - - override suspend fun update(tagId: String, detail: TagDetail) { - localDataSource.update(tagId, detail) - } - - override suspend fun updateDelete(tagId: String, isDelete: Boolean) { - localDataSource.updateDelete(tagId, isDelete) - } - - override suspend fun updateFinish(tagId: String, isFinish: Boolean) { - localDataSource.updateFinish(tagId, isFinish) - } - - override fun find(tagId: String): Flow = localDataSource.find(tagId, true).mapLatest { it?.toTag() } - - override fun findByIds(tagIds: Set): Flow> = - localDataSource - .findByIds(tagIds, true) - .mapCollectionLatest(TagDto::toTag) - - override fun page(owner: String?): Flow> = - localDataSource - .page(owner) - .mapCollectionLatest(TagDto::toTag) +internal class TagRepositoryImpl( + private val localDataSource: TagDao, +) : TagRepository { + override suspend fun upsert(tag: Tag) { + localDataSource.upsert(tag.toDto()) + } + + override suspend fun update(tagId: String, detail: TagDetail) { + localDataSource.update(tagId, detail) + } + + override suspend fun updateDelete(tagId: String, isDelete: Boolean) { + localDataSource.updateDelete(tagId, isDelete) + } + + override suspend fun updateFinish(tagId: String, isFinish: Boolean) { + localDataSource.updateFinish(tagId, isFinish) + } + + override fun page(owner: String?): Flow> = localDataSource + .page(owner) + .mapCollectionLatest(TagDto::toTag) + + override fun find(tagId: String): Flow = localDataSource.find(tagId, true).mapLatest { it?.toTag() } + + override fun findByIds(tagIds: Set): Flow> = + localDataSource + .findByIds(tagIds, true) + .mapCollectionLatest(TagDto::toTag) + + override fun findMemoByTagId(tagId: String): Flow> { + return localDataSource.findMemoByTagId(tagId) + .mapCollectionLatest(MemoDto::toMemo) + } } diff --git a/app/domain/account/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/account/usecase/GetAccountUseCase.kt b/app/domain/account/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/account/usecase/GetAccountUseCase.kt index 89adc4d0..5e11d2c8 100644 --- a/app/domain/account/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/account/usecase/GetAccountUseCase.kt +++ b/app/domain/account/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/account/usecase/GetAccountUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class GetAccountUseCase(private val repository: AccountRepository) { +public class GetAccountUseCase( + private val repository: AccountRepository, +) { public operator fun invoke(): Flow> = flow { combine( diff --git a/app/domain/account/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/account/GetAccountUseCaseTest.kt b/app/domain/account/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/account/GetAccountUseCaseTest.kt new file mode 100644 index 00000000..f18e1311 --- /dev/null +++ b/app/domain/account/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/account/GetAccountUseCaseTest.kt @@ -0,0 +1,56 @@ +package io.github.taetae98coding.diary.domain.account + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.domain.account.repository.AccountRepository +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.clearAllMocks +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf + +class GetAccountUseCaseTest : BehaviorSpec() { + init { + val accountRepository = mockk() + val useCase = GetAccountUseCase( + repository = accountRepository, + ) + + Given("no uid and email") { + every { accountRepository.getUid() } returns flowOf(null) + every { accountRepository.getEmail() } returns flowOf(null) + + When("call usecase") { + val result = useCase().first() + + Then("result is guest") { + result.shouldBeSuccess(mockk()) + } + } + + clearAllMocks() + } + + Given("has uid and email") { + val account = mockk { + every { uid } returns "uid" + every { email } returns "email" + } + + every { accountRepository.getUid() } returns flowOf(account.uid) + every { accountRepository.getEmail() } returns flowOf(account.email) + + When("call usecase") { + val result = useCase().first() + + Then("result is member") { + result.shouldBeSuccess(account) + } + } + + clearAllMocks() + } + } +} diff --git a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/BackupUseCase.kt b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/BackupUseCase.kt index 7c0aedd3..d4ca1ae6 100644 --- a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/BackupUseCase.kt +++ b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/BackupUseCase.kt @@ -8,7 +8,11 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class BackupUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val tagBackupRepository: TagBackupRepository, private val memoBackupRepository: MemoBackupRepository) { +public class BackupUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val tagBackupRepository: TagBackupRepository, + private val memoBackupRepository: MemoBackupRepository, +) { public suspend operator fun invoke(): Result = runCatching { val account = getAccountUseCase().first().getOrThrow() diff --git a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushMemoBackupQueueUseCase.kt b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushMemoBackupQueueUseCase.kt index abb527e8..4c529493 100644 --- a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushMemoBackupQueueUseCase.kt +++ b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushMemoBackupQueueUseCase.kt @@ -9,7 +9,12 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Factory @Factory -public class PushMemoBackupQueueUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val backupUseCase: BackupUseCase, private val coroutineScope: CoroutineScope, private val repository: MemoBackupRepository) { +public class PushMemoBackupQueueUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val backupUseCase: BackupUseCase, + private val coroutineScope: CoroutineScope, + private val repository: MemoBackupRepository, +) { public suspend operator fun invoke(memoId: String?): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushTagBackupQueueUseCase.kt b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushTagBackupQueueUseCase.kt index 5d116015..4076dc95 100644 --- a/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushTagBackupQueueUseCase.kt +++ b/app/domain/backup/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/backup/usecase/PushTagBackupQueueUseCase.kt @@ -9,7 +9,12 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Factory @Factory -public class PushTagBackupQueueUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val backupUseCase: BackupUseCase, private val coroutineScope: CoroutineScope, private val repository: TagBackupRepository) { +public class PushTagBackupQueueUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val backupUseCase: BackupUseCase, + private val coroutineScope: CoroutineScope, + private val repository: TagBackupRepository, +) { public suspend operator fun invoke(tagId: String?): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/BackupUseCaseTest.kt b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/BackupUseCaseTest.kt new file mode 100644 index 00000000..601493a2 --- /dev/null +++ b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/BackupUseCaseTest.kt @@ -0,0 +1,77 @@ +package io.github.taetae98coding.diary.domain.backup + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.backup.repository.MemoBackupRepository +import io.github.taetae98coding.diary.domain.backup.repository.TagBackupRepository +import io.github.taetae98coding.diary.domain.backup.usecase.BackupUseCase +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.Called +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf + +class BackupUseCaseTest : BehaviorSpec() { + init { + val getAccountUseCase = mockk() + val memoBackupRepository = mockk(relaxed = true, relaxUnitFun = true) + val tagBackupRepository = mockk(relaxed = true, relaxUnitFun = true) + + val useCase = BackupUseCase( + getAccountUseCase = getAccountUseCase, + memoBackupRepository = memoBackupRepository, + tagBackupRepository = tagBackupRepository, + ) + + Given("account is Guest") { + every { getAccountUseCase() } returns flowOf(Result.success(mockk())) + + When("call usecase") { + val result = useCase() + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do nothing") { + verify { + tagBackupRepository wasNot Called + memoBackupRepository wasNot Called + } + } + } + + clearAllMocks() + } + + Given("account is Member") { + val accountUid = "uid" + val account = mockk { + every { uid } returns accountUid + } + + every { getAccountUseCase() } returns flowOf(Result.success(account)) + + When("call usecase") { + val result = useCase() + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do backup") { + coVerify { + tagBackupRepository.backup(accountUid) + memoBackupRepository.backup(accountUid) + } + } + } + + clearAllMocks() + } + } +} diff --git a/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushMemoBackupQueueUseCaseTest.kt b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushMemoBackupQueueUseCaseTest.kt new file mode 100644 index 00000000..5f394bc6 --- /dev/null +++ b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushMemoBackupQueueUseCaseTest.kt @@ -0,0 +1,122 @@ +package io.github.taetae98coding.diary.domain.backup + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.backup.repository.MemoBackupRepository +import io.github.taetae98coding.diary.domain.backup.usecase.BackupUseCase +import io.github.taetae98coding.diary.domain.backup.usecase.PushMemoBackupQueueUseCase +import io.kotest.core.concurrency.CoroutineDispatcherFactory +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.core.test.TestCase +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.Called +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.withContext + +@OptIn(ExperimentalCoroutinesApi::class) +class PushMemoBackupQueueUseCaseTest : BehaviorSpec() { + init { + val dispatcher = UnconfinedTestDispatcher() + val scope = CoroutineScope(dispatcher) + + coroutineDispatcherFactory = object : CoroutineDispatcherFactory { + override suspend fun withDispatcher( + testCase: TestCase, + f: suspend () -> T, + ): T = withContext(dispatcher) { + f() + } + } + + val getAccountUseCase = mockk() + val backupUseCase = mockk(relaxed = true, relaxUnitFun = true) + val memoBackupRepository = mockk(relaxed = true, relaxUnitFun = true) + val useCase = PushMemoBackupQueueUseCase( + getAccountUseCase = getAccountUseCase, + backupUseCase = backupUseCase, + coroutineScope = scope, + repository = memoBackupRepository, + ) + + Given("memoId is null") { + val memoId = null + + When("call usecase") { + val result = useCase(memoId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do nothing") { + verify { + getAccountUseCase wasNot Called + backupUseCase wasNot Called + memoBackupRepository wasNot Called + } + } + } + + clearAllMocks() + } + + Given("memoId is not null") { + val memoId = "memoId" + + And("account is Guest") { + every { getAccountUseCase() } returns flowOf(Result.success(mockk())) + + When("call usecase") { + val result = useCase(memoId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do not backup") { + verify { + memoBackupRepository wasNot Called + backupUseCase wasNot Called + } + } + } + + clearAllMocks() + } + + And("account is Member") { + val accountUid = "uid" + val account = mockk { + every { uid } returns accountUid + } + + every { getAccountUseCase() } returns flowOf(Result.success(account)) + + When("call usecase") { + val result = useCase(memoId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do backup") { + coVerify { + memoBackupRepository.upsertBackupQueue(accountUid, memoId) + backupUseCase() + } + } + } + + clearAllMocks() + } + } + } +} diff --git a/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushTagBackupQueueUseCaseTest.kt b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushTagBackupQueueUseCaseTest.kt new file mode 100644 index 00000000..ccec6831 --- /dev/null +++ b/app/domain/backup/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/backup/PushTagBackupQueueUseCaseTest.kt @@ -0,0 +1,118 @@ +package io.github.taetae98coding.diary.domain.backup + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.backup.repository.TagBackupRepository +import io.github.taetae98coding.diary.domain.backup.usecase.BackupUseCase +import io.github.taetae98coding.diary.domain.backup.usecase.PushTagBackupQueueUseCase +import io.kotest.core.concurrency.CoroutineDispatcherFactory +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.core.test.TestCase +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.Called +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.withContext + +@OptIn(ExperimentalCoroutinesApi::class) +class PushTagBackupQueueUseCaseTest : BehaviorSpec() { + init { + val dispatcher = UnconfinedTestDispatcher() + val scope = CoroutineScope(dispatcher) + + coroutineDispatcherFactory = object : CoroutineDispatcherFactory { + override suspend fun withDispatcher(testCase: TestCase, f: suspend () -> T): T = withContext(dispatcher) { + f() + } + } + + val getAccountUseCase = mockk() + val backupUseCase = mockk(relaxed = true, relaxUnitFun = true) + val tagBackupRepository = mockk(relaxed = true, relaxUnitFun = true) + val useCase = PushTagBackupQueueUseCase( + getAccountUseCase = getAccountUseCase, + backupUseCase = backupUseCase, + coroutineScope = scope, + repository = tagBackupRepository, + ) + + Given("tagId is null") { + val tagId = null + + When("call usecase") { + val result = useCase(tagId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do nothing") { + verify { + getAccountUseCase wasNot Called + backupUseCase wasNot Called + tagBackupRepository wasNot Called + } + } + } + } + + Given("tagId is not null") { + val tagId = "tagId" + + And("account is Guest") { + every { getAccountUseCase.invoke() } returns flowOf(Result.success(mockk())) + + When("call usecase") { + val result = useCase(tagId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do not backup") { + verify { + backupUseCase wasNot Called + tagBackupRepository wasNot Called + } + } + } + + clearAllMocks() + } + + And("account is Member") { + val accountUid = "uid" + val account = mockk { + every { this@mockk.uid } returns accountUid + } + + every { getAccountUseCase.invoke() } returns flowOf(Result.success(account)) + + When("call usecase") { + val result = useCase(tagId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do backup") { + + coVerify { + tagBackupRepository.upsertBackupQueue(accountUid, tagId) + backupUseCase() + } + } + } + + clearAllMocks() + } + } + } +} diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/entity/CalendarTagFilter.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/entity/CalendarTagFilter.kt index 99791fdf..1484c42b 100644 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/entity/CalendarTagFilter.kt +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/entity/CalendarTagFilter.kt @@ -2,4 +2,7 @@ package io.github.taetae98coding.diary.domain.calendar.entity import io.github.taetae98coding.diary.core.model.tag.Tag -public data class CalendarTagFilter(val tag: Tag, val isSelected: Boolean) +public data class CalendarTagFilter( + val tag: Tag, + val isSelected: Boolean, +) diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/DeleteCalendarTagUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/DeleteCalendarTagUseCase.kt index 9073c454..fef2137f 100644 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/DeleteCalendarTagUseCase.kt +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/DeleteCalendarTagUseCase.kt @@ -6,9 +6,14 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class DeleteCalendarTagUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val repository: CalendarRepository) { - public suspend operator fun invoke(tagId: String): Result = +public class DeleteCalendarTagUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val repository: CalendarRepository, +) { + public suspend operator fun invoke(tagId: String?): Result = runCatching { + if (tagId.isNullOrBlank()) return@runCatching + val account = getAccountUseCase().first().getOrThrow() repository.delete(account.uid, tagId) } diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarFilterTagUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarFilterTagUseCase.kt deleted file mode 100644 index 81808209..00000000 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarFilterTagUseCase.kt +++ /dev/null @@ -1,57 +0,0 @@ -package io.github.taetae98coding.diary.domain.calendar.usecase - -import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase -import io.github.taetae98coding.diary.domain.calendar.entity.CalendarTagFilter -import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository -import io.github.taetae98coding.diary.domain.tag.repository.TagRepository -import io.github.taetae98coding.diary.domain.tag.usecase.PageTagUseCase -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.emitAll -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.mapLatest -import org.koin.core.annotation.Factory - -@OptIn(ExperimentalCoroutinesApi::class) -@Factory -public class FindCalendarFilterTagUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val pageTagUseCase: PageTagUseCase, private val calendarRepository: CalendarRepository, private val tagRepository: TagRepository) { - public operator fun invoke(): Flow>> = - flow { - val accountFlow = getAccountUseCase().mapLatest { it.getOrThrow() } - val pageTagFlow = pageTagUseCase().mapLatest { it.getOrThrow() } - val filterTagFlow = - accountFlow - .flatMapLatest { calendarRepository.findFilter(it.uid) } - .flatMapLatest { tagRepository.findByIds(it) } - - combine( - pageTagFlow, - filterTagFlow, - ) { pageTag, filterTag -> - val filterTagIds = filterTag.map { it.id }.toSet() - - buildList { - addAll(pageTag) - addAll(filterTag) - }.distinctBy { - it.id - }.sortedBy { - it.detail.title - }.map { - CalendarTagFilter( - tag = it, - isSelected = filterTagIds.contains(it.id), - ) - } - }.also { - emitAll(it) - } - }.mapLatest { - Result.success(it) - }.catch { - emit(Result.failure(it)) - } -} diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarMemoUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarMemoUseCase.kt index 10f2c005..87c3e9ad 100644 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarMemoUseCase.kt +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarMemoUseCase.kt @@ -2,7 +2,6 @@ package io.github.taetae98coding.diary.domain.calendar.usecase import io.github.taetae98coding.diary.core.model.memo.Memo import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase -import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -18,19 +17,22 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FindCalendarMemoUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val calendarRepository: CalendarRepository, private val memoRepository: MemoRepository, private val tagRepository: TagRepository) { +public class FindCalendarMemoUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val findCalendarSelectedTagFilterUseCase: FindCalendarSelectedTagFilterUseCase, + private val memoRepository: MemoRepository, + private val tagRepository: TagRepository, +) { public operator fun invoke(dateRange: ClosedRange): Flow>> = flow { - val accountFlow = getAccountUseCase().mapLatest { it.getOrThrow() } - val calendarTagFilterFlow = - accountFlow - .flatMapLatest { calendarRepository.findFilter(it.uid) } - .flatMapLatest { tagRepository.findByIds(it) } - .mapLatest { list -> list.map { it.id }.toSet() } - - combine(accountFlow, calendarTagFilterFlow) { account, tagFilter -> + combine( + getAccountUseCase().mapLatest { it.getOrThrow() }, + findCalendarSelectedTagFilterUseCase().mapLatest { it.getOrThrow() }, + ) { account, selectedTagFilter -> + account to selectedTagFilter.map { it.id }.toSet() + }.flatMapLatest { (account, selectedTagFilterIds) -> memoRepository - .findByDateRange(account.uid, dateRange, tagFilter) + .findByDateRange(account.uid, dateRange, selectedTagFilterIds) .flatMapLatest { memoList -> val tagIdSet = memoList.mapNotNull { it.primaryTag }.toSet() @@ -48,8 +50,6 @@ public class FindCalendarMemoUseCase internal constructor(private val getAccount } } } - }.flatMapLatest { - it }.also { emitAll(it) } diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarSelectedTagFilterUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarSelectedTagFilterUseCase.kt new file mode 100644 index 00000000..2239e9d9 --- /dev/null +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarSelectedTagFilterUseCase.kt @@ -0,0 +1,34 @@ +package io.github.taetae98coding.diary.domain.calendar.usecase + +import io.github.taetae98coding.diary.core.model.tag.Tag +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository +import io.github.taetae98coding.diary.domain.tag.repository.TagRepository +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.mapLatest +import org.koin.core.annotation.Factory + +@OptIn(ExperimentalCoroutinesApi::class) +@Factory +public class FindCalendarSelectedTagFilterUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val calendarRepository: CalendarRepository, + private val tagRepository: TagRepository, +) { + public operator fun invoke(): Flow>> = flow { + getAccountUseCase() + .mapLatest { it.getOrThrow() } + .flatMapLatest { calendarRepository.findFilter(it.uid) } + .flatMapLatest { tagRepository.findByIds(it) } + .also { emitAll(it) } + }.mapLatest { + Result.success(it) + }.catch { + emit(Result.failure(it)) + } +} diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarTagFilterUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarTagFilterUseCase.kt new file mode 100644 index 00000000..8b8fc18f --- /dev/null +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/FindCalendarTagFilterUseCase.kt @@ -0,0 +1,49 @@ +package io.github.taetae98coding.diary.domain.calendar.usecase + +import io.github.taetae98coding.diary.domain.calendar.entity.CalendarTagFilter +import io.github.taetae98coding.diary.domain.tag.usecase.PageTagUseCase +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.mapLatest +import org.koin.core.annotation.Factory + +@OptIn(ExperimentalCoroutinesApi::class) +@Factory +public class FindCalendarTagFilterUseCase internal constructor( + private val pageTagUseCase: PageTagUseCase, + private val findCalendarSelectedTagFilterUseCase: FindCalendarSelectedTagFilterUseCase, +) { + public operator fun invoke(): Flow>> = + flow { + combine( + pageTagUseCase().mapLatest { it.getOrThrow() }, + findCalendarSelectedTagFilterUseCase().mapLatest { it.getOrThrow() }, + ) { pageTag, selectedTagFilter -> + val selectedTagFilterIds = selectedTagFilter.map { it.id }.toSet() + + buildList { + addAll(pageTag) + addAll(selectedTagFilter) + }.distinctBy { + it.id + }.sortedBy { + it.detail.title + }.map { + CalendarTagFilter( + tag = it, + isSelected = selectedTagFilterIds.contains(it.id), + ) + } + }.also { + emitAll(it) + } + }.mapLatest { + Result.success(it) + }.catch { + emit(Result.failure(it)) + } +} diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/HasCalendarFilterUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/HasCalendarFilterUseCase.kt index 0ad5edc0..3b5a4f82 100644 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/HasCalendarFilterUseCase.kt +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/HasCalendarFilterUseCase.kt @@ -1,26 +1,22 @@ package io.github.taetae98coding.diary.domain.calendar.usecase -import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase -import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository -import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.emitAll -import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.mapLatest import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class HasCalendarFilterUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val calendarRepository: CalendarRepository, private val tagRepository: TagRepository) { +public class HasCalendarFilterUseCase internal constructor( + private val findCalendarSelectedTagFilterUseCase: FindCalendarSelectedTagFilterUseCase, +) { public operator fun invoke(): Flow> = flow { - getAccountUseCase() + findCalendarSelectedTagFilterUseCase() .mapLatest { it.getOrThrow() } - .flatMapLatest { calendarRepository.findFilter(it.uid) } - .flatMapLatest { tagRepository.findByIds(it) } .mapLatest { it.isNotEmpty() } .also { emitAll(it) } }.mapLatest { diff --git a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/UpsertCalendarTagUseCase.kt b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/UpsertCalendarTagUseCase.kt index 5f4d2608..f42dc1cc 100644 --- a/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/UpsertCalendarTagUseCase.kt +++ b/app/domain/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/calendar/usecase/UpsertCalendarTagUseCase.kt @@ -6,7 +6,10 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpsertCalendarTagUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val repository: CalendarRepository) { +public class UpsertCalendarTagUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val repository: CalendarRepository, +) { public suspend operator fun invoke(tagId: String): Result = runCatching { val account = getAccountUseCase().first().getOrThrow() diff --git a/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/DeleteCalendarTagUseCaseTest.kt b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/DeleteCalendarTagUseCaseTest.kt new file mode 100644 index 00000000..eaee1de0 --- /dev/null +++ b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/DeleteCalendarTagUseCaseTest.kt @@ -0,0 +1,78 @@ +package io.github.taetae98coding.diary.domain.calendar + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository +import io.github.taetae98coding.diary.domain.calendar.usecase.DeleteCalendarTagUseCase +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.Called +import io.mockk.clearAllMocks +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf + +class DeleteCalendarTagUseCaseTest : BehaviorSpec() { + init { + val getAccountUseCase = mockk() + val calendarRepository = mockk(relaxed = true, relaxUnitFun = true) + + val useCase = DeleteCalendarTagUseCase( + getAccountUseCase = getAccountUseCase, + repository = calendarRepository, + ) + + Given("has account") { + val accountUid = "uid" + val account = mockk { + every { uid } returns accountUid + } + + every { getAccountUseCase() } returns flowOf(Result.success(account)) + + And("tagId is null") { + val tagId = null + + When("call usecase") { + val result = useCase(tagId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do nothing") { + verify { + getAccountUseCase wasNot Called + calendarRepository wasNot Called + } + } + } + + clearAllMocks(answers = false) + } + + And("tagId is not null") { + val tagId = "tagId" + + When("call usecase") { + val result = useCase(tagId) + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do delete") { + + coVerify { + calendarRepository.delete(accountUid, tagId) + } + } + } + + clearAllMocks(answers = false) + } + } + } +} diff --git a/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarMemoUseCaseTest.kt b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarMemoUseCaseTest.kt new file mode 100644 index 00000000..4abbc4f6 --- /dev/null +++ b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarMemoUseCaseTest.kt @@ -0,0 +1,114 @@ +package io.github.taetae98coding.diary.domain.calendar + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.core.model.memo.Memo +import io.github.taetae98coding.diary.core.model.memo.MemoDetail +import io.github.taetae98coding.diary.core.model.tag.Tag +import io.github.taetae98coding.diary.core.model.tag.TagDetail +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.calendar.usecase.FindCalendarMemoUseCase +import io.github.taetae98coding.diary.domain.calendar.usecase.FindCalendarSelectedTagFilterUseCase +import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository +import io.github.taetae98coding.diary.domain.tag.repository.TagRepository +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.result.shouldBeSuccess +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.Instant +import kotlinx.datetime.LocalDate + +class FindCalendarMemoUseCaseTest : BehaviorSpec() { + init { + val getAccountUseCase = mockk() + val findCalendarSelectedTagFilterUseCase = mockk() + val memoRepository = mockk(relaxed = true, relaxUnitFun = true) + val tagRepository = mockk(relaxed = true, relaxUnitFun = true) + + val useCase = FindCalendarMemoUseCase( + getAccountUseCase = getAccountUseCase, + findCalendarSelectedTagFilterUseCase = findCalendarSelectedTagFilterUseCase, + memoRepository = memoRepository, + tagRepository = tagRepository, + ) + + Given("has account") { + val accountUid = "uid" + val account = mockk(relaxed = true, relaxUnitFun = true) { + every { uid } returns accountUid + } + every { getAccountUseCase() } returns flowOf(Result.success(account)) + + And("has selected tag filter") { + val selectedTagFilter = listOf(createTag()) + + every { findCalendarSelectedTagFilterUseCase() } answers { + flowOf(Result.success(selectedTagFilter)) + } + + When("call usecase") { + val dateRange = LocalDate(2000, 1, 1)..LocalDate(2000, 1, 31) + val memoList = List(2) { createMemo(it.toString(), if (it == 0) "0" else null) } + val tagList = listOf(createTag()) + + every { memoRepository.findByDateRange(any(), any(), any()) } returns flowOf(memoList) + every { tagRepository.findByIds(any()) } returns flowOf(tagList) + + val result = useCase(dateRange).first() + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("memo color changed") { + val resultList = result.getOrThrow() + val tag = tagList.first() + + resultList.first().detail.color shouldBe tag.detail.color + resultList.last().detail.color shouldNotBe tag.detail.color + } + + Then("do find") { + verify { + memoRepository.findByDateRange(accountUid, dateRange, selectedTagFilter.map { it.id }.toSet()) + tagRepository.findByIds(any()) + } + } + } + } + } + } + + private fun createTag(): Tag = Tag( + id = "0", + detail = TagDetail( + title = "title", + description = "description", + color = 100, + ), + owner = null, + isFinish = false, + isDelete = false, + updateAt = Instant.DISTANT_PAST, + ) + + private fun createMemo(id: String, primaryTag: String?): Memo = Memo( + id = id, + detail = MemoDetail( + title = "title", + description = "description", + start = null, + endInclusive = null, + color = 0, + ), + primaryTag = primaryTag, + owner = null, + isFinish = false, + isDelete = false, + updateAt = Instant.DISTANT_PAST, + ) +} diff --git a/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarSelectedTagFilterUseCaseTest.kt b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarSelectedTagFilterUseCaseTest.kt new file mode 100644 index 00000000..2d589915 --- /dev/null +++ b/app/domain/calendar/src/jvmTest/kotlin/io/github/taetae98coding/diary/domain/calendar/FindCalendarSelectedTagFilterUseCaseTest.kt @@ -0,0 +1,69 @@ +package io.github.taetae98coding.diary.domain.calendar + +import io.github.taetae98coding.diary.core.model.account.Account +import io.github.taetae98coding.diary.core.model.tag.Tag +import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase +import io.github.taetae98coding.diary.domain.calendar.repository.CalendarRepository +import io.github.taetae98coding.diary.domain.calendar.usecase.FindCalendarSelectedTagFilterUseCase +import io.github.taetae98coding.diary.domain.tag.repository.TagRepository +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.result.shouldBeSuccess +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOf + +class FindCalendarSelectedTagFilterUseCaseTest : BehaviorSpec() { + init { + val getAccountUseCase = mockk() + val calendarRepository = mockk() + val tagRepository = mockk() + + val useCase = FindCalendarSelectedTagFilterUseCase( + getAccountUseCase = getAccountUseCase, + calendarRepository = calendarRepository, + tagRepository = tagRepository, + ) + + Given("has account") { + val accountUid = "uid" + val account = mockk(relaxed = true) { + every { uid } returns accountUid + } + + every { getAccountUseCase() } returns flowOf(Result.success(account)) + + And("has tag filter") { + val tagIds = setOf("1", "2", "3") + every { calendarRepository.findFilter(any()) } returns flowOf(tagIds) + + When("call usecase") { + every { tagRepository.findByIds(any()) } answers { + val ids = arg>(0) + val list = ids.map { + mockk { + every { id } returns it + } + } + + flowOf(list) + } + + val result = useCase().first() + + Then("result is success") { + result.shouldBeSuccess() + } + + Then("do find") { + verify { + calendarRepository.findFilter(accountUid) + tagRepository.findByIds(tagIds) + } + } + } + } + } + } +} diff --git a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/JoinUseCase.kt b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/JoinUseCase.kt index 707122b7..1778cf8b 100644 --- a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/JoinUseCase.kt +++ b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/JoinUseCase.kt @@ -6,7 +6,9 @@ import io.github.taetae98coding.diary.library.kotlin.regex.email import org.koin.core.annotation.Factory @Factory -public class JoinUseCase internal constructor(private val repository: CredentialRepository) { +public class JoinUseCase internal constructor( + private val repository: CredentialRepository, +) { public suspend operator fun invoke(email: String, password: String): Result = runCatching { if (!email.contains(Regex.email())) throw InvalidEmailException() diff --git a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LoginUseCase.kt b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LoginUseCase.kt index ed2f292d..f79f3027 100644 --- a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LoginUseCase.kt +++ b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LoginUseCase.kt @@ -11,7 +11,12 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Factory @Factory -public class LoginUseCase internal constructor(private val coroutineScope: CoroutineScope, private val repository: CredentialRepository, private val fetchUseCase: FetchUseCase, private val updateFCMTokenUseCase: UpdateFCMTokenUseCase) { +public class LoginUseCase internal constructor( + private val coroutineScope: CoroutineScope, + private val repository: CredentialRepository, + private val fetchUseCase: FetchUseCase, + private val updateFCMTokenUseCase: UpdateFCMTokenUseCase, +) { public suspend operator fun invoke(email: String, password: String): Result = runCatching { val token = repository.fetchToken(email, password).first() diff --git a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LogoutUseCase.kt b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LogoutUseCase.kt index f93e55e1..a020bc8c 100644 --- a/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LogoutUseCase.kt +++ b/app/domain/credential/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/credential/usecase/LogoutUseCase.kt @@ -6,7 +6,11 @@ import io.github.taetae98coding.diary.domain.fcm.usecase.UpdateFCMTokenUseCase import org.koin.core.annotation.Factory @Factory -public class LogoutUseCase internal constructor(private val repository: CredentialRepository, private val backupUseCase: BackupUseCase, private val updateFCMTokenUseCase: UpdateFCMTokenUseCase) { +public class LogoutUseCase internal constructor( + private val repository: CredentialRepository, + private val backupUseCase: BackupUseCase, + private val updateFCMTokenUseCase: UpdateFCMTokenUseCase, +) { public suspend operator fun invoke(): Result = runCatching { backupUseCase() diff --git a/app/domain/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpdateFCMTokenUseCase.kt b/app/domain/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpdateFCMTokenUseCase.kt index fbe419bb..15a5b272 100644 --- a/app/domain/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpdateFCMTokenUseCase.kt +++ b/app/domain/fcm/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpdateFCMTokenUseCase.kt @@ -7,7 +7,10 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpdateFCMTokenUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val repository: FCMRepository) { +public class UpdateFCMTokenUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val repository: FCMRepository, +) { public suspend operator fun invoke(): Result = runCatching { val account = getAccountUseCase().first().getOrThrow() diff --git a/app/domain/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fetch/usecase/FetchUseCase.kt b/app/domain/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fetch/usecase/FetchUseCase.kt index 31c3f07a..d5866819 100644 --- a/app/domain/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fetch/usecase/FetchUseCase.kt +++ b/app/domain/fetch/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/fetch/usecase/FetchUseCase.kt @@ -9,7 +9,12 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class FetchUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val backupUseCase: BackupUseCase, private val memoFetchRepository: MemoFetchRepository, private val tagFetchRepository: TagFetchRepository) { +public class FetchUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val backupUseCase: BackupUseCase, + private val memoFetchRepository: MemoFetchRepository, + private val tagFetchRepository: TagFetchRepository, +) { public suspend operator fun invoke(): Result = runCatching { val account = getAccountUseCase().first().getOrThrow() diff --git a/app/domain/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/holiday/usecase/FindHolidayUseCase.kt b/app/domain/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/holiday/usecase/FindHolidayUseCase.kt index 1b40670d..9bb38b7b 100644 --- a/app/domain/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/holiday/usecase/FindHolidayUseCase.kt +++ b/app/domain/holiday/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/holiday/usecase/FindHolidayUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FindHolidayUseCase internal constructor(private val repository: HolidayRepository) { +public class FindHolidayUseCase internal constructor( + private val repository: HolidayRepository, +) { public operator fun invoke(year: Int, month: Month): Flow>> = flow { emitAll(repository.findHoliday(year, month)) } .mapLatest { Result.success(it) } diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/entity/MemoTag.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/entity/MemoTag.kt index 85c48a6a..7b48fe66 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/entity/MemoTag.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/entity/MemoTag.kt @@ -2,4 +2,8 @@ package io.github.taetae98coding.diary.domain.memo.entity import io.github.taetae98coding.diary.core.model.tag.Tag -public data class MemoTag(val tag: Tag, val isSelected: Boolean, val isPrimary: Boolean) +public data class MemoTag( + val tag: Tag, + val isSelected: Boolean, + val isPrimary: Boolean, +) diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/AddMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/AddMemoUseCase.kt index 7dfac6f3..c9c120d0 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/AddMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/AddMemoUseCase.kt @@ -6,15 +6,20 @@ import io.github.taetae98coding.diary.core.model.memo.MemoDetail import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase import io.github.taetae98coding.diary.domain.backup.usecase.PushMemoBackupQueueUseCase import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository -import kotlin.uuid.ExperimentalUuidApi -import kotlin.uuid.Uuid import kotlinx.coroutines.flow.first import kotlinx.datetime.Clock import org.koin.core.annotation.Factory +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @OptIn(ExperimentalUuidApi::class) @Factory -public class AddMemoUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val clock: Clock, private val repository: MemoRepository) { +public class AddMemoUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val clock: Clock, + private val repository: MemoRepository, +) { public suspend operator fun invoke( detail: MemoDetail, primaryTag: String?, diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoPrimaryTagUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoPrimaryTagUseCase.kt index 53e52cbb..9c087df4 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoPrimaryTagUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoPrimaryTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import org.koin.core.annotation.Factory @Factory -public class DeleteMemoPrimaryTagUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoRepository) { +public class DeleteMemoPrimaryTagUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { public suspend operator fun invoke(memoId: String?): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoUseCase.kt index 1cc74670..ff576ec6 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/DeleteMemoUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import org.koin.core.annotation.Factory @Factory -public class DeleteMemoUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoRepository) { +public class DeleteMemoUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { public suspend operator fun invoke(memoId: String?): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoTagUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoTagUseCase.kt index adf84253..5512297c 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoTagUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoTagUseCase.kt @@ -17,7 +17,12 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FindMemoTagUseCase internal constructor(private val findMemoUseCase: FindMemoUseCase, private val pageTagUseCase: PageTagUseCase, private val memoTagRepository: MemoTagRepository, private val tagRepository: TagRepository) { +public class FindMemoTagUseCase internal constructor( + private val findMemoUseCase: FindMemoUseCase, + private val pageTagUseCase: PageTagUseCase, + private val memoTagRepository: MemoTagRepository, + private val tagRepository: TagRepository, +) { public operator fun invoke(memoId: String?): Flow>> { if (memoId.isNullOrBlank()) return flowOf(Result.success(emptyList())) diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoUseCase.kt index b3f59f0d..9b9a8bc3 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FindMemoUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FindMemoUseCase internal constructor(private val repository: MemoRepository) { +public class FindMemoUseCase internal constructor( + private val repository: MemoRepository, +) { public operator fun invoke(memoId: String?): Flow> { if (memoId.isNullOrBlank()) return flowOf(Result.success(null)) diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FinishMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FinishMemoUseCase.kt index f2a4d5e4..fa429df2 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FinishMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FinishMemoUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import org.koin.core.annotation.Factory @Factory -public class FinishMemoUseCase internal constructor(private val repository: MemoRepository, private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase) { +public class FinishMemoUseCase internal constructor( + private val repository: MemoRepository, + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, +) { public suspend operator fun invoke(memoId: String?): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestartMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestartMemoUseCase.kt index 8cca1360..c413acf8 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestartMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestartMemoUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import org.koin.core.annotation.Factory @Factory -public class RestartMemoUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoRepository) { +public class RestartMemoUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { public suspend operator fun invoke(memoId: String?): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestoreMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestoreMemoUseCase.kt new file mode 100644 index 00000000..8f555bc3 --- /dev/null +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/RestoreMemoUseCase.kt @@ -0,0 +1,20 @@ +package io.github.taetae98coding.diary.domain.memo.usecase + +import io.github.taetae98coding.diary.domain.backup.usecase.PushMemoBackupQueueUseCase +import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository +import org.koin.core.annotation.Factory + +@Factory +public class RestoreMemoUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { + public suspend operator fun invoke(memoId: String?): Result { + return runCatching { + if (memoId.isNullOrBlank()) return@runCatching + + repository.updateDelete(memoId, false) + pushMemoBackupQueueUseCase(memoId) + } + } +} diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/SelectMemoTagUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/SelectMemoTagUseCase.kt index c4d058d4..6202f82c 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/SelectMemoTagUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/SelectMemoTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoTagRepository import org.koin.core.annotation.Factory @Factory -public class SelectMemoTagUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoTagRepository) { +public class SelectMemoTagUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoTagRepository, +) { public suspend operator fun invoke(memoId: String?, tagId: String?): Result { return runCatching { if (memoId.isNullOrBlank() || tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UnselectMemoTagUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UnselectMemoTagUseCase.kt index 88b01888..e00977fb 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UnselectMemoTagUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UnselectMemoTagUseCase.kt @@ -7,7 +7,12 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UnselectMemoTagUseCase internal constructor(private val findMemoUseCase: FindMemoUseCase, private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val memoRepository: MemoRepository, private val memoTagRepository: MemoTagRepository) { +public class UnselectMemoTagUseCase internal constructor( + private val findMemoUseCase: FindMemoUseCase, + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val memoRepository: MemoRepository, + private val memoTagRepository: MemoTagRepository, +) { public suspend operator fun invoke(memoId: String?, tagId: String?): Result { return runCatching { if (memoId.isNullOrBlank() || tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoPrimaryTagUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoPrimaryTagUseCase.kt index 06a50680..cac0643e 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoPrimaryTagUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoPrimaryTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.memo.repository.MemoRepository import org.koin.core.annotation.Factory @Factory -public class UpdateMemoPrimaryTagUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoRepository) { +public class UpdateMemoPrimaryTagUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { public suspend operator fun invoke(memoId: String?, tagId: String?): Result { return runCatching { if (memoId.isNullOrBlank() || tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoUseCase.kt b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoUseCase.kt index 1737ec24..f1018baf 100644 --- a/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoUseCase.kt +++ b/app/domain/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpdateMemoUseCase.kt @@ -7,7 +7,10 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpdateMemoUseCase internal constructor(private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, private val repository: MemoRepository) { +public class UpdateMemoUseCase internal constructor( + private val pushMemoBackupQueueUseCase: PushMemoBackupQueueUseCase, + private val repository: MemoRepository, +) { public suspend operator fun invoke(memoId: String?, detail: MemoDetail): Result { return runCatching { if (memoId.isNullOrBlank()) return@runCatching diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/repository/TagRepository.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/repository/TagRepository.kt index b0222f2a..0b5cda8f 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/repository/TagRepository.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/repository/TagRepository.kt @@ -1,5 +1,6 @@ package io.github.taetae98coding.diary.domain.tag.repository +import io.github.taetae98coding.diary.core.model.memo.Memo import io.github.taetae98coding.diary.core.model.tag.Tag import io.github.taetae98coding.diary.core.model.tag.TagDetail import kotlinx.coroutines.flow.Flow @@ -13,9 +14,11 @@ public interface TagRepository { public suspend fun updateFinish(tagId: String, isFinish: Boolean) + public fun page(owner: String?): Flow> + public fun find(tagId: String): Flow public fun findByIds(tagIds: Set): Flow> - public fun page(owner: String?): Flow> + public fun findMemoByTagId(tagId: String): Flow> } diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/AddTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/AddTagUseCase.kt index 402c1bb5..343f9774 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/AddTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/AddTagUseCase.kt @@ -6,15 +6,20 @@ import io.github.taetae98coding.diary.core.model.tag.TagDetail import io.github.taetae98coding.diary.domain.account.usecase.GetAccountUseCase import io.github.taetae98coding.diary.domain.backup.usecase.PushTagBackupQueueUseCase import io.github.taetae98coding.diary.domain.tag.repository.TagRepository -import kotlin.uuid.ExperimentalUuidApi -import kotlin.uuid.Uuid import kotlinx.coroutines.flow.first import kotlinx.datetime.Clock import org.koin.core.annotation.Factory +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @OptIn(ExperimentalUuidApi::class) @Factory -public class AddTagUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, private val clock: Clock, private val repository: TagRepository) { +public class AddTagUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, + private val clock: Clock, + private val repository: TagRepository, +) { public suspend operator fun invoke(detail: TagDetail): Result = runCatching { if (detail.title.isBlank()) throw TagTitleBlankException() diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/DeleteTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/DeleteTagUseCase.kt index e80031d0..fc1273b5 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/DeleteTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/DeleteTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import org.koin.core.annotation.Factory @Factory -public class DeleteTagUseCase internal constructor(private val repository: TagRepository, private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase) { +public class DeleteTagUseCase internal constructor( + private val repository: TagRepository, + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, +) { public suspend operator fun invoke(tagId: String?): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FindTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FindTagUseCase.kt index 79dbdbc9..62e3e8c2 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FindTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FindTagUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FindTagUseCase internal constructor(private val repository: TagRepository) { +public class FindTagUseCase internal constructor( + private val repository: TagRepository, +) { public operator fun invoke(tagId: String?): Flow> { if (tagId.isNullOrBlank()) return flowOf(Result.success(null)) diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FinishTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FinishTagUseCase.kt index f10fb168..a10d8995 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FinishTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FinishTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import org.koin.core.annotation.Factory @Factory -public class FinishTagUseCase internal constructor(private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, private val repository: TagRepository) { +public class FinishTagUseCase internal constructor( + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, + private val repository: TagRepository, +) { public suspend operator fun invoke(tagId: String?): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagMemoUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagMemoUseCase.kt new file mode 100644 index 00000000..b1a2f2f1 --- /dev/null +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagMemoUseCase.kt @@ -0,0 +1,26 @@ +package io.github.taetae98coding.diary.domain.tag.usecase + +import io.github.taetae98coding.diary.core.model.memo.Memo +import io.github.taetae98coding.diary.domain.tag.repository.TagRepository +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.emitAll +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.mapLatest +import org.koin.core.annotation.Factory + +@OptIn(ExperimentalCoroutinesApi::class) +@Factory +public class PageTagMemoUseCase internal constructor( + private val repository: TagRepository, +) { + public operator fun invoke(tagId: String?): Flow>> { + if (tagId.isNullOrBlank()) return flowOf(Result.success(emptyList())) + + return flow { emitAll(repository.findMemoByTagId(tagId)) } + .mapLatest { Result.success(it) } + .catch { emit(Result.failure(it)) } + } +} diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagUseCase.kt index ea940cc8..efeb79ca 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/PageTagUseCase.kt @@ -14,7 +14,10 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class PageTagUseCase internal constructor(private val getAccountUseCase: GetAccountUseCase, private val repository: TagRepository) { +public class PageTagUseCase internal constructor( + private val getAccountUseCase: GetAccountUseCase, + private val repository: TagRepository, +) { public operator fun invoke(): Flow>> = flow { getAccountUseCase() diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestartTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestartTagUseCase.kt index 952fd13c..64d9f77c 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestartTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestartTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import org.koin.core.annotation.Factory @Factory -public class RestartTagUseCase internal constructor(private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, private val repository: TagRepository) { +public class RestartTagUseCase internal constructor( + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, + private val repository: TagRepository, +) { public suspend operator fun invoke(tagId: String?): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestoreTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestoreTagUseCase.kt index aa3961be..d416a3df 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestoreTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/RestoreTagUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.tag.repository.TagRepository import org.koin.core.annotation.Factory @Factory -public class RestoreTagUseCase internal constructor(private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, private val repository: TagRepository) { +public class RestoreTagUseCase internal constructor( + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, + private val repository: TagRepository, +) { public suspend operator fun invoke(tagId: String?): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpdateTagUseCase.kt b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpdateTagUseCase.kt index a6b2a1ab..ca120c49 100644 --- a/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpdateTagUseCase.kt +++ b/app/domain/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpdateTagUseCase.kt @@ -7,7 +7,10 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpdateTagUseCase internal constructor(private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, private val repository: TagRepository) { +public class UpdateTagUseCase internal constructor( + private val pushTagBackupQueueUseCase: PushTagBackupQueueUseCase, + private val repository: TagRepository, +) { public suspend operator fun invoke(tagId: String?, detail: TagDetail): Result { return runCatching { if (tagId.isNullOrBlank()) return@runCatching diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/common/BottomBarButton.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/common/BottomBarButton.kt index eb03f40c..0e86af95 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/common/BottomBarButton.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/common/BottomBarButton.kt @@ -52,7 +52,8 @@ internal fun BottomBarButtonContent( content: @Composable BoxScope.() -> Unit, ) { Box( - modifier = modifier.fillMaxWidth() + modifier = modifier + .fillMaxWidth() .height(50.dp) .windowInsetsPadding(NavigationBarDefaults.windowInsets), contentAlignment = Alignment.Center, diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinScreen.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinScreen.kt index 02ecec02..9ddc1fb1 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinScreen.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinScreen.kt @@ -82,7 +82,8 @@ internal fun JoinScreen( Content( state = state, onJoin = onJoin, - modifier = Modifier.padding(it) + modifier = Modifier + .padding(it) .padding(DiaryTheme.dimen.screenPaddingValues), ) } diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinViewModel.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinViewModel.kt index b9f53634..100e06a3 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinViewModel.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/JoinViewModel.kt @@ -14,7 +14,10 @@ import kotlinx.coroutines.launch import org.koin.android.annotation.KoinViewModel @KoinViewModel -internal class JoinViewModel(private val joinUseCase: JoinUseCase, private val loginUseCase: LoginUseCase) : ViewModel() { +internal class JoinViewModel( + private val joinUseCase: JoinUseCase, + private val loginUseCase: LoginUseCase, +) : ViewModel() { private val _uiState = MutableStateFlow(JoinUiState(onMessageShow = ::clearMessage)) val uiState = _uiState.asStateFlow() diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinScreenState.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinScreenState.kt index 57f206bf..5b4ac3ec 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinScreenState.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinScreenState.kt @@ -12,7 +12,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch -internal class JoinScreenState(val coroutineScope: CoroutineScope) { +internal class JoinScreenState( + val coroutineScope: CoroutineScope, +) { private var messageJob: Job? = null val hostState: SnackbarHostState = SnackbarHostState() diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinUiState.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinUiState.kt index 889f301b..72e412e5 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinUiState.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/join/state/JoinUiState.kt @@ -1,5 +1,12 @@ package io.github.taetae98coding.diary.feature.account.join.state -internal data class JoinUiState(val isProgress: Boolean = false, val isLoginFinish: Boolean = false, val isExistEmail: Boolean = false, val isNetworkError: Boolean = false, val isUnknownError: Boolean = false, val onMessageShow: () -> Unit = {}) { +internal data class JoinUiState( + val isProgress: Boolean = false, + val isLoginFinish: Boolean = false, + val isExistEmail: Boolean = false, + val isNetworkError: Boolean = false, + val isUnknownError: Boolean = false, + val onMessageShow: () -> Unit = {}, +) { val hasMessage = isLoginFinish || isExistEmail || isNetworkError || isUnknownError } diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginScreen.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginScreen.kt index 0efb680f..733f0ada 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginScreen.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginScreen.kt @@ -82,7 +82,8 @@ internal fun LoginScreen( Content( state = state, onLogin = onLogin, - modifier = Modifier.padding(it) + modifier = Modifier + .padding(it) .padding(DiaryTheme.dimen.screenPaddingValues), ) } diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginViewModel.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginViewModel.kt index 99343c3d..47fcaf59 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginViewModel.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/LoginViewModel.kt @@ -13,7 +13,9 @@ import kotlinx.coroutines.launch import org.koin.android.annotation.KoinViewModel @KoinViewModel -internal class LoginViewModel(private val loginUseCase: LoginUseCase) : ViewModel() { +internal class LoginViewModel( + private val loginUseCase: LoginUseCase, +) : ViewModel() { private val _uiState = MutableStateFlow(LoginUiState(onMessageShow = ::clearMessage)) val uiState = _uiState.asStateFlow() diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginScreenState.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginScreenState.kt index 0a52386a..51e3c545 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginScreenState.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginScreenState.kt @@ -11,7 +11,9 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch -internal class LoginScreenState(private val coroutineScope: CoroutineScope) { +internal class LoginScreenState( + private val coroutineScope: CoroutineScope, +) { private var messageJob: Job? = null val hostState: SnackbarHostState = SnackbarHostState() diff --git a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginUiState.kt b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginUiState.kt index d39e959b..ceb2dbf1 100644 --- a/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginUiState.kt +++ b/app/feature/account/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/account/login/state/LoginUiState.kt @@ -1,5 +1,12 @@ package io.github.taetae98coding.diary.feature.account.login.state -internal data class LoginUiState(val isProgress: Boolean = false, val isLoginFinish: Boolean = false, val isAccountNotFound: Boolean = false, val isNetworkError: Boolean = false, val isUnknownError: Boolean = false, val onMessageShow: () -> Unit = {}) { +internal data class LoginUiState( + val isProgress: Boolean = false, + val isLoginFinish: Boolean = false, + val isAccountNotFound: Boolean = false, + val isNetworkError: Boolean = false, + val isUnknownError: Boolean = false, + val onMessageShow: () -> Unit = {}, +) { val hasMessage = isLoginFinish || isAccountNotFound || isNetworkError || isUnknownError } diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/CalendarNavigation.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/CalendarNavigation.kt index 69bcbf4b..ca394d75 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/CalendarNavigation.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/CalendarNavigation.kt @@ -5,6 +5,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.compose.dialog import androidx.navigation.compose.navigation +import androidx.navigation.navOptions import io.github.taetae98coding.diary.core.compose.dialog.transparentScrimDialogProperties import io.github.taetae98coding.diary.core.navigation.calendar.CalendarDestination import io.github.taetae98coding.diary.core.navigation.calendar.CalendarFilterDestination @@ -15,25 +16,30 @@ import io.github.taetae98coding.diary.feature.calendar.filter.CalendarFilterRout import io.github.taetae98coding.diary.feature.calendar.home.CalendarHomeRoute public fun NavGraphBuilder.calendarNavigation( - navController: NavController, + navController: NavController, ) { - navigation( - startDestination = CalendarHomeDestination, - ) { - composable { - CalendarHomeRoute( - navigateToCalendarFilter = { navController.navigate(CalendarFilterDestination) }, - navigateToMemoAdd = { navController.navigate(MemoAddDestination(it.start, it.endInclusive)) }, - navigateToMemoDetail = { navController.navigate(MemoDetailDestination(it)) }, - ) - } + navigation( + startDestination = CalendarHomeDestination, + ) { + composable { + CalendarHomeRoute( + navigateToCalendarFilter = { navController.navigate(CalendarFilterDestination) }, + navigateToMemoAdd = { navController.navigate(MemoAddDestination(it.start, it.endInclusive)) }, + navigateToMemoDetail = { + navController.navigate( + route = MemoDetailDestination(it), + navOptions = navOptions { launchSingleTop = true }, + ) + }, + ) + } - dialog( - dialogProperties = transparentScrimDialogProperties(), - ) { - CalendarFilterRoute( - navigateUp = navController::popBackStack, - ) - } - } + dialog( + dialogProperties = transparentScrimDialogProperties(), + ) { + CalendarFilterRoute( + navigateUp = navController::popBackStack, + ) + } + } } diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterDialog.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterDialog.kt index b1c967bd..06bf2f50 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterDialog.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterDialog.kt @@ -44,7 +44,8 @@ internal fun CalendarFilterDialog( Title() Content( listProvider = listProvider, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .heightIn(min = 100.dp), ) } @@ -57,7 +58,8 @@ private fun Title( ) { Text( text = "태그", - modifier = modifier.minimumInteractiveComponentSize() + modifier = modifier + .minimumInteractiveComponentSize() .padding(horizontal = DiaryTheme.dimen.diaryHorizontalPadding), ) } @@ -87,7 +89,8 @@ private fun Content( } } else { FlowRow( - modifier = modifier.verticalScroll(rememberScrollState()) + modifier = modifier + .verticalScroll(rememberScrollState()) .padding(DiaryTheme.dimen.itemSpace), horizontalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace, Alignment.CenterHorizontally), verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace, Alignment.CenterVertically), diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterTagViewModel.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterTagViewModel.kt index 6024f373..4c430fc8 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterTagViewModel.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/CalendarFilterTagViewModel.kt @@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty import io.github.taetae98coding.diary.domain.calendar.usecase.DeleteCalendarTagUseCase -import io.github.taetae98coding.diary.domain.calendar.usecase.FindCalendarFilterTagUseCase +import io.github.taetae98coding.diary.domain.calendar.usecase.FindCalendarTagFilterUseCase import io.github.taetae98coding.diary.domain.calendar.usecase.UpsertCalendarTagUseCase import io.github.taetae98coding.diary.library.coroutines.mapCollectionLatest import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -16,9 +16,13 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class CalendarFilterTagViewModel(findCalendarFilterTagUseCase: FindCalendarFilterTagUseCase, private val upsertCalendarTagUseCase: UpsertCalendarTagUseCase, private val deleteCalendarTagUseCase: DeleteCalendarTagUseCase) : ViewModel() { +internal class CalendarFilterTagViewModel( + findCalendarTagFilterUseCase: FindCalendarTagFilterUseCase, + private val upsertCalendarTagUseCase: UpsertCalendarTagUseCase, + private val deleteCalendarTagUseCase: DeleteCalendarTagUseCase, +) : ViewModel() { val list = - findCalendarFilterTagUseCase() + findCalendarTagFilterUseCase() .mapLatest { it.getOrNull() } .mapCollectionLatest { TagUiState( diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/TagUiState.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/TagUiState.kt index 941c55bd..481f21b5 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/TagUiState.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/filter/TagUiState.kt @@ -2,4 +2,10 @@ package io.github.taetae98coding.diary.feature.calendar.filter import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty -public data class TagUiState(val id: String, val title: String, val isSelected: Boolean, val select: SkipProperty<() -> Unit>, val unselect: SkipProperty<() -> Unit>) +public data class TagUiState( + val id: String, + val title: String, + val isSelected: Boolean, + val select: SkipProperty<() -> Unit>, + val unselect: SkipProperty<() -> Unit>, +) diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeHolidayViewModel.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeHolidayViewModel.kt index 0a2e9c49..dd924cc8 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeHolidayViewModel.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeHolidayViewModel.kt @@ -22,7 +22,9 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class CalendarHomeHolidayViewModel(findHolidayUseCase: FindHolidayUseCase) : ViewModel() { +internal class CalendarHomeHolidayViewModel( + findHolidayUseCase: FindHolidayUseCase, +) : ViewModel() { private val yearAndMonth = MutableStateFlow?>(null) val holidayList = diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreen.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreen.kt index aa516add..b3fd7580 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreen.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreen.kt @@ -69,7 +69,8 @@ internal fun CalendarHomeScreen( textItemListProvider = textItemListProvider, holidayListProvider = holidayListProvider, onCalendarItemClick = onCalendarItemClick, - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .padding(it) .calendarDateRangeSelectable( state = state.calendarState, diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreenState.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreenState.kt index 8ea19674..a7d393b4 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreenState.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeScreenState.kt @@ -2,4 +2,6 @@ package io.github.taetae98coding.diary.feature.calendar.home import io.github.taetae98coding.diary.core.calendar.compose.state.CalendarState -internal class CalendarHomeScreenState(val calendarState: CalendarState) +internal class CalendarHomeScreenState( + val calendarState: CalendarState, +) diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeViewModel.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeViewModel.kt index c90d44ad..4468753f 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeViewModel.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/CalendarHomeViewModel.kt @@ -23,7 +23,10 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class CalendarHomeViewModel(hasCalendarFilterUseCase: HasCalendarFilterUseCase, findCalendarMemoUseCase: FindCalendarMemoUseCase) : ViewModel() { +internal class CalendarHomeViewModel( + hasCalendarFilterUseCase: HasCalendarFilterUseCase, + findCalendarMemoUseCase: FindCalendarMemoUseCase, +) : ViewModel() { private val yearAndMonth = MutableStateFlow?>(null) val hasFilter = diff --git a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/MemoKey.kt b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/MemoKey.kt index 0bd609c3..75e30093 100644 --- a/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/MemoKey.kt +++ b/app/feature/calendar/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/calendar/home/MemoKey.kt @@ -3,4 +3,6 @@ package io.github.taetae98coding.diary.feature.calendar.home import kotlin.jvm.JvmInline @JvmInline -internal value class MemoKey(val id: String) +internal value class MemoKey( + val id: String, +) diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/MemoNavigation.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/MemoNavigation.kt index 71c2b866..2b6b8717 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/MemoNavigation.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/MemoNavigation.kt @@ -3,6 +3,7 @@ package io.github.taetae98coding.diary.feature.memo import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable +import androidx.navigation.navOptions import androidx.navigation.navigation import io.github.taetae98coding.diary.core.navigation.memo.MemoAddDestination import io.github.taetae98coding.diary.core.navigation.memo.MemoDestination @@ -16,27 +17,37 @@ import kotlin.reflect.typeOf import kotlinx.datetime.LocalDate public fun NavGraphBuilder.memoNavigation( - navController: NavController, + navController: NavController, ) { - navigation( - startDestination = MemoAddDestination(), - ) { - composable( - typeMap = mapOf(typeOf() to LocalDateNavType), - ) { - MemoAddRoute( - navigateUp = navController::popBackStack, - navigateToTagAdd = { navController.navigate(TagAddDestination) }, - navigateToTagDetail = { navController.navigate(TagDetailDestination(it)) }, - ) - } + navigation( + startDestination = MemoAddDestination(), + ) { + composable( + typeMap = mapOf(typeOf() to LocalDateNavType), + ) { + MemoAddRoute( + navigateUp = navController::popBackStack, + navigateToTagAdd = { navController.navigate(TagAddDestination) }, + navigateToTagDetail = { + navController.navigate( + route = TagDetailDestination(it), + navOptions = navOptions { launchSingleTop = true }, + ) + }, + ) + } - composable { - MemoDetailRoute( - navigateUp = navController::popBackStack, - navigateToTagAdd = { navController.navigate(TagAddDestination) }, - navigateToTagDetail = { navController.navigate(TagDetailDestination(it)) }, - ) - } - } + composable { + MemoDetailRoute( + navigateUp = navController::popBackStack, + navigateToTagAdd = { navController.navigate(TagAddDestination) }, + navigateToTagDetail = { + navController.navigate( + route = TagDetailDestination(it), + navOptions = navOptions { launchSingleTop = true }, + ) + }, + ) + } + } } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddRoute.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddRoute.kt index 39d48049..664ff0f2 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddRoute.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddRoute.kt @@ -37,7 +37,7 @@ internal fun MemoAddRoute( val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)) ListDetailPaneScaffold( - directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 450.dp), + directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp), value = navigator.scaffoldValue, listPane = { val state = rememberMemoDetailScreenAddState( diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddViewModel.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddViewModel.kt index 11cc082b..ccea7968 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddViewModel.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/add/MemoAddViewModel.kt @@ -28,7 +28,11 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class MemoAddViewModel(savedStateHandle: SavedStateHandle, private val addMemoUseCase: AddMemoUseCase, pageTagUseCase: PageTagUseCase) : ViewModel() { +internal class MemoAddViewModel( + savedStateHandle: SavedStateHandle, + private val addMemoUseCase: AddMemoUseCase, + pageTagUseCase: PageTagUseCase, +) : ViewModel() { val route = savedStateHandle.toRoute( typeMap = mapOf(typeOf() to LocalDateNavType), @@ -45,7 +49,7 @@ internal class MemoAddViewModel(savedStateHandle: SavedStateHandle, private val started = SharingStarted.WhileSubscribed(5_000), initialValue = null, ) - private val selectedTag = MutableStateFlow(emptySet()) + private val selectedTag = MutableStateFlow(setOfNotNull(savedStateHandle.get(MemoAddDestination.SELECTED_TAG))) private val primaryTag = MutableStateFlow(null) val memoTagList = diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailActionButton.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailActionButton.kt index c4564aa7..498c4f2a 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailActionButton.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailActionButton.kt @@ -3,5 +3,9 @@ package io.github.taetae98coding.diary.feature.memo.detail internal sealed class MemoDetailActionButton { data object None : MemoDetailActionButton() - data class FinishAndDetail(val isFinish: Boolean, val onFinishChange: (Boolean) -> Unit, val delete: () -> Unit) : MemoDetailActionButton() + data class FinishAndDetail( + val isFinish: Boolean, + val onFinishChange: (Boolean) -> Unit, + val delete: () -> Unit, + ) : MemoDetailActionButton() } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailFloatingButton.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailFloatingButton.kt index 4fc0315e..7ba4d129 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailFloatingButton.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailFloatingButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.memo.detail internal sealed class MemoDetailFloatingButton { data object None : MemoDetailFloatingButton() - data class Add(val onAdd: () -> Unit) : MemoDetailFloatingButton() + data class Add( + val onAdd: () -> Unit, + ) : MemoDetailFloatingButton() } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailNavigationButton.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailNavigationButton.kt index 5806fbfa..37a6963a 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailNavigationButton.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailNavigationButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.memo.detail internal sealed class MemoDetailNavigationButton { data object None : MemoDetailNavigationButton() - data class NavigateUp(val onNavigateUp: () -> Unit) : MemoDetailNavigationButton() + data class NavigateUp( + val onNavigateUp: () -> Unit, + ) : MemoDetailNavigationButton() } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailRoute.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailRoute.kt index c5ae22ce..a9930158 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailRoute.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailRoute.kt @@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.core.layout.WindowWidthSizeClass import io.github.taetae98coding.diary.core.compose.adaptive.isListVisible @@ -33,7 +34,7 @@ internal fun MemoDetailRoute( val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)) ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, + directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp), value = navigator.scaffoldValue, listPane = { val detail by detailViewModel.detail.collectAsStateWithLifecycle() diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreen.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreen.kt index 271b9850..ecdec0bf 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreen.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreen.kt @@ -121,7 +121,8 @@ internal fun MemoDetailScreen( onTagTitle = onTagTitle, onTag = onTag, tagListProvider = tagListProvider, - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .padding(it) .padding(DiaryTheme.dimen.screenPaddingValues), ) @@ -202,7 +203,8 @@ private fun Content( modifier: Modifier = Modifier, ) { Column( - modifier = Modifier.verticalScroll(state = rememberScrollState()) + modifier = Modifier + .verticalScroll(state = rememberScrollState()) .then(modifier), verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), ) { @@ -227,7 +229,8 @@ private fun InternalDiaryTag( TagFlow( title = { Row( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .clickable(onClick = onTitle) .minimumInteractiveComponentSize() .padding(horizontal = DiaryTheme.dimen.diaryHorizontalPadding), @@ -245,7 +248,8 @@ private fun InternalDiaryTag( onClick = { onTag(it.id) }, ) }, - modifier = modifier.fillMaxWidth() + modifier = modifier + .fillMaxWidth() .heightIn(min = 150.dp, max = 200.dp), ) } @@ -258,7 +262,8 @@ private fun InternalDiaryColor( Row(modifier = modifier) { DiaryColor( state = state.colorState, - modifier = Modifier.weight(1F) + modifier = Modifier + .weight(1F) .height(100.dp), ) diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenState.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenState.kt index 97d34762..59759996 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenState.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenState.kt @@ -21,9 +21,21 @@ internal sealed class MemoDetailScreenState { val hostState: SnackbarHostState = SnackbarHostState() - data class Add(override val coroutineScope: CoroutineScope, override val componentState: DiaryComponentState, override val dateState: DiaryDateState, override val colorState: DiaryColorState) : MemoDetailScreenState() + data class Add( + override val coroutineScope: CoroutineScope, + override val componentState: DiaryComponentState, + override val dateState: DiaryDateState, + override val colorState: DiaryColorState, + ) : MemoDetailScreenState() - data class Detail(val onDelete: () -> Unit, val onUpdate: () -> Unit, override val coroutineScope: CoroutineScope, override val componentState: DiaryComponentState, override val dateState: DiaryDateState, override val colorState: DiaryColorState) : MemoDetailScreenState() + data class Detail( + val onDelete: () -> Unit, + val onUpdate: () -> Unit, + override val coroutineScope: CoroutineScope, + override val componentState: DiaryComponentState, + override val dateState: DiaryDateState, + override val colorState: DiaryColorState, + ) : MemoDetailScreenState() val memoDetail: MemoDetail get() { diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenUiState.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenUiState.kt index a80c596e..b5ff6468 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenUiState.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailScreenUiState.kt @@ -1,5 +1,13 @@ package io.github.taetae98coding.diary.feature.memo.detail -internal data class MemoDetailScreenUiState(val isProgress: Boolean = false, val isAdd: Boolean = false, val isDelete: Boolean = false, val isUpdate: Boolean = false, val isTitleBlankError: Boolean = false, val isUnknownError: Boolean = false, val onMessageShow: () -> Unit = {}) { +internal data class MemoDetailScreenUiState( + val isProgress: Boolean = false, + val isAdd: Boolean = false, + val isDelete: Boolean = false, + val isUpdate: Boolean = false, + val isTitleBlankError: Boolean = false, + val isUnknownError: Boolean = false, + val onMessageShow: () -> Unit = {}, +) { val hasMessage = isAdd || isDelete || isUpdate || isTitleBlankError || isUnknownError } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailViewModel.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailViewModel.kt index 381a2d38..52b29663 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailViewModel.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/MemoDetailViewModel.kt @@ -50,7 +50,7 @@ internal class MemoDetailViewModel( .mapLatest { it?.detail } .stateIn( scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), + started = SharingStarted.WhileSubscribed(5_000), initialValue = null, ) @@ -66,11 +66,11 @@ internal class MemoDetailViewModel( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = - MemoDetailActionButton.FinishAndDetail( - isFinish = false, - onFinishChange = ::onFinishChange, - delete = ::delete, - ), + MemoDetailActionButton.FinishAndDetail( + isFinish = false, + onFinishChange = ::onFinishChange, + delete = ::delete, + ), ) private fun onFinishChange(isFinish: Boolean) { diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/RememberMemoDetailScreenDetailState.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/RememberMemoDetailScreenDetailState.kt index 66644f6d..012b322a 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/RememberMemoDetailScreenDetailState.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/detail/RememberMemoDetailScreenDetailState.kt @@ -16,6 +16,7 @@ internal fun rememberMemoDetailScreenDetailState( detailProvider: () -> MemoDetail?, ): MemoDetailScreenState.Detail { val detail = detailProvider() + println(detail) val coroutineScope = rememberCoroutineScope() val componentState = rememberDiaryComponentState( diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagNavigationButton.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagNavigationButton.kt index 7187f450..11579461 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagNavigationButton.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagNavigationButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.memo.tag internal sealed class MemoTagNavigationButton { data object None : MemoTagNavigationButton() - data class NavigateUp(val onNavigateUp: () -> Unit) : MemoTagNavigationButton() + data class NavigateUp( + val onNavigateUp: () -> Unit, + ) : MemoTagNavigationButton() } diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagScreen.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagScreen.kt index a672de75..e2174fd0 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagScreen.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/MemoTagScreen.kt @@ -48,7 +48,8 @@ internal fun MemoTagScreen( onTagAdd = onTagAdd, memoTagListProvider = memoTagListProvider, tagListProvider = tagListProvider, - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .padding(it) .padding(DiaryTheme.dimen.diaryPaddingValues), ) @@ -67,13 +68,15 @@ private fun Content( verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), ) { TagFlow( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .weight(3F), listProvider = memoTagListProvider, title = { Text( text = "캘린더 태그", - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .minimumInteractiveComponentSize() .padding(horizontal = DiaryTheme.dimen.diaryHorizontalPadding), ) @@ -83,13 +86,15 @@ private fun Content( ) TagFlow( - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .weight(7F), listProvider = tagListProvider, title = { Text( text = "태그", - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .minimumInteractiveComponentSize() .padding(horizontal = DiaryTheme.dimen.diaryHorizontalPadding), ) diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagFlow.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagFlow.kt index 325367b8..a847418f 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagFlow.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagFlow.kt @@ -52,7 +52,8 @@ internal fun TagFlow( } } else { FlowRow( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .verticalScroll(rememberScrollState()) .padding(DiaryTheme.dimen.itemSpace), horizontalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace, Alignment.CenterHorizontally), diff --git a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagUiState.kt b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagUiState.kt index b0b8d668..834626d6 100644 --- a/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagUiState.kt +++ b/app/feature/memo/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/memo/tag/TagUiState.kt @@ -2,4 +2,11 @@ package io.github.taetae98coding.diary.feature.memo.tag import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty -public data class TagUiState(val id: String, val title: String, val isSelected: Boolean, val color: Int, val select: SkipProperty<() -> Unit>, val unselect: SkipProperty<() -> Unit>) +public data class TagUiState( + val id: String, + val title: String, + val isSelected: Boolean, + val color: Int, + val select: SkipProperty<() -> Unit>, + val unselect: SkipProperty<() -> Unit>, +) diff --git a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/MoreScreen.kt b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/MoreScreen.kt index c7956365..72958308 100644 --- a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/MoreScreen.kt +++ b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/MoreScreen.kt @@ -34,7 +34,8 @@ internal fun MoreScreen( accountUiStateProvider = accountUiStateProvider, onLogin = onLogin, onJoin = onJoin, - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .padding(it) .padding(DiaryTheme.dimen.screenPaddingValues), ) @@ -49,7 +50,8 @@ private fun Content( modifier: Modifier = Modifier, ) { Column( - modifier = Modifier.verticalScroll(rememberScrollState()) + modifier = Modifier + .verticalScroll(rememberScrollState()) .then(modifier), ) { MoreAccount( diff --git a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/MoreAccount.kt b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/MoreAccount.kt index 013d9def..bf3fae21 100644 --- a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/MoreAccount.kt +++ b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/MoreAccount.kt @@ -77,7 +77,8 @@ private fun ProfileImage( modifier: Modifier = Modifier, ) { Box( - modifier = modifier.size(54.dp) + modifier = modifier + .size(54.dp) .background( color = LocalContentColor.current.multiplyAlpha(value = 0.38F), shape = CircleShape, @@ -98,7 +99,8 @@ private fun Email( is MoreAccountUiState.Loading -> { Text( text = "", - modifier = modifier.width(100.dp) + modifier = modifier + .width(100.dp) .shimmer(), ) } diff --git a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/state/MoreAccountUiState.kt b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/state/MoreAccountUiState.kt index 9df7829d..90b462fb 100644 --- a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/state/MoreAccountUiState.kt +++ b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/account/state/MoreAccountUiState.kt @@ -5,5 +5,8 @@ internal sealed class MoreAccountUiState { data object Guest : MoreAccountUiState() - data class Member(val email: String, val logout: () -> Unit) : MoreAccountUiState() + data class Member( + val email: String, + val logout: () -> Unit, + ) : MoreAccountUiState() } diff --git a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/viewmodel/MoreAccountViewModel.kt b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/viewmodel/MoreAccountViewModel.kt index 19ee2137..25213164 100644 --- a/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/viewmodel/MoreAccountViewModel.kt +++ b/app/feature/more/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/more/viewmodel/MoreAccountViewModel.kt @@ -17,7 +17,10 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class MoreAccountViewModel(getAccountUseCase: GetAccountUseCase, private val logoutUseCase: LogoutUseCase) : ViewModel() { +internal class MoreAccountViewModel( + getAccountUseCase: GetAccountUseCase, + private val logoutUseCase: LogoutUseCase, +) : ViewModel() { private val isProgress = MutableStateFlow(false) private val account = getAccountUseCase() diff --git a/app/feature/tag/build.gradle.kts b/app/feature/tag/build.gradle.kts index f6887fa8..82cfdaaf 100644 --- a/app/feature/tag/build.gradle.kts +++ b/app/feature/tag/build.gradle.kts @@ -6,6 +6,7 @@ kotlin { sourceSets { commonMain { dependencies { + implementation(project(":app:domain:memo")) implementation(project(":app:domain:tag")) } } diff --git a/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenPreview.kt b/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenPreview.kt index 882125c1..7923c719 100644 --- a/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenPreview.kt +++ b/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenPreview.kt @@ -30,6 +30,7 @@ private fun DetailPreview() { state = rememberTagDetailScreenDetailState( onUpdate = {}, onDelete = {}, + onMemo = {}, detailProvider = { TagDetail( title = "Title", diff --git a/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenPreview.kt b/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenPreview.kt new file mode 100644 index 00000000..06fc2027 --- /dev/null +++ b/app/feature/tag/src/androidMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenPreview.kt @@ -0,0 +1,68 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import androidx.compose.runtime.Composable +import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty +import io.github.taetae98coding.diary.core.design.system.preview.DiaryPreview +import io.github.taetae98coding.diary.core.design.system.theme.DiaryTheme +import kotlinx.datetime.LocalDate + +@DiaryPreview +@Composable +private fun LoadingPreview() { + DiaryTheme { + TagMemoScreen( + state = rememberTagMemoScreenState(), + navigateButtonProvider = { TagMemoNavigateButton.NavigateUp(onNavigateUp = {}) }, + uiStateProvider = { TagMemoScreenUiState() }, + onAdd = {}, + listProvider = { null }, + onMemo = {}, + ) + } +} + +@DiaryPreview +@Composable +private fun EmptyPreview() { + DiaryTheme { + TagMemoScreen( + state = rememberTagMemoScreenState(), + navigateButtonProvider = { TagMemoNavigateButton.NavigateUp(onNavigateUp = {}) }, + uiStateProvider = { TagMemoScreenUiState() }, + onAdd = {}, + listProvider = { emptyList() }, + onMemo = {}, + ) + } +} + +@DiaryPreview +@Composable +private fun Preview() { + DiaryTheme { + TagMemoScreen( + state = rememberTagMemoScreenState(), + navigateButtonProvider = { TagMemoNavigateButton.NavigateUp(onNavigateUp = {}) }, + uiStateProvider = { TagMemoScreenUiState() }, + onAdd = {}, + listProvider = { + List(10) { + MemoListItemUiState( + id = it.toString(), + title = "Title $it", + dateRange = if (it % 3 == 0) { + null + } else if (it % 3 == 1) { + LocalDate(2000, 1, 1)..LocalDate(2000, 1, 1) + } else { + LocalDate(2000, 1, 1)..LocalDate(2000, 1, 2) + }, + finish = SkipProperty {}, + delete = SkipProperty {}, + ) + } + }, + onMemo = {}, + ) + } +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigate.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigate.kt index afdef0ac..d6e1bc7f 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigate.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigate.kt @@ -5,5 +5,7 @@ internal sealed class TagNavigate { data object Add : TagNavigate() - data class Tag(val tagId: String) : TagNavigate() + data class Tag( + val tagId: String, + ) : TagNavigate() } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigation.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigation.kt index ca5a54d2..cc2c0cb5 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigation.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagNavigation.kt @@ -4,7 +4,11 @@ import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable +import androidx.navigation.navOptions +import androidx.navigation.toRoute import io.github.taetae98coding.diary.core.compose.adaptive.isListVisible +import io.github.taetae98coding.diary.core.navigation.memo.MemoAddDestination +import io.github.taetae98coding.diary.core.navigation.memo.MemoDetailDestination import io.github.taetae98coding.diary.core.navigation.tag.TagAddDestination import io.github.taetae98coding.diary.core.navigation.tag.TagDestination import io.github.taetae98coding.diary.core.navigation.tag.TagDetailDestination @@ -13,23 +17,39 @@ import io.github.taetae98coding.diary.feature.tag.detail.TagDetailRoute @OptIn(ExperimentalMaterial3AdaptiveApi::class) public fun NavGraphBuilder.tagNavigation( - navController: NavController, + navController: NavController, ) { - composable { backStackEntry -> - TagRoute( - onScaffoldValueChange = { backStackEntry.savedStateHandle["app_navigation_visible"] = it.isListVisible() }, - ) - } + composable { backStackEntry -> + TagRoute( + navigateToMemoAdd = { navController.navigate(MemoAddDestination(selectedTag = it)) }, + navigateToMemoDetail = { + navController.navigate( + route = MemoDetailDestination(it), + navOptions = navOptions { launchSingleTop = true }, + ) + }, + onScaffoldValueChange = { backStackEntry.savedStateHandle["app_navigation_visible"] = it.isListVisible() }, + ) + } - composable { - TagAddRoute( - navigateUp = navController::popBackStack, - ) - } + composable { + TagAddRoute( + navigateUp = navController::popBackStack, + ) + } - composable { - TagDetailRoute( - navigateUp = navController::popBackStack, - ) - } + composable { backStackEntry -> + val route = backStackEntry.toRoute() + + TagDetailRoute( + navigateUp = navController::popBackStack, + navigateToMemoAdd = { navController.navigate(MemoAddDestination(selectedTag = route.tagId)) }, + navigateToMemoDetail = { + navController.navigate( + route = MemoDetailDestination(it), + navOptions = navOptions { launchSingleTop = true }, + ) + }, + ) + } } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagRoute.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagRoute.kt index 6486b655..d0f635f4 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagRoute.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/TagRoute.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.core.layout.WindowWidthSizeClass import io.github.taetae98coding.diary.core.compose.adaptive.isDetailVisible @@ -35,213 +36,255 @@ import io.github.taetae98coding.diary.feature.tag.list.TagListFloatingButton import io.github.taetae98coding.diary.feature.tag.list.TagListScreen import io.github.taetae98coding.diary.feature.tag.list.TagListViewModel import io.github.taetae98coding.diary.feature.tag.list.rememberTagListScreenState +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoNavigateButton +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoScreen +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoViewModel +import io.github.taetae98coding.diary.feature.tag.memo.rememberTagMemoScreenState import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable internal fun TagRoute( - onScaffoldValueChange: (ThreePaneScaffoldValue) -> Unit, - modifier: Modifier = Modifier, - listViewModel: TagListViewModel = koinViewModel(), - addViewModel: TagAddViewModel = koinViewModel(), - detailViewModel: TagDetailViewModel = koinViewModel(), + navigateToMemoAdd: (String) -> Unit, + navigateToMemoDetail: (String) -> Unit, + onScaffoldValueChange: (ThreePaneScaffoldValue) -> Unit, + modifier: Modifier = Modifier, + listViewModel: TagListViewModel = koinViewModel(), + addViewModel: TagAddViewModel = koinViewModel(), + detailViewModel: TagDetailViewModel = koinViewModel(), + memoViewModel: TagMemoViewModel = koinViewModel(), ) { - val windowAdaptiveInfo = currentWindowAdaptiveInfo() - val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)) - - var tagNavigate by remember { mutableStateOf(TagNavigate.None) } - var detailPaneRefreshCount by remember { mutableIntStateOf(0) } - - ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, - listPane = { - AnimatedPane { - val isFloatingVisible by remember { - derivedStateOf { - if (navigator.isDetailVisible()) { - navigator.currentDestination?.content != null - } else { - true - } - } - } - - val list by listViewModel.list.collectAsStateWithLifecycle() - val uiState by listViewModel.uiState.collectAsStateWithLifecycle() - - TagListScreen( - state = rememberTagListScreenState(), - floatingButtonProvider = { - if (isFloatingVisible) { - TagListFloatingButton.Add( - onAdd = { - if (navigator.isDetailVisible()) { - tagNavigate = TagNavigate.Add - } else { - navigator.navigateTo(ThreePaneScaffoldRole.Primary) - } - }, - ) - } else { - TagListFloatingButton.None - } - }, - listProvider = { list }, - onTag = { - if (navigator.isDetailVisible() && navigator.currentDestination?.content != null) { - tagNavigate = TagNavigate.Tag(it) - } else { - navigator.navigateTo(ThreePaneScaffoldRole.Primary, it) - detailPaneRefreshCount++ - } - }, - uiStateProvider = { uiState }, - ) - } - }, - detailPane = { - AnimatedPane { - val tagDetail by detailViewModel.tagDetail.collectAsStateWithLifecycle() - val isAdd = remember(detailPaneRefreshCount) { navigator.currentDestination?.content == null } - val state = if (isAdd) { - rememberTagDetailScreenAddState() - } else { - rememberTagDetailScreenDetailState( - onUpdate = { - when (val navigate = tagNavigate) { - is TagNavigate.Add -> { - navigator.navigateTo(ThreePaneScaffoldRole.Primary) - detailPaneRefreshCount++ - tagNavigate = TagNavigate.None - } - - is TagNavigate.Tag -> { - navigator.navigateTo(ThreePaneScaffoldRole.Primary, navigate.tagId) - tagNavigate = TagNavigate.None - } - - is TagNavigate.None -> { - navigator.navigateBack() - } - } - }, - onDelete = { - navigator.navigateBack() - if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { - detailPaneRefreshCount++ - } - }, - detailProvider = { tagDetail }, - ) - } - val isNavigateUpVisible = remember(windowAdaptiveInfo) { - if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { - !navigator.isListVisible() - } else { - true - } - } - val detailActionButton by detailViewModel.actionButton.collectAsStateWithLifecycle() - val uiState = if (isAdd) { - addViewModel.uiState.collectAsStateWithLifecycle() - } else { - detailViewModel.uiState.collectAsStateWithLifecycle() - } - - TagDetailScreen( - state = state, - titleProvider = { - if (isAdd) { - "태그 추가" - } else { - tagDetail?.title - } - }, - navigateButtonProvider = { - if (isNavigateUpVisible) { - TagDetailNavigationButton.NavigateUp( - onNavigateUp = { - if (isAdd) { - navigator.navigateBack() - } else { - detailViewModel.update(state.tagDetail) - } - }, - ) - } else { - TagDetailNavigationButton.None - } - }, - actionButtonProvider = { - if (isAdd) { - TagDetailActionButton.None - } else { - detailActionButton - } - }, - floatingButtonProvider = { - if (isAdd) { - TagDetailFloatingButton.Add(onAdd = { addViewModel.add(state.tagDetail) }) - } else { - TagDetailFloatingButton.None - } - }, - uiStateProvider = { uiState.value }, - ) - - LaunchedEffect(tagNavigate) { - when (tagNavigate) { - is TagNavigate.Add -> { - detailViewModel.update(state.tagDetail) - } - - is TagNavigate.Tag -> { - detailViewModel.update(state.tagDetail) - } - - is TagNavigate.None -> Unit - } - } - } - }, - modifier = modifier, - ) - - LaunchedScaffoldValue( - navigator = navigator, - onScaffoldValueChange = onScaffoldValueChange, - ) - - LaunchedFetch( - navigator = navigator, - detailViewModel = detailViewModel, - ) - - KBackHandler( - isEnabled = navigator.canNavigateBack(), - onBack = navigator::navigateBack, - ) + val windowAdaptiveInfo = currentWindowAdaptiveInfo() + val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)) + + var tagNavigate by remember { mutableStateOf(TagNavigate.None) } + var detailPaneRefreshCount by remember { mutableIntStateOf(0) } + + ListDetailPaneScaffold( + directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp), + value = navigator.scaffoldValue, + listPane = { + AnimatedPane { + val isFloatingVisible by remember { + derivedStateOf { + if (navigator.isDetailVisible()) { + navigator.currentDestination?.content != null + } else { + true + } + } + } + + val list by listViewModel.list.collectAsStateWithLifecycle() + val uiState by listViewModel.uiState.collectAsStateWithLifecycle() + + TagListScreen( + state = rememberTagListScreenState(), + floatingButtonProvider = { + if (isFloatingVisible) { + TagListFloatingButton.Add( + onAdd = { + if (navigator.isDetailVisible()) { + tagNavigate = TagNavigate.Add + } else { + navigator.navigateTo(ThreePaneScaffoldRole.Primary) + } + }, + ) + } else { + TagListFloatingButton.None + } + }, + listProvider = { list }, + onTag = { + if (navigator.isDetailVisible() && navigator.currentDestination?.content != null) { + tagNavigate = TagNavigate.Tag(it) + } else { + navigator.navigateTo(ThreePaneScaffoldRole.Primary, it) + detailPaneRefreshCount++ + } + }, + uiStateProvider = { uiState }, + ) + } + }, + detailPane = { + AnimatedPane { + val tagDetail by detailViewModel.tagDetail.collectAsStateWithLifecycle() + val isAdd = remember(detailPaneRefreshCount) { navigator.currentDestination?.content == null } + val state = if (isAdd) { + rememberTagDetailScreenAddState() + } else { + rememberTagDetailScreenDetailState( + onUpdate = { + when (val navigate = tagNavigate) { + is TagNavigate.Add -> { + navigator.navigateTo(ThreePaneScaffoldRole.Primary) + detailPaneRefreshCount++ + tagNavigate = TagNavigate.None + } + + is TagNavigate.Tag -> { + navigator.navigateTo(ThreePaneScaffoldRole.Primary, navigate.tagId) + tagNavigate = TagNavigate.None + } + + is TagNavigate.None -> { + navigator.navigateBack() + } + } + }, + onDelete = { + navigator.navigateBack() + if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { + detailPaneRefreshCount++ + } + }, + onMemo = { navigator.currentDestination?.content?.let { navigator.navigateTo(ThreePaneScaffoldRole.Tertiary, it) } }, + detailProvider = { tagDetail }, + ) + } + val isNavigateUpVisible by remember(windowAdaptiveInfo) { + derivedStateOf { + if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { + !navigator.isListVisible() + } else { + true + } + } + } + val detailActionButton by detailViewModel.actionButton.collectAsStateWithLifecycle() + val uiState = if (isAdd) { + addViewModel.uiState.collectAsStateWithLifecycle() + } else { + detailViewModel.uiState.collectAsStateWithLifecycle() + } + + TagDetailScreen( + state = state, + titleProvider = { + if (isAdd) { + "태그 추가" + } else { + tagDetail?.title + } + }, + navigateButtonProvider = { + if (isNavigateUpVisible) { + TagDetailNavigationButton.NavigateUp( + onNavigateUp = { + if (isAdd) { + navigator.navigateBack() + } else { + detailViewModel.update(state.tagDetail) + } + }, + ) + } else { + TagDetailNavigationButton.None + } + }, + actionButtonProvider = { + if (isAdd) { + TagDetailActionButton.None + } else { + detailActionButton + } + }, + floatingButtonProvider = { + if (isAdd) { + TagDetailFloatingButton.Add(onAdd = { addViewModel.add(state.tagDetail) }) + } else { + TagDetailFloatingButton.None + } + }, + uiStateProvider = { uiState.value }, + ) + + LaunchedEffect(tagNavigate) { + when (tagNavigate) { + is TagNavigate.Add -> { + detailViewModel.update(state.tagDetail) + } + + is TagNavigate.Tag -> { + detailViewModel.update(state.tagDetail) + } + + is TagNavigate.None -> Unit + } + } + } + }, + modifier = modifier, + extraPane = { + AnimatedPane { + val uiState by memoViewModel.uiState.collectAsStateWithLifecycle() + val list by memoViewModel.memoList.collectAsStateWithLifecycle() + + val isNavigateUpVisible = remember(windowAdaptiveInfo) { + if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { + !navigator.isDetailVisible() + } else { + true + } + } + + TagMemoScreen( + state = rememberTagMemoScreenState(), + navigateButtonProvider = { + if (isNavigateUpVisible) { + TagMemoNavigateButton.NavigateUp(onNavigateUp = navigator::navigateBack) + } else { + TagMemoNavigateButton.None + } + }, + uiStateProvider = { uiState }, + onAdd = { navigator.currentDestination?.content?.let(navigateToMemoAdd) }, + listProvider = { list }, + onMemo = navigateToMemoDetail, + ) + } + }, + ) + + LaunchedScaffoldValue( + navigator = navigator, + onScaffoldValueChange = onScaffoldValueChange, + ) + + LaunchedFetch( + navigator = navigator, + detailViewModel = detailViewModel, + memoViewModel = memoViewModel, + ) + + KBackHandler( + isEnabled = navigator.canNavigateBack(), + onBack = navigator::navigateBack, + ) } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable private fun LaunchedFetch( - navigator: ThreePaneScaffoldNavigator, - detailViewModel: TagDetailViewModel, + navigator: ThreePaneScaffoldNavigator, + detailViewModel: TagDetailViewModel, + memoViewModel: TagMemoViewModel, ) { - LaunchedEffect(navigator.currentDestination?.content, detailViewModel) { - detailViewModel.fetch(navigator.currentDestination?.content) - } + LaunchedEffect(navigator.currentDestination?.content, detailViewModel) { + detailViewModel.fetch(navigator.currentDestination?.content) + memoViewModel.fetch(navigator.currentDestination?.content) + } } @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable private fun LaunchedScaffoldValue( - navigator: ThreePaneScaffoldNavigator, - onScaffoldValueChange: (ThreePaneScaffoldValue) -> Unit, + navigator: ThreePaneScaffoldNavigator, + onScaffoldValueChange: (ThreePaneScaffoldValue) -> Unit, ) { - LaunchedEffect(navigator.scaffoldValue) { - onScaffoldValueChange(navigator.scaffoldValue) - } + LaunchedEffect(navigator.scaffoldValue) { + onScaffoldValueChange(navigator.scaffoldValue) + } } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddRoute.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddRoute.kt index 97b390c2..8aa0e745 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddRoute.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddRoute.kt @@ -7,6 +7,7 @@ import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaf import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.github.taetae98coding.diary.feature.tag.detail.TagDetailActionButton import io.github.taetae98coding.diary.feature.tag.detail.TagDetailFloatingButton @@ -24,7 +25,7 @@ internal fun TagAddRoute( val navigator = rememberListDetailPaneScaffoldNavigator() ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, + directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp), value = navigator.scaffoldValue, listPane = { AnimatedPane { diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddViewModel.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddViewModel.kt index 3baf723f..d673911a 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddViewModel.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/add/TagAddViewModel.kt @@ -13,7 +13,9 @@ import kotlinx.coroutines.launch import org.koin.android.annotation.KoinViewModel @KoinViewModel -internal class TagAddViewModel(private val addTagUseCase: AddTagUseCase) : ViewModel() { +internal class TagAddViewModel( + private val addTagUseCase: AddTagUseCase, +) : ViewModel() { private val _uiState = MutableStateFlow(TagDetailScreenUiState(onMessageShow = ::clearMessage)) val uiState = _uiState.asStateFlow() diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/RememberTagDetailScreenDetailState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/RememberTagDetailScreenDetailState.kt index ec6bbba2..2b124ee1 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/RememberTagDetailScreenDetailState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/RememberTagDetailScreenDetailState.kt @@ -12,6 +12,7 @@ import io.github.taetae98coding.diary.core.model.tag.TagDetail internal fun rememberTagDetailScreenDetailState( onUpdate: () -> Unit, onDelete: () -> Unit, + onMemo: () -> Unit, detailProvider: () -> TagDetail?, ): TagDetailScreenState.Detail { val detail = detailProvider() @@ -32,6 +33,7 @@ internal fun rememberTagDetailScreenDetailState( TagDetailScreenState.Detail( onUpdate = onUpdate, onDelete = onDelete, + onMemo = onMemo, coroutineScope = coroutineScope, componentState = componentState, colorState = colorState, diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailActionButton.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailActionButton.kt index ffd8b182..2116362a 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailActionButton.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailActionButton.kt @@ -3,5 +3,9 @@ package io.github.taetae98coding.diary.feature.tag.detail internal sealed class TagDetailActionButton { data object None : TagDetailActionButton() - data class FinishAndDetail(val isFinish: Boolean, val onFinishChange: (Boolean) -> Unit, val delete: () -> Unit) : TagDetailActionButton() + data class FinishAndDetail( + val isFinish: Boolean, + val onFinishChange: (Boolean) -> Unit, + val delete: () -> Unit, + ) : TagDetailActionButton() } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailFloatingButton.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailFloatingButton.kt index c2fa677f..5e77de56 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailFloatingButton.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailFloatingButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.tag.detail internal sealed class TagDetailFloatingButton { data object None : TagDetailFloatingButton() - data class Add(val onAdd: () -> Unit) : TagDetailFloatingButton() + data class Add( + val onAdd: () -> Unit, + ) : TagDetailFloatingButton() } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailNavigationButton.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailNavigationButton.kt index 3c5ba3ec..a79b8477 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailNavigationButton.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailNavigationButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.tag.detail internal sealed class TagDetailNavigationButton { data object None : TagDetailNavigationButton() - data class NavigateUp(val onNavigateUp: () -> Unit) : TagDetailNavigationButton() + data class NavigateUp( + val onNavigateUp: () -> Unit, + ) : TagDetailNavigationButton() } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailRoute.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailRoute.kt index 6d80f0dd..ba884514 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailRoute.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailRoute.kt @@ -1,54 +1,98 @@ package io.github.taetae98coding.diary.feature.tag.detail import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.material3.adaptive.layout.AnimatedPane import androidx.compose.material3.adaptive.layout.ListDetailPaneScaffold +import androidx.compose.material3.adaptive.layout.ThreePaneScaffoldRole +import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective import androidx.compose.material3.adaptive.navigation.rememberListDetailPaneScaffoldNavigator import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.window.core.layout.WindowWidthSizeClass +import io.github.taetae98coding.diary.core.compose.adaptive.isListVisible +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoNavigateButton +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoScreen +import io.github.taetae98coding.diary.feature.tag.memo.TagMemoViewModel +import io.github.taetae98coding.diary.feature.tag.memo.rememberTagMemoScreenState import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalMaterial3AdaptiveApi::class) @Composable internal fun TagDetailRoute( - navigateUp: () -> Unit, - modifier: Modifier = Modifier, - detailViewModel: TagDetailViewModel = koinViewModel(), + navigateUp: () -> Unit, + navigateToMemoAdd: () -> Unit, + navigateToMemoDetail: (String) -> Unit, + modifier: Modifier = Modifier, + detailViewModel: TagDetailViewModel = koinViewModel(), + memoViewModel: TagMemoViewModel = koinViewModel(), ) { - val navigator = rememberListDetailPaneScaffoldNavigator() + val windowAdaptiveInfo = currentWindowAdaptiveInfo() + val navigator = rememberListDetailPaneScaffoldNavigator(scaffoldDirective = calculatePaneScaffoldDirective(windowAdaptiveInfo)) - ListDetailPaneScaffold( - directive = navigator.scaffoldDirective, - value = navigator.scaffoldValue, - listPane = { - AnimatedPane { - val tagDetail by detailViewModel.tagDetail.collectAsStateWithLifecycle() - val state = rememberTagDetailScreenDetailState( - onUpdate = navigateUp, - onDelete = navigateUp, - detailProvider = { tagDetail }, - ) - val actionButton by detailViewModel.actionButton.collectAsStateWithLifecycle() - val uiState by detailViewModel.uiState.collectAsStateWithLifecycle() + ListDetailPaneScaffold( + directive = navigator.scaffoldDirective.copy(defaultPanePreferredWidth = 500.dp), + value = navigator.scaffoldValue, + listPane = { + AnimatedPane { + val tagDetail by detailViewModel.tagDetail.collectAsStateWithLifecycle() + val state = rememberTagDetailScreenDetailState( + onUpdate = navigateUp, + onDelete = navigateUp, + onMemo = { navigator.navigateTo(ThreePaneScaffoldRole.Primary) }, + detailProvider = { tagDetail }, + ) + val actionButton by detailViewModel.actionButton.collectAsStateWithLifecycle() + val uiState by detailViewModel.uiState.collectAsStateWithLifecycle() - TagDetailScreen( - state = state, - titleProvider = { tagDetail?.title }, - navigateButtonProvider = { - TagDetailNavigationButton.NavigateUp( - onNavigateUp = { detailViewModel.update(state.tagDetail) }, - ) - }, - actionButtonProvider = { actionButton }, - floatingButtonProvider = { TagDetailFloatingButton.None }, - uiStateProvider = { uiState }, - ) - } - }, - detailPane = { - }, - modifier = modifier, - ) + TagDetailScreen( + state = state, + titleProvider = { tagDetail?.title }, + navigateButtonProvider = { + TagDetailNavigationButton.NavigateUp( + onNavigateUp = { detailViewModel.update(state.tagDetail) }, + ) + }, + actionButtonProvider = { actionButton }, + floatingButtonProvider = { TagDetailFloatingButton.None }, + uiStateProvider = { uiState }, + ) + } + }, + detailPane = { + val isNavigateUpVisible by remember(windowAdaptiveInfo) { + derivedStateOf { + if (windowAdaptiveInfo.windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) { + !navigator.isListVisible() + } else { + true + } + } + } + + val uiState by memoViewModel.uiState.collectAsStateWithLifecycle() + val list by memoViewModel.memoList.collectAsStateWithLifecycle() + + TagMemoScreen( + state = rememberTagMemoScreenState(), + navigateButtonProvider = { + if (isNavigateUpVisible) { + TagMemoNavigateButton.NavigateUp(onNavigateUp = navigator::navigateBack) + } else { + TagMemoNavigateButton.None + } + }, + uiStateProvider = { uiState }, + onAdd = navigateToMemoAdd, + listProvider = { list }, + onMemo = navigateToMemoDetail, + ) + }, + modifier = modifier, + ) } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreen.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreen.kt index f451179f..eb18f41b 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreen.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreen.kt @@ -6,14 +6,15 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Card import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.IconButton import androidx.compose.material3.IconToggleButton @@ -26,6 +27,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import io.github.taetae98coding.diary.core.compose.button.FloatingAddButton @@ -132,7 +134,8 @@ internal fun TagDetailScreen( ) { Content( state = state, - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .padding(DiaryTheme.dimen.screenPaddingValues) .padding(it), ) @@ -211,19 +214,35 @@ private fun Content( modifier: Modifier = Modifier, ) { Column( - modifier = Modifier.verticalScroll(state = rememberScrollState()) + modifier = Modifier + .verticalScroll(state = rememberScrollState()) .then(modifier), verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), ) { DiaryComponent(state = state.componentState) - Row { + Row(horizontalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace)) { DiaryColor( state = state.colorState, - modifier = Modifier.weight(1F) + modifier = Modifier + .weight(1F) .height(100.dp), ) - Spacer(modifier = Modifier.weight(1F)) + if (state is TagDetailScreenState.Detail) { + Card( + onClick = state.onMemo, + modifier = Modifier + .weight(1F) + .height(100.dp), + ) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Text(text = "메모") + } + } + } } } } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenState.kt index bda9b279..fcc62c27 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenState.kt @@ -19,9 +19,20 @@ internal sealed class TagDetailScreenState { val hostState: SnackbarHostState = SnackbarHostState() - data class Add(override val coroutineScope: CoroutineScope, override val componentState: DiaryComponentState, override val colorState: DiaryColorState) : TagDetailScreenState() - - data class Detail(val onUpdate: () -> Unit, val onDelete: () -> Unit, override val coroutineScope: CoroutineScope, override val componentState: DiaryComponentState, override val colorState: DiaryColorState) : TagDetailScreenState() + data class Add( + override val coroutineScope: CoroutineScope, + override val componentState: DiaryComponentState, + override val colorState: DiaryColorState, + ) : TagDetailScreenState() + + data class Detail( + val onUpdate: () -> Unit, + val onDelete: () -> Unit, + val onMemo: () -> Unit, + override val coroutineScope: CoroutineScope, + override val componentState: DiaryComponentState, + override val colorState: DiaryColorState, + ) : TagDetailScreenState() val tagDetail: TagDetail get() { diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenUiState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenUiState.kt index ee44c608..64fd3af0 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenUiState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailScreenUiState.kt @@ -1,5 +1,13 @@ package io.github.taetae98coding.diary.feature.tag.detail -internal data class TagDetailScreenUiState(val isProgress: Boolean = false, val isAdd: Boolean = false, val isDelete: Boolean = false, val isUpdate: Boolean = false, val isTitleBlankError: Boolean = false, val isUnknownError: Boolean = false, val onMessageShow: () -> Unit = {}) { +internal data class TagDetailScreenUiState( + val isProgress: Boolean = false, + val isAdd: Boolean = false, + val isDelete: Boolean = false, + val isUpdate: Boolean = false, + val isTitleBlankError: Boolean = false, + val isUnknownError: Boolean = false, + val onMessageShow: () -> Unit = {}, +) { val hasMessage = isAdd || isDelete || isUpdate || isTitleBlankError || isUnknownError } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailViewModel.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailViewModel.kt index df0699f2..9408acab 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailViewModel.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/detail/TagDetailViewModel.kt @@ -71,11 +71,11 @@ internal class TagDetailViewModel( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), initialValue = - TagDetailActionButton.FinishAndDetail( - isFinish = false, - onFinishChange = ::onFinishChange, - delete = ::delete, - ), + TagDetailActionButton.FinishAndDetail( + isFinish = false, + onFinishChange = ::onFinishChange, + delete = ::delete, + ), ) private fun onFinishChange(isFinish: Boolean) { diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListFloatingButton.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListFloatingButton.kt index dd938a72..2958713e 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListFloatingButton.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListFloatingButton.kt @@ -3,5 +3,7 @@ package io.github.taetae98coding.diary.feature.tag.list internal sealed class TagListFloatingButton { data object None : TagListFloatingButton() - data class Add(val onAdd: () -> Unit) : TagListFloatingButton() + data class Add( + val onAdd: () -> Unit, + ) : TagListFloatingButton() } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListItemUiState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListItemUiState.kt index d613088e..37d79eea 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListItemUiState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListItemUiState.kt @@ -2,4 +2,9 @@ package io.github.taetae98coding.diary.feature.tag.list import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty -internal data class TagListItemUiState(val id: String, val title: String, val finish: SkipProperty<() -> Unit>, val delete: SkipProperty<() -> Unit>) +internal data class TagListItemUiState( + val id: String, + val title: String, + val finish: SkipProperty<() -> Unit>, + val delete: SkipProperty<() -> Unit>, +) diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreen.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreen.kt index ac9eae39..cf346b4d 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreen.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreen.kt @@ -31,164 +31,169 @@ import io.github.taetae98coding.diary.core.design.system.theme.DiaryTheme @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun TagListScreen( - state: TagListScreenState, - floatingButtonProvider: () -> TagListFloatingButton, - listProvider: () -> List?, - onTag: (String) -> Unit, - uiStateProvider: () -> TagListScreenUiState, - modifier: Modifier = Modifier, + state: TagListScreenState, + floatingButtonProvider: () -> TagListFloatingButton, + listProvider: () -> List?, + onTag: (String) -> Unit, + uiStateProvider: () -> TagListScreenUiState, + modifier: Modifier = Modifier, ) { - Scaffold( - modifier = modifier, - topBar = { - TopAppBar( - title = { Text(text = "태그") }, - ) - }, - snackbarHost = { SnackbarHost(hostState = state.hostState) }, - floatingActionButton = { - val button = floatingButtonProvider() + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + title = { Text(text = "태그") }, + ) + }, + snackbarHost = { SnackbarHost(hostState = state.hostState) }, + floatingActionButton = { + val button = floatingButtonProvider() - AnimatedVisibility( - visible = button is TagListFloatingButton.Add, - enter = scaleIn(), - exit = scaleOut(), - ) { - FloatingAddButton( - onClick = { - if (button is TagListFloatingButton.Add) { - button.onAdd() - } - }, - ) - } - }, - ) { - Content( - listProvider = listProvider, - onTag = onTag, - modifier = Modifier.fillMaxSize() - .padding(it), - ) - } + AnimatedVisibility( + visible = button is TagListFloatingButton.Add, + enter = scaleIn(), + exit = scaleOut(), + ) { + FloatingAddButton( + onClick = { + if (button is TagListFloatingButton.Add) { + button.onAdd() + } + }, + ) + } + }, + ) { + Content( + listProvider = listProvider, + onTag = onTag, + modifier = Modifier + .fillMaxSize() + .padding(it), + ) + } - Message( - state = state, - uiStateProvider = uiStateProvider, - ) + Message( + state = state, + uiStateProvider = uiStateProvider, + ) } @Composable private fun Message( - state: TagListScreenState, - uiStateProvider: () -> TagListScreenUiState, + state: TagListScreenState, + uiStateProvider: () -> TagListScreenUiState, ) { - val uiState = uiStateProvider() + val uiState = uiStateProvider() - LaunchedEffect( - uiState.finishTagId, - uiState.deleteTagId, - uiState.isUnknownError, - ) { - if (!uiState.hasMessage) return@LaunchedEffect + LaunchedEffect( + uiState.finishTagId, + uiState.deleteTagId, + uiState.isUnknownError, + ) { + if (!uiState.hasMessage) return@LaunchedEffect - when { - !uiState.finishTagId.isNullOrBlank() -> { - state.showMessage( - message = "태그 완료 ${Emoji.congratulate.random()}", - actionLabel = "취소", - ) { - uiState.restartTag(uiState.finishTagId) - } - } + when { + !uiState.finishTagId.isNullOrBlank() -> { + state.showMessage( + message = "태그 완료 ${Emoji.congratulate.random()}", + actionLabel = "취소", + ) { + uiState.restartTag(uiState.finishTagId) + } + } - !uiState.deleteTagId.isNullOrBlank() -> { - state.showMessage( - message = "태그 삭제 ${Emoji.congratulate.random()}", - actionLabel = "취소", - ) { - uiState.restoreTag(uiState.deleteTagId) - } - } + !uiState.deleteTagId.isNullOrBlank() -> { + state.showMessage( + message = "태그 삭제 ${Emoji.congratulate.random()}", + actionLabel = "취소", + ) { + uiState.restoreTag(uiState.deleteTagId) + } + } - uiState.isUnknownError -> state.showMessage("알 수 없는 에러가 발생했어요 잠시 후 다시 시도해 주세요 ${Emoji.error.random()}") - } + uiState.isUnknownError -> state.showMessage("알 수 없는 에러가 발생했어요 잠시 후 다시 시도해 주세요 ${Emoji.error.random()}") + } - uiState.onMessageShow() - } + uiState.onMessageShow() + } } @Composable private fun Content( - listProvider: () -> List?, - onTag: (String) -> Unit, - modifier: Modifier = Modifier, + listProvider: () -> List?, + onTag: (String) -> Unit, + modifier: Modifier = Modifier, ) { - val isLoading by remember { derivedStateOf { listProvider() == null } } - val isEmpty by remember { derivedStateOf { !isLoading && listProvider().isNullOrEmpty() } } + val isLoading by remember { derivedStateOf { listProvider() == null } } + val isEmpty by remember { derivedStateOf { !isLoading && listProvider().isNullOrEmpty() } } - if (isEmpty) { - Box( - modifier = modifier, - contentAlignment = Alignment.Center, - ) { - Text( - text = "태그가 없어요 🐼", - style = DiaryTheme.typography.headlineMedium, - ) - } - } else { - LazyColumn( - modifier = modifier, - contentPadding = DiaryTheme.dimen.screenPaddingValues, - verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), - ) { - if (isLoading) { - items( - count = 5, - contentType = { "Tag" }, - ) { - TagItem( - uiState = null, - onClick = {}, - ) - } - } else { - items( - items = listProvider().orEmpty(), - key = { it.id }, - contentType = { "Tag" }, - ) { - TagItem( - uiState = it, - onClick = { onTag(it.id) }, - modifier = Modifier.animateItem(), - ) - } - } - } - } + if (isEmpty) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center, + ) { + Text( + text = "태그가 없어요 🐼", + style = DiaryTheme.typography.headlineMedium, + ) + } + } else { + LazyColumn( + modifier = modifier, + contentPadding = DiaryTheme.dimen.screenPaddingValues, + verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), + ) { + if (isLoading) { + items( + count = 5, + contentType = { "Tag" }, + ) { + TagItem( + uiState = null, + onClick = {}, + ) + } + } else { + items( + items = listProvider().orEmpty(), + key = { it.id }, + contentType = { "Tag" }, + ) { + TagItem( + uiState = it, + onClick = { onTag(it.id) }, + modifier = Modifier.animateItem(), + ) + } + } + } + } } @Composable private fun TagItem( - uiState: TagListItemUiState?, - onClick: () -> Unit, - modifier: Modifier = Modifier, + uiState: TagListItemUiState?, + onClick: () -> Unit, + modifier: Modifier = Modifier, ) { - FinishAndDeleteSwipeBox( - modifier = modifier, - onFinish = { uiState?.finish?.value?.invoke() }, - onDelete = { uiState?.delete?.value?.invoke() }, - ) { - Card(onClick = onClick) { - Box( - modifier = Modifier.fillMaxSize() - .padding(16.dp), - contentAlignment = Alignment.Center, - ) { - Text(text = uiState?.title.orEmpty()) - } - } - } + FinishAndDeleteSwipeBox( + modifier = modifier, + onFinish = { uiState?.finish?.value?.invoke() }, + onDelete = { uiState?.delete?.value?.invoke() }, + ) { + Card(onClick = onClick) { + Box( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + contentAlignment = Alignment.Center, + ) { + Text( + text = uiState?.title.orEmpty(), + style = DiaryTheme.typography.titleLarge, + ) + } + } + } } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenState.kt index 63c1af2c..4d095a10 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenState.kt @@ -8,7 +8,9 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -internal class TagListScreenState(private val coroutineScope: CoroutineScope) { +internal class TagListScreenState( + private val coroutineScope: CoroutineScope, +) { private var messageJob: Job? = null val hostState: SnackbarHostState = SnackbarHostState() diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenUiState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenUiState.kt index e8d91c90..bd7ea03a 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenUiState.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListScreenUiState.kt @@ -1,5 +1,12 @@ package io.github.taetae98coding.diary.feature.tag.list -internal data class TagListScreenUiState(val finishTagId: String? = null, val deleteTagId: String? = null, val isUnknownError: Boolean = false, val restartTag: (String) -> Unit = {}, val restoreTag: (String) -> Unit = {}, val onMessageShow: () -> Unit = {}) { +internal data class TagListScreenUiState( + val finishTagId: String? = null, + val deleteTagId: String? = null, + val isUnknownError: Boolean = false, + val restartTag: (String) -> Unit = {}, + val restoreTag: (String) -> Unit = {}, + val onMessageShow: () -> Unit = {}, +) { val hasMessage = !finishTagId.isNullOrBlank() || !deleteTagId.isNullOrBlank() || isUnknownError } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListViewModel.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListViewModel.kt index 57b2f346..7cb9a76e 100644 --- a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListViewModel.kt +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/list/TagListViewModel.kt @@ -21,7 +21,13 @@ import org.koin.android.annotation.KoinViewModel @OptIn(ExperimentalCoroutinesApi::class) @KoinViewModel -internal class TagListViewModel(pageTagUseCase: PageTagUseCase, private val finishTagUseCase: FinishTagUseCase, private val deleteTagUseCase: DeleteTagUseCase, private val restartTagUseCase: RestartTagUseCase, private val restoreTagUseCase: RestoreTagUseCase) : ViewModel() { +internal class TagListViewModel( + pageTagUseCase: PageTagUseCase, + private val finishTagUseCase: FinishTagUseCase, + private val deleteTagUseCase: DeleteTagUseCase, + private val restartTagUseCase: RestartTagUseCase, + private val restoreTagUseCase: RestoreTagUseCase, +) : ViewModel() { private val _uiState = MutableStateFlow( TagListScreenUiState( @@ -48,18 +54,18 @@ internal class TagListViewModel(pageTagUseCase: PageTagUseCase, private val fini initialValue = null, ) - private fun finish(id: String) { + private fun finish(tagId: String) { viewModelScope.launch { - finishTagUseCase(id) - .onSuccess { _uiState.update { it.copy(finishTagId = id) } } + finishTagUseCase(tagId) + .onSuccess { _uiState.update { it.copy(finishTagId = tagId) } } .onFailure { _uiState.update { it.copy(isUnknownError = true) } } } } - private fun delete(id: String) { + private fun delete(tagId: String) { viewModelScope.launch { - deleteTagUseCase(id) - .onSuccess { _uiState.update { it.copy(deleteTagId = id) } } + deleteTagUseCase(tagId) + .onSuccess { _uiState.update { it.copy(deleteTagId = tagId) } } .onFailure { _uiState.update { it.copy(isUnknownError = true) } } } } diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/MemoListItemUiState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/MemoListItemUiState.kt new file mode 100644 index 00000000..c261b49d --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/MemoListItemUiState.kt @@ -0,0 +1,12 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty +import kotlinx.datetime.LocalDate + +internal data class MemoListItemUiState( + val id: String, + val title: String, + val dateRange: ClosedRange?, + val finish: SkipProperty<() -> Unit>, + val delete: SkipProperty<() -> Unit>, +) diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/RememberTagMemoScreenState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/RememberTagMemoScreenState.kt new file mode 100644 index 00000000..ee8026dd --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/RememberTagMemoScreenState.kt @@ -0,0 +1,14 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope + +@Composable +internal fun rememberTagMemoScreenState(): TagMemoScreenState { + val coroutineScope = rememberCoroutineScope() + + return remember { + TagMemoScreenState(coroutineScope = coroutineScope) + } +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoNavigateButton.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoNavigateButton.kt new file mode 100644 index 00000000..5eea12e1 --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoNavigateButton.kt @@ -0,0 +1,9 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +internal sealed class TagMemoNavigateButton { + data object None : TagMemoNavigateButton() + + data class NavigateUp( + val onNavigateUp: () -> Unit, + ) : TagMemoNavigateButton() +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreen.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreen.kt new file mode 100644 index 00000000..c1ce1e9c --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreen.kt @@ -0,0 +1,207 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Card +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.IconButton +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import io.github.taetae98coding.diary.core.compose.button.FloatingAddButton +import io.github.taetae98coding.diary.core.compose.swipe.FinishAndDeleteSwipeBox +import io.github.taetae98coding.diary.core.design.system.emoji.Emoji +import io.github.taetae98coding.diary.core.design.system.icon.NavigateUpIcon +import io.github.taetae98coding.diary.core.design.system.theme.DiaryTheme +import io.github.taetae98coding.diary.library.color.multiplyAlpha + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun TagMemoScreen( + state: TagMemoScreenState, + navigateButtonProvider: () -> TagMemoNavigateButton, + uiStateProvider: () -> TagMemoScreenUiState, + onAdd: () -> Unit, + listProvider: () -> List?, + onMemo: (String) -> Unit, + modifier: Modifier = Modifier, +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + title = { }, + navigationIcon = { + when (val button = navigateButtonProvider()) { + is TagMemoNavigateButton.NavigateUp -> { + IconButton(onClick = button.onNavigateUp) { + NavigateUpIcon() + } + } + + is TagMemoNavigateButton.None -> Unit + } + }, + ) + }, + snackbarHost = { SnackbarHost(hostState = state.hostState) }, + floatingActionButton = { FloatingAddButton(onClick = onAdd) } + ) { + Content( + listProvider = listProvider, + onMemo = onMemo, + modifier = Modifier + .fillMaxSize() + .padding(it), + ) + } + + Message( + state = state, + uiStateProvider = uiStateProvider, + ) +} + +@Composable +private fun Message( + state: TagMemoScreenState, + uiStateProvider: () -> TagMemoScreenUiState, +) { + val uiState = uiStateProvider() + + LaunchedEffect( + uiState.finishTagId, + uiState.deleteTagId, + uiState.isUnknownError, + ) { + if (!uiState.hasMessage) return@LaunchedEffect + + when { + !uiState.finishTagId.isNullOrBlank() -> { + state.showMessage( + message = "메모 완료 ${Emoji.congratulate.random()}", + actionLabel = "취소", + ) { + uiState.restartTag(uiState.finishTagId) + } + } + + !uiState.deleteTagId.isNullOrBlank() -> { + state.showMessage( + message = "메모 삭제 ${Emoji.congratulate.random()}", + actionLabel = "취소", + ) { + uiState.restoreTag(uiState.deleteTagId) + } + } + + uiState.isUnknownError -> state.showMessage("알 수 없는 에러가 발생했어요 잠시 후 다시 시도해 주세요 ${Emoji.error.random()}") + } + + uiState.onMessageShow() + } +} + +@Composable +private fun Content( + listProvider: () -> List?, + onMemo: (String) -> Unit, + modifier: Modifier = Modifier, +) { + val isLoading by remember { derivedStateOf { listProvider() == null } } + val isEmpty by remember { derivedStateOf { !isLoading && listProvider().isNullOrEmpty() } } + + if (isEmpty) { + Box( + modifier = modifier, + contentAlignment = Alignment.Center, + ) { + Text( + text = "메모가 없어요 🐰", + style = DiaryTheme.typography.headlineMedium, + ) + } + } else { + LazyColumn( + modifier = modifier, + contentPadding = DiaryTheme.dimen.screenPaddingValues, + verticalArrangement = Arrangement.spacedBy(DiaryTheme.dimen.itemSpace), + ) { + if (isLoading) { + items( + count = 5, + contentType = { "Tag" }, + ) { + MemoItem( + uiState = null, + onClick = {}, + ) + } + } else { + items( + items = listProvider().orEmpty(), + key = { it.id }, + contentType = { "Tag" }, + ) { + MemoItem( + uiState = it, + onClick = { onMemo(it.id) }, + modifier = Modifier.animateItem(), + ) + } + } + } + } +} + +@Composable +private fun MemoItem( + uiState: MemoListItemUiState?, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + FinishAndDeleteSwipeBox( + modifier = modifier, + onFinish = { uiState?.finish?.value?.invoke() }, + onDelete = { uiState?.delete?.value?.invoke() }, + ) { + Card(onClick = onClick) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp), + ) { + MaterialTheme.typography.bodySmall + Text( + text = uiState?.title.orEmpty(), + style = DiaryTheme.typography.titleLarge, + ) + if (uiState?.dateRange != null) { + Text( + text = listOf(uiState.dateRange.start, uiState.dateRange.endInclusive) + .distinct() + .joinToString(separator = " ~ "), + color = LocalContentColor.current.multiplyAlpha(0.5F), + style = DiaryTheme.typography.labelSmall, + ) + } + } + } + } +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenState.kt new file mode 100644 index 00000000..70a24a05 --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenState.kt @@ -0,0 +1,45 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import androidx.compose.material3.SnackbarDuration +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.SnackbarResult +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch + +internal class TagMemoScreenState( + private val coroutineScope: CoroutineScope, +) { + private var messageJob: Job? = null + + val hostState: SnackbarHostState = SnackbarHostState() + + fun showMessage( + message: String, + actionLabel: String, + onResult: (SnackbarResult) -> Unit, + ) { + messageJob?.cancel() + messageJob = + coroutineScope.launch { + val result = + hostState.showSnackbar( + message = message, + actionLabel = actionLabel, + duration = SnackbarDuration.Long, + ) + + if (isActive) { + onResult(result) + } + } + } + + fun showMessage( + message: String, + ) { + messageJob?.cancel() + messageJob = coroutineScope.launch { hostState.showSnackbar(message = message) } + } +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenUiState.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenUiState.kt new file mode 100644 index 00000000..dd541986 --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoScreenUiState.kt @@ -0,0 +1,12 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +internal data class TagMemoScreenUiState( + val finishTagId: String? = null, + val deleteTagId: String? = null, + val isUnknownError: Boolean = false, + val restartTag: (String) -> Unit = {}, + val restoreTag: (String) -> Unit = {}, + val onMessageShow: () -> Unit = {}, +) { + val hasMessage = !finishTagId.isNullOrBlank() || !deleteTagId.isNullOrBlank() || isUnknownError +} diff --git a/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoViewModel.kt b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoViewModel.kt new file mode 100644 index 00000000..c0ba1f51 --- /dev/null +++ b/app/feature/tag/src/commonMain/kotlin/io/github/taetae98coding/diary/feature/tag/memo/TagMemoViewModel.kt @@ -0,0 +1,114 @@ +package io.github.taetae98coding.diary.feature.tag.memo + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import io.github.taetae98coding.diary.core.compose.runtime.SkipProperty +import io.github.taetae98coding.diary.core.navigation.tag.TagDetailDestination +import io.github.taetae98coding.diary.domain.memo.usecase.DeleteMemoUseCase +import io.github.taetae98coding.diary.domain.memo.usecase.FinishMemoUseCase +import io.github.taetae98coding.diary.domain.memo.usecase.RestartMemoUseCase +import io.github.taetae98coding.diary.domain.memo.usecase.RestoreMemoUseCase +import io.github.taetae98coding.diary.domain.tag.usecase.PageTagMemoUseCase +import io.github.taetae98coding.diary.library.coroutines.mapCollectionLatest +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.mapLatest +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.koin.android.annotation.KoinViewModel + +@OptIn(ExperimentalCoroutinesApi::class) +@KoinViewModel +internal class TagMemoViewModel( + private val savedStateHandle: SavedStateHandle, + private val pageTagMemoUseCase: PageTagMemoUseCase, + private val finishMemoUseCase: FinishMemoUseCase, + private val deleteMemoUseCase: DeleteMemoUseCase, + private val restartMemoUseCase: RestartMemoUseCase, + private val restoreMemoUseCase: RestoreMemoUseCase, +) : ViewModel() { + private val tagId = savedStateHandle.getStateFlow(TagDetailDestination.TAG_ID, null) + + private val _uiState = + MutableStateFlow( + TagMemoScreenUiState( + restartTag = ::restart, + restoreTag = ::restore, + onMessageShow = ::clearMessage, + ), + ) + val uiState = _uiState.asStateFlow() + + + val memoList = tagId + .flatMapLatest { pageTagMemoUseCase(it) } + .mapLatest { it.getOrNull() } + .mapCollectionLatest { + val start = it.detail.start + val endInclusive = it.detail.endInclusive + + MemoListItemUiState( + id = it.id, + title = it.detail.title, + dateRange = if (start != null && endInclusive != null) { + start..endInclusive + } else { + null + }, + finish = SkipProperty { finish(it.id) }, + delete = SkipProperty { delete(it.id) }, + ) + } + .stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = null, + ) + + private fun finish(memoId: String) { + viewModelScope.launch { + finishMemoUseCase(memoId) + .onSuccess { _uiState.update { it.copy(finishTagId = memoId) } } + .onFailure { _uiState.update { it.copy(isUnknownError = true) } } + } + } + + private fun delete(memoId: String) { + viewModelScope.launch { + deleteMemoUseCase(memoId) + .onSuccess { _uiState.update { it.copy(deleteTagId = memoId) } } + .onFailure { _uiState.update { it.copy(isUnknownError = true) } } + } + } + + private fun restart(id: String) { + viewModelScope.launch { + restartMemoUseCase(id) + } + } + + private fun restore(id: String) { + viewModelScope.launch { + restoreMemoUseCase(id) + } + } + + private fun clearMessage() { + _uiState.update { + it.copy( + finishTagId = null, + deleteTagId = null, + isUnknownError = false, + ) + } + } + + fun fetch(tagId: String?) { + savedStateHandle[TagDetailDestination.TAG_ID] = tagId + } +} diff --git a/app/platform/android/build.gradle.kts b/app/platform/android/build.gradle.kts index 172f58fc..6c976713 100644 --- a/app/platform/android/build.gradle.kts +++ b/app/platform/android/build.gradle.kts @@ -35,8 +35,8 @@ android { defaultConfig { applicationId = "io.github.taetae98coding.diary" - versionCode = 4 - versionName = "1.2.1" + versionCode = 5 + versionName = "1.2.2" } buildTypes { diff --git a/app/platform/android/src/main/kotlin/io/github/taetae98coding/diary/notification/DefaultNotificationManager.kt b/app/platform/android/src/main/kotlin/io/github/taetae98coding/diary/notification/DefaultNotificationManager.kt index e8a7a494..7b142149 100644 --- a/app/platform/android/src/main/kotlin/io/github/taetae98coding/diary/notification/DefaultNotificationManager.kt +++ b/app/platform/android/src/main/kotlin/io/github/taetae98coding/diary/notification/DefaultNotificationManager.kt @@ -7,11 +7,13 @@ import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import io.github.taetae98coding.diary.R -import kotlin.math.abs import org.koin.core.annotation.Factory +import kotlin.math.abs @Factory -internal class DefaultNotificationManager(private val context: Context) { +internal class DefaultNotificationManager( + private val context: Context, +) { fun notify(title: String, description: String?) { if (context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) return diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/App.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/App.kt index a122ce84..8c17a3f2 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/App.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/App.kt @@ -38,7 +38,8 @@ import kotlinx.coroutines.flow.flowOf public fun App() { DiaryTheme { AppScaffold( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() .imePadding(), ) } @@ -62,7 +63,8 @@ private fun AppScaffold( ) isNavigationVisibleFromBackStackEntry ?: visibleDestination.any { - backStackEntry?.destination + backStackEntry + ?.destination ?.hasRoute(it) ?: false } @@ -77,7 +79,8 @@ private fun AppScaffold( AppNavigation.Calendar, AppNavigation.More, ).forEach { navigation -> - val isSelected = backStackEntry?.destination + val isSelected = backStackEntry + ?.destination ?.hierarchy ?.any { it.hasRoute(navigation.route::class) } ?: false diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/BackupManager.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/BackupManager.kt index 5ab8cfa5..cb4e1d69 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/BackupManager.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/BackupManager.kt @@ -9,7 +9,9 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Singleton @Singleton -public class BackupManager(private val backupUseCase: BackupUseCase) { +public class BackupManager( + private val backupUseCase: BackupUseCase, +) { public fun attach(lifecycleOwner: LifecycleOwner) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FCMManager.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FCMManager.kt index 06f6df0b..dc50c1b0 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FCMManager.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FCMManager.kt @@ -9,7 +9,9 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Singleton @Singleton -public class FCMManager internal constructor(private val updateFCMTokenUseCase: UpdateFCMTokenUseCase) { +public class FCMManager internal constructor( + private val updateFCMTokenUseCase: UpdateFCMTokenUseCase, +) { public fun attach(lifecycleOwner: LifecycleOwner) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FetchManager.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FetchManager.kt index b4543799..3d4a5c2f 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FetchManager.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/manager/FetchManager.kt @@ -9,7 +9,9 @@ import kotlinx.coroutines.launch import org.koin.core.annotation.Singleton @Singleton -public class FetchManager(private val fetchUseCase: FetchUseCase) { +public class FetchManager( + private val fetchUseCase: FetchUseCase, +) { public fun attach(lifecycleOwner: LifecycleOwner) { lifecycleOwner.lifecycleScope.launch { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/navigation/AppNavigation.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/navigation/AppNavigation.kt index 30980511..46ec66a5 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/navigation/AppNavigation.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/navigation/AppNavigation.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.core.navigation.memo.MemoDestination import io.github.taetae98coding.diary.core.navigation.more.MoreDestination import io.github.taetae98coding.diary.core.navigation.tag.TagDestination -internal enum class AppNavigation(val title: String, val route: Any) { +internal enum class AppNavigation( + val title: String, + val route: Any, +) { Memo( title = "메모", route = MemoDestination, diff --git a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/state/AppState.kt b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/state/AppState.kt index 56764c9a..353992db 100644 --- a/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/state/AppState.kt +++ b/app/platform/common/src/commonMain/kotlin/io/github/taetae98coding/diary/app/state/AppState.kt @@ -8,7 +8,9 @@ import io.github.taetae98coding.diary.app.navigation.AppNavigation import io.github.taetae98coding.diary.core.navigation.calendar.CalendarHomeDestination @Stable -internal class AppState(val navController: NavHostController) { +internal class AppState( + val navController: NavHostController, +) { fun navigate(navigation: AppNavigation) { val isSelected = navController.currentBackStackEntry diff --git a/app/platform/jvm/build.gradle.kts b/app/platform/jvm/build.gradle.kts index dd8e1daa..132048da 100644 --- a/app/platform/jvm/build.gradle.kts +++ b/app/platform/jvm/build.gradle.kts @@ -47,7 +47,7 @@ compose { targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) packageName = "Diary" - packageVersion = "1.2.1" + packageVersion = "1.2.2" macOS { appStore = true diff --git a/build-logic/src/main/kotlin/plugin/convention/AppDomainPlugin.kt b/build-logic/src/main/kotlin/plugin/convention/AppDomainPlugin.kt index 6806df88..afb89824 100644 --- a/build-logic/src/main/kotlin/plugin/convention/AppDomainPlugin.kt +++ b/build-logic/src/main/kotlin/plugin/convention/AppDomainPlugin.kt @@ -9,10 +9,12 @@ import ext.withKotlinMultiplatform import ext.withPlugin import org.gradle.api.Plugin import org.gradle.api.Project +import plugin.kotest.KotestJvmPlugin import plugin.kotlin.KotlinMultiplatformCommonPlugin internal class AppDomainPlugin : Plugin { private val kotlinMultiplatformCommonPlugin = KotlinMultiplatformCommonPlugin() + private val kotestJvmPlugin = KotestJvmPlugin() override fun apply(target: Project) { val libs = target.libs @@ -47,5 +49,7 @@ internal class AppDomainPlugin : Plugin { kspCommon(platform(libs.library("koin-annotations-bom"))) kspCommon(libs.library("koin-compiler")) } + + kotestJvmPlugin.apply(target) } } diff --git a/build-logic/src/main/kotlin/plugin/kotest/KotestJvmPlugin.kt b/build-logic/src/main/kotlin/plugin/kotest/KotestJvmPlugin.kt new file mode 100644 index 00000000..3fb24582 --- /dev/null +++ b/build-logic/src/main/kotlin/plugin/kotest/KotestJvmPlugin.kt @@ -0,0 +1,41 @@ +package plugin.kotest + +import ext.bundle +import ext.library +import ext.libs +import ext.sourceSets +import ext.withKotlinMultiplatform +import ext.withPlugin +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.testing.Test +import org.gradle.kotlin.dsl.withType + +internal class KotestJvmPlugin : Plugin{ + override fun apply(target: Project) { + val libs = target.libs + + target.withPlugin { + apply("io.kotest.multiplatform") + } + + target.withKotlinMultiplatform { + sourceSets { + jvmTest { + dependencies { + implementation(kotlin("reflect")) + implementation(libs.library("kotlinx-coroutines-test")) + + implementation(libs.bundle("kotest")) + implementation(libs.library("kotest-runner-junit5")) + implementation(libs.library("mockk")) + } + } + } + } + + target.tasks.withType().configureEach { + useJUnitPlatform() + } + } +} diff --git a/build.gradle.kts b/build.gradle.kts index d1233dc7..72902894 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,6 +10,7 @@ plugins { alias(libs.plugins.compose).apply(false) alias(libs.plugins.compose.compiler).apply(false) alias(libs.plugins.room).apply(false) + alias(libs.plugins.kotest).apply(false) alias(libs.plugins.android.application).apply(false) alias(libs.plugins.android.library).apply(false) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/ApiException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/ApiException.kt index 39383033..b1dd2529 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/ApiException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/ApiException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception -public class ApiException(override val message: String? = null, override val cause: Throwable? = null) : Exception(message, cause) +public class ApiException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/NetworkException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/NetworkException.kt index 2bb1cedf..348b7edf 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/NetworkException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/NetworkException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception -public class NetworkException(override val message: String? = null, override val cause: Throwable? = null) : Exception(message, cause) +public class NetworkException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/AccountNotFoundException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/AccountNotFoundException.kt index 0f201b70..318507c5 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/AccountNotFoundException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/AccountNotFoundException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception.account -public class AccountNotFoundException(override val message: String? = null, override val cause: Throwable? = null) : Exception(message, cause) +public class AccountNotFoundException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/ExistEmailException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/ExistEmailException.kt index a1919a1f..c6646c2f 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/ExistEmailException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/ExistEmailException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception.account -public class ExistEmailException(override val message: String? = null, override val cause: Throwable? = null) : Exception(message, cause) +public class ExistEmailException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/InvalidEmailException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/InvalidEmailException.kt index 3fa63949..1000f812 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/InvalidEmailException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/account/InvalidEmailException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception.account -public class InvalidEmailException(override val message: String? = "", override val cause: Throwable? = null) : Exception(message, cause) +public class InvalidEmailException( + override val message: String? = "", + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/memo/MemoTitleBlankException.kt b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/memo/MemoTitleBlankException.kt index 527d53fb..9b7cef70 100644 --- a/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/memo/MemoTitleBlankException.kt +++ b/common/exception/src/commonMain/kotlin/io/github/taetae98coding/diary/common/exception/memo/MemoTitleBlankException.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.common.exception.memo -public class MemoTitleBlankException(override val message: String? = null, override val cause: Throwable? = null) : Exception(message, cause) +public class MemoTitleBlankException( + override val message: String? = null, + override val cause: Throwable? = null, +) : Exception(message, cause) diff --git a/common/model/src/commonMain/kotlin/io/github/taetae98coding/diary/common/model/response/DiaryResponse.kt b/common/model/src/commonMain/kotlin/io/github/taetae98coding/diary/common/model/response/DiaryResponse.kt index 93365f5b..d6babf5b 100644 --- a/common/model/src/commonMain/kotlin/io/github/taetae98coding/diary/common/model/response/DiaryResponse.kt +++ b/common/model/src/commonMain/kotlin/io/github/taetae98coding/diary/common/model/response/DiaryResponse.kt @@ -3,7 +3,11 @@ package io.github.taetae98coding.diary.common.model.response import kotlinx.serialization.Serializable @Serializable -public data class DiaryResponse(val code: Int = 0, val message: String = "", val body: T? = null) { +public data class DiaryResponse( + val code: Int = 0, + val message: String = "", + val body: T? = null, +) { public companion object { public val Success: DiaryResponse = DiaryResponse(200, "SUCCESS", Unit) public val Created: DiaryResponse = DiaryResponse(201, "CREATED", Unit) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1137765c..09ea114f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,6 +24,9 @@ datastore = "1.1.1" # https://developer.android.com/jetp room = "2.7.0-alpha11" # https://developer.android.com/jetpack/androidx/releases/room?hl=en sqlite = "2.5.0-alpha11" # https://developer.android.com/jetpack/androidx/releases/sqlite?hl=en +kotest = "6.0.0.M1" # https://github.com/kotest/kotest/releases +mockk = "1.13.13" # https://github.com/mockk/mockk/releases + ### android android-material = "1.12.0" # https://github.com/material-components/material-components-android/releases androidx-activity = "1.9.3" # https://developer.android.com/jetpack/androidx/releases/activity?hl=en @@ -63,6 +66,7 @@ kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx- kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" } @@ -94,6 +98,12 @@ koin-annotations-bom = { group = "io.insert-koin", name = "koin-annotations-bom" koin-annotations = { group = "io.insert-koin", name = "koin-annotations" } koin-compiler = { group = "io.insert-koin", name = "koin-ksp-compiler" } +kotest-framework-engin = { group = "io.kotest", name = "kotest-framework-engine", version.ref = "kotest" } +kotest-assertions = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotest" } +kotest-property = { group = "io.kotest", name = "kotest-property", version.ref = "kotest" } +kotest-runner-junit5 = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotest" } +mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" } + ### android android-material = { group = "com.google.android.material", name = "material", version.ref = "android-material" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidx-activity" } @@ -150,6 +160,8 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = " room = { id = "androidx.room", version.ref = "room" } +kotest = { id = "io.kotest.multiplatform", version.ref = "kotest" } + ### android android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } @@ -179,6 +191,12 @@ room = [ "sqlite-bundled" ] +kotest = [ + "kotest-framework-engin", + "kotest-assertions", + "kotest-property" +] + ktor-server = [ "ktor-server-netty", "ktor-server-config-yaml", diff --git a/library/coroutines/src/commonMain/kotlin/io/github/taetae98coding/diary/library/coroutines/FlowExt.kt b/library/coroutines/src/commonMain/kotlin/io/github/taetae98coding/diary/library/coroutines/FlowExt.kt index 470288bc..c70589fc 100644 --- a/library/coroutines/src/commonMain/kotlin/io/github/taetae98coding/diary/library/coroutines/FlowExt.kt +++ b/library/coroutines/src/commonMain/kotlin/io/github/taetae98coding/diary/library/coroutines/FlowExt.kt @@ -1,10 +1,10 @@ package io.github.taetae98coding.diary.library.coroutines -import kotlin.jvm.JvmName import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.mapLatest +import kotlin.jvm.JvmName @JvmName("mapCollectionLatest") @OptIn(ExperimentalCoroutinesApi::class) diff --git a/library/koin-datastore/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/datastore/DataStoreExt.jvm.kt b/library/koin-datastore/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/datastore/DataStoreExt.jvm.kt index f942eda2..2e0c9f92 100644 --- a/library/koin-datastore/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/datastore/DataStoreExt.jvm.kt +++ b/library/koin-datastore/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/datastore/DataStoreExt.jvm.kt @@ -1,7 +1,7 @@ package io.github.taetae98coding.diary.library.koin.datastore -import java.io.File import org.koin.core.component.KoinComponent +import java.io.File public var koinDataStoreDefaultPath: String = System.getProperty("user.home") diff --git a/library/koin-room/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/room/RoomExt.jvm.kt b/library/koin-room/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/room/RoomExt.jvm.kt index e4292737..966aec85 100644 --- a/library/koin-room/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/room/RoomExt.jvm.kt +++ b/library/koin-room/src/jvmMain/kotlin/io/github/taetae98coding/diary/library/koin/room/RoomExt.jvm.kt @@ -2,8 +2,8 @@ package io.github.taetae98coding.diary.library.koin.room import androidx.room.Room import androidx.room.RoomDatabase -import java.io.File import org.koin.core.component.KoinComponent +import java.io.File public var koinRoomDefaultPath: String = System.getProperty("user.home") diff --git a/server/app/src/main/kotlin/io/github/taetae98coding/diary/plugin/ContentNegotiationPlugin.kt b/server/app/src/main/kotlin/io/github/taetae98coding/diary/plugin/ContentNegotiationPlugin.kt index 0882fd0c..75d9766f 100644 --- a/server/app/src/main/kotlin/io/github/taetae98coding/diary/plugin/ContentNegotiationPlugin.kt +++ b/server/app/src/main/kotlin/io/github/taetae98coding/diary/plugin/ContentNegotiationPlugin.kt @@ -11,9 +11,9 @@ internal fun Application.installContentNegotiation() { install(ContentNegotiation) { json( json = - Json(DefaultJson) { - ignoreUnknownKeys = true - }, + Json(DefaultJson) { + ignoreUnknownKeys = true + }, ) } } diff --git a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Account.kt b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Account.kt index 213358aa..01d5cd8a 100644 --- a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Account.kt +++ b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Account.kt @@ -1,3 +1,7 @@ package io.github.taetae98coding.diary.core.model -public data class Account(val uid: String, val email: String, val password: String) +public data class Account( + val uid: String, + val email: String, + val password: String, +) diff --git a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Memo.kt b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Memo.kt index 460500a1..5b934687 100644 --- a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Memo.kt +++ b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Memo.kt @@ -3,4 +3,16 @@ package io.github.taetae98coding.diary.core.model import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate -public data class Memo(val id: String, val title: String, val description: String, val start: LocalDate?, val endInclusive: LocalDate?, val color: Int, val owner: String, val primaryTag: String?, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant) +public data class Memo( + val id: String, + val title: String, + val description: String, + val start: LocalDate?, + val endInclusive: LocalDate?, + val color: Int, + val owner: String, + val primaryTag: String?, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, +) diff --git a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/MemoAndTagIds.kt b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/MemoAndTagIds.kt index f73b7e72..3a96067a 100644 --- a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/MemoAndTagIds.kt +++ b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/MemoAndTagIds.kt @@ -1,3 +1,6 @@ package io.github.taetae98coding.diary.core.model -public data class MemoAndTagIds(val memo: Memo, val tagIds: Set) +public data class MemoAndTagIds( + val memo: Memo, + val tagIds: Set, +) diff --git a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Tag.kt b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Tag.kt index 2d9ad929..c585e522 100644 --- a/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Tag.kt +++ b/server/core/model/src/main/kotlin/io/github/taetae98coding/diary/core/model/Tag.kt @@ -2,4 +2,13 @@ package io.github.taetae98coding.diary.core.model import kotlinx.datetime.Instant -public data class Tag(val id: String, val title: String, val description: String, val color: Int, val owner: String, val isFinish: Boolean, val isDelete: Boolean, val updateAt: Instant) +public data class Tag( + val id: String, + val title: String, + val description: String, + val color: Int, + val owner: String, + val isFinish: Boolean, + val isDelete: Boolean, + val updateAt: Instant, +) diff --git a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/FindAccountUseCase.kt b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/FindAccountUseCase.kt index 23c95ce1..2656ce7f 100644 --- a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/FindAccountUseCase.kt +++ b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/FindAccountUseCase.kt @@ -5,7 +5,10 @@ import io.github.taetae98coding.diary.domain.account.repository.AccountRepositor import org.koin.core.annotation.Factory @Factory -public class FindAccountUseCase internal constructor(private val hashingPasswordUseCase: HashingPasswordUseCase, private val repository: AccountRepository) { +public class FindAccountUseCase internal constructor( + private val hashingPasswordUseCase: HashingPasswordUseCase, + private val repository: AccountRepository, +) { public suspend operator fun invoke(email: String, password: String): Result = runCatching { repository.findByEmail( diff --git a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/HashingPasswordUseCase.kt b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/HashingPasswordUseCase.kt index cca4acb9..a6f18ce9 100644 --- a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/HashingPasswordUseCase.kt +++ b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/HashingPasswordUseCase.kt @@ -1,9 +1,9 @@ package io.github.taetae98coding.diary.domain.account.usecase -import java.security.MessageDigest import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.koin.core.annotation.Factory +import java.security.MessageDigest @OptIn(ExperimentalStdlibApi::class) @Factory diff --git a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/JoinUseCase.kt b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/JoinUseCase.kt index a393ba1d..50a99918 100644 --- a/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/JoinUseCase.kt +++ b/server/domain/account/src/main/kotlin/io/github/taetae98coding/diary/domain/account/usecase/JoinUseCase.kt @@ -5,13 +5,16 @@ import io.github.taetae98coding.diary.common.exception.account.InvalidEmailExcep import io.github.taetae98coding.diary.core.model.Account import io.github.taetae98coding.diary.domain.account.repository.AccountRepository import io.github.taetae98coding.diary.library.kotlin.regex.email +import org.koin.core.annotation.Factory import kotlin.uuid.ExperimentalUuidApi import kotlin.uuid.Uuid -import org.koin.core.annotation.Factory @OptIn(ExperimentalUuidApi::class) @Factory -public class JoinUseCase internal constructor(private val hashingPasswordUseCase: HashingPasswordUseCase, private val repository: AccountRepository) { +public class JoinUseCase internal constructor( + private val hashingPasswordUseCase: HashingPasswordUseCase, + private val repository: AccountRepository, +) { public suspend operator fun invoke(email: String, password: String): Result = runCatching { // TODO password check diff --git a/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/DeleteFCMTokenUseCase.kt b/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/DeleteFCMTokenUseCase.kt index 9abd99da..90f77c96 100644 --- a/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/DeleteFCMTokenUseCase.kt +++ b/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/DeleteFCMTokenUseCase.kt @@ -4,6 +4,8 @@ import io.github.taetae98coding.diary.domain.fcm.repository.FCMRepository import org.koin.core.annotation.Factory @Factory -public class DeleteFCMTokenUseCase internal constructor(private val repository: FCMRepository) { +public class DeleteFCMTokenUseCase internal constructor( + private val repository: FCMRepository, +) { public suspend operator fun invoke(token: String): Result = runCatching { repository.delete(token) } } diff --git a/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpsertFCMTokenUseCase.kt b/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpsertFCMTokenUseCase.kt index 12babd64..4589d1f7 100644 --- a/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpsertFCMTokenUseCase.kt +++ b/server/domain/fcm/src/main/kotlin/io/github/taetae98coding/diary/domain/fcm/usecase/UpsertFCMTokenUseCase.kt @@ -4,6 +4,8 @@ import io.github.taetae98coding.diary.domain.fcm.repository.FCMRepository import org.koin.core.annotation.Factory @Factory -public class UpsertFCMTokenUseCase internal constructor(private val repository: FCMRepository) { +public class UpsertFCMTokenUseCase internal constructor( + private val repository: FCMRepository, +) { public suspend operator fun invoke(token: String, owner: String): Result = runCatching { repository.upsert(token, owner) } } diff --git a/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FetchMemoUseCase.kt b/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FetchMemoUseCase.kt index 5b6ea6a0..78cc73bd 100644 --- a/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FetchMemoUseCase.kt +++ b/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/FetchMemoUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FetchMemoUseCase internal constructor(private val repository: MemoRepository) { +public class FetchMemoUseCase internal constructor( + private val repository: MemoRepository, +) { public operator fun invoke(uid: String, updateAt: Instant): Flow>> = flow { emitAll(repository.findMemoAndTagIdsByUpdateAt(uid, updateAt)) } .mapLatest { Result.success(it) } diff --git a/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpsertMemoUseCase.kt b/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpsertMemoUseCase.kt index acfe9300..6f713f1a 100644 --- a/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpsertMemoUseCase.kt +++ b/server/domain/memo/src/main/kotlin/io/github/taetae98coding/diary/domain/memo/usecase/UpsertMemoUseCase.kt @@ -7,7 +7,9 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpsertMemoUseCase internal constructor(private val repository: MemoRepository) { +public class UpsertMemoUseCase internal constructor( + private val repository: MemoRepository, +) { public suspend operator fun invoke(list: List): Result { return runCatching { // TODO Permission Check @@ -26,13 +28,13 @@ public class UpsertMemoUseCase internal constructor(private val repository: Memo }.map { it.copy( memo = - it.memo.copy( - title = - it.memo.title.ifBlank { - val origin = originMap[it.memo.id] ?: throw TagTitleBlankException() - origin.title - }, - ), + it.memo.copy( + title = + it.memo.title.ifBlank { + val origin = originMap[it.memo.id] ?: throw TagTitleBlankException() + origin.title + }, + ), ) } diff --git a/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FetchTagUseCase.kt b/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FetchTagUseCase.kt index 42baa61e..9c813172 100644 --- a/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FetchTagUseCase.kt +++ b/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/FetchTagUseCase.kt @@ -13,7 +13,9 @@ import org.koin.core.annotation.Factory @OptIn(ExperimentalCoroutinesApi::class) @Factory -public class FetchTagUseCase internal constructor(private val repository: TagRepository) { +public class FetchTagUseCase internal constructor( + private val repository: TagRepository, +) { public operator fun invoke(uid: String, updateAt: Instant): Flow>> = flow { emitAll(repository.findByUpdateAt(uid, updateAt)) } .mapLatest { Result.success(it) } diff --git a/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpsertTagUseCase.kt b/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpsertTagUseCase.kt index a087b4bd..7363c101 100644 --- a/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpsertTagUseCase.kt +++ b/server/domain/tag/src/main/kotlin/io/github/taetae98coding/diary/domain/tag/usecase/UpsertTagUseCase.kt @@ -7,7 +7,9 @@ import kotlinx.coroutines.flow.first import org.koin.core.annotation.Factory @Factory -public class UpsertTagUseCase internal constructor(private val repository: TagRepository) { +public class UpsertTagUseCase internal constructor( + private val repository: TagRepository, +) { public suspend operator fun invoke(list: List): Result { return runCatching { // TODO Permission Check @@ -26,10 +28,10 @@ public class UpsertTagUseCase internal constructor(private val repository: TagRe }.map { it.copy( title = - it.title.ifBlank { - val origin = originMap[it.id] ?: throw TagTitleBlankException() - origin.title - }, + it.title.ifBlank { + val origin = originMap[it.id] ?: throw TagTitleBlankException() + origin.title + }, ) }