From f2bef5cd3642ada055068855c2e470f410edf958 Mon Sep 17 00:00:00 2001 From: SeHun <81347125+s9hn@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:59:48 +0900 Subject: [PATCH] =?UTF-8?q?[Feature/#869]=20=EC=98=A4=EB=8A=98=EC=9D=98=20?= =?UTF-8?q?=EC=86=9D=EB=A7=88=EB=94=94=20=EB=8C=80=EC=8B=9C=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#880)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: TodayFortuneBox 구현 * feat: 오늘의 운세(TodayFortuneDashboard) UI 구현 * feat: FortuneDetailRoute, FortuneDetailScreen 파일 분리 * refactor: 패키지 네이밍 수정 * feat: fortune 데이터레이어 구현 - di 모듈 추가 - network api 구현 * feat: fortune 도메인레이어 구현, internal 키워드 일괄 적용 - mapper 구현 - 레포지토리 인터페이스 생성 및 적용 - 힐트모듈 수정 * refactor: internal 키워드 삭제 * refactor: 함수 네이밍 수정 * feat: 레이어 의존성 추가 * refactor: 네트워크 path 수정 * feat: 네트워크 통신 구현 및 state 적용 * feat: 오늘의 솝마디 관련 유즈케이스 생성 * refactor: TodayFortuneBox 패딩값 추가 * refactor: 타입 및 네이밍 수정 * refactor: internal 추가 * test: FortuneDetailScreenTest 구현 * refactor: SimpleDataFormatter로 리팩터링 * refactor: Timber 적용 * build: 의존성 수정 * refactor: break strategy 적용 * fix(deps): update dependency com.tbuonomo:dotsindicator to v5.1.0 (#878) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * build: baseline&spotless 적용 --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 + .../baselineProfiles/baseline-prof.txt | 19 ++-- .../baselineProfiles/startup-prof.txt | 19 ++-- data/fortune/.gitignore | 1 + data/fortune/build.gradle.kts | 40 +++++++ data/fortune/consumer-rules.pro | 0 data/fortune/src/main/AndroidManifest.xml | 27 +++++ .../official/data/fortune/di/ApiModule.kt | 44 ++++++++ .../data/fortune/di/RepositoryModule.kt | 42 ++++++++ .../data/fortune/mapper/FortuneMapper.kt | 42 ++++++++ .../data/fortune/remote/api/FortuneApi.kt | 41 +++++++ .../response/TodayFortuneCardResponse.kt | 40 +++++++ .../response/TodayFortuneWordResponse.kt | 36 +++++++ .../repository/DefaultFortuneRepository.kt | 41 +++++++ domain/fortune/.gitignore | 1 + domain/fortune/build.gradle.kts | 36 +++++++ .../domain/fortune/model/TodayFortuneCard.kt | 32 ++++++ .../domain/fortune/model/TodayFortuneWord.kt | 30 ++++++ .../fortune/repository/FortuneRepository.kt | 33 ++++++ .../fortune/usecase/GetTodayDateUseCase.kt | 38 +++++++ .../fortune/usecase/GetTodayFortuneUseCase.kt | 37 +++++++ feature/fortune/build.gradle.kts | 4 + .../fortuneDetail/FortuneDetailScreenTest.kt | 78 ++++++++++++++ .../feature/fortune/FoundationScreen.kt | 4 +- .../fortuneDetail/FortuneDetailRoute.kt | 48 +++++++++ .../FortuneDetailScreen.kt | 69 ++++++------ .../fortuneDetail/FortuneDetailViewModel.kt | 67 ++++++++++++ .../component/FortuneDetailBox.kt | 67 ++++++++++++ .../component/TodayFortuneDashboard.kt | 100 ++++++++++++++++++ .../model/FortuneDetailUiState.kt | 47 ++++++++ .../navigation/FortuneDetailNavGraph.kt | 6 +- .../feature/home/navigation/HomeNavGraph.kt | 3 +- .../feature/mypage/component/MyPageSection.kt | 2 +- gradle/libs.versions.toml | 2 +- settings.gradle.kts | 2 + 35 files changed, 1032 insertions(+), 68 deletions(-) create mode 100644 data/fortune/.gitignore create mode 100644 data/fortune/build.gradle.kts create mode 100644 data/fortune/consumer-rules.pro create mode 100644 data/fortune/src/main/AndroidManifest.xml create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/di/ApiModule.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/di/RepositoryModule.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/mapper/FortuneMapper.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/remote/api/FortuneApi.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneCardResponse.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneWordResponse.kt create mode 100644 data/fortune/src/main/java/org/sopt/official/data/fortune/repository/DefaultFortuneRepository.kt create mode 100644 domain/fortune/.gitignore create mode 100644 domain/fortune/build.gradle.kts create mode 100644 domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneCard.kt create mode 100644 domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneWord.kt create mode 100644 domain/fortune/src/main/java/org/sopt/official/domain/fortune/repository/FortuneRepository.kt create mode 100644 domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayDateUseCase.kt create mode 100644 domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayFortuneUseCase.kt create mode 100644 feature/fortune/src/androidTest/java/org/sopt/official/feature/fortune/fortuneDetail/FortuneDetailScreenTest.kt create mode 100644 feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailRoute.kt rename feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/{fortundDetail => fortuneDetail}/FortuneDetailScreen.kt (55%) create mode 100644 feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel.kt create mode 100644 feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/FortuneDetailBox.kt create mode 100644 feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/TodayFortuneDashboard.kt create mode 100644 feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/model/FortuneDetailUiState.kt rename feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/{fortundDetail => fortuneDetail}/navigation/FortuneDetailNavGraph.kt (90%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 29b900515..5c5663364 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -117,8 +117,10 @@ dependencies { implementation(projects.domain.soptamp) implementation(projects.domain.mypage) implementation(projects.domain.poke) + implementation(projects.domain.fortune) implementation(projects.domain.notification) implementation(projects.feature.soptamp) + implementation(projects.data.fortune) implementation(projects.data.soptamp) implementation(projects.data.mypage) implementation(projects.data.poke) diff --git a/app/src/release/generated/baselineProfiles/baseline-prof.txt b/app/src/release/generated/baselineProfiles/baseline-prof.txt index 668f43d51..b1d8dc4ac 100644 --- a/app/src/release/generated/baselineProfiles/baseline-prof.txt +++ b/app/src/release/generated/baselineProfiles/baseline-prof.txt @@ -525,7 +525,6 @@ Landroidx/arch/core/internal/SafeIterableMap$SupportRemove; HSPLandroidx/arch/core/internal/SafeIterableMap$SupportRemove;->()V Landroidx/collection/ArrayMap; HSPLandroidx/collection/ArrayMap;->()V -HSPLandroidx/collection/ArrayMap;->(I)V HSPLandroidx/collection/ArrayMap;->containsKey(Ljava/lang/Object;)Z HSPLandroidx/collection/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/collection/ArrayMap;->keySet()Ljava/util/Set; @@ -3458,7 +3457,6 @@ HSPLcom/google/android/gms/common/internal/BaseGmsClient;->getUseDynamicLookup() HSPLcom/google/android/gms/common/internal/BaseGmsClient;->isConnected()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->isConnecting()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->onConnectedLocked(Landroid/os/IInterface;)V -PLcom/google/android/gms/common/internal/BaseGmsClient;->onConnectionSuspended(I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->onPostInitHandler(ILandroid/os/IBinder;Landroid/os/Bundle;I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->requiresAccount()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->requiresSignIn()Z @@ -3469,7 +3467,6 @@ HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zze()Ljava/lang/Strin HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzf(Lcom/google/android/gms/common/internal/BaseGmsClient;)Ljava/util/ArrayList; HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzg(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/ConnectionResult;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzh(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/internal/IGmsServiceBroker;)V -PLcom/google/android/gms/common/internal/BaseGmsClient;->zzi(Lcom/google/android/gms/common/internal/BaseGmsClient;ILandroid/os/IInterface;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzj(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/internal/zzk;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzl(ILandroid/os/Bundle;I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzn(Lcom/google/android/gms/common/internal/BaseGmsClient;IILandroid/os/IInterface;)Z @@ -3489,7 +3486,6 @@ Lcom/google/android/gms/common/internal/GmsClientSupervisor; HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->()V HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->()V HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->getInstance(Landroid/content/Context;)Lcom/google/android/gms/common/internal/GmsClientSupervisor; -PLcom/google/android/gms/common/internal/GmsClientSupervisor;->zzb(Ljava/lang/String;Ljava/lang/String;ILandroid/content/ServiceConnection;Ljava/lang/String;Z)V Lcom/google/android/gms/common/internal/IGmsCallbacks; Lcom/google/android/gms/common/internal/IGmsServiceBroker; Lcom/google/android/gms/common/internal/Objects; @@ -3581,7 +3577,6 @@ HSPLcom/google/android/gms/common/internal/zzd;->zzc(ILandroid/os/IBinder;Lcom/g Lcom/google/android/gms/common/internal/zze; HSPLcom/google/android/gms/common/internal/zze;->(Lcom/google/android/gms/common/internal/BaseGmsClient;I)V HSPLcom/google/android/gms/common/internal/zze;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V -PLcom/google/android/gms/common/internal/zze;->onServiceDisconnected(Landroid/content/ComponentName;)V Lcom/google/android/gms/common/internal/zzf; HSPLcom/google/android/gms/common/internal/zzf;->(Lcom/google/android/gms/common/internal/BaseGmsClient;ILandroid/os/IBinder;Landroid/os/Bundle;)V HSPLcom/google/android/gms/common/internal/zzf;->zzd()Z @@ -3606,8 +3601,6 @@ HSPLcom/google/android/gms/common/internal/zzo;->zzb(Landroid/content/Context;)L Lcom/google/android/gms/common/internal/zzp; HSPLcom/google/android/gms/common/internal/zzp;->(Lcom/google/android/gms/common/internal/zzs;Lcom/google/android/gms/common/internal/zzo;)V HSPLcom/google/android/gms/common/internal/zzp;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V -PLcom/google/android/gms/common/internal/zzp;->onServiceDisconnected(Landroid/content/ComponentName;)V -PLcom/google/android/gms/common/internal/zzp;->zza()I HSPLcom/google/android/gms/common/internal/zzp;->zzd(Landroid/content/ServiceConnection;Landroid/content/ServiceConnection;Ljava/lang/String;)V HSPLcom/google/android/gms/common/internal/zzp;->zze(Ljava/lang/String;Ljava/util/concurrent/Executor;)V PLcom/google/android/gms/common/internal/zzp;->zzf(Landroid/content/ServiceConnection;Ljava/lang/String;)V @@ -3956,9 +3949,11 @@ HSPLcom/google/android/gms/internal/measurement/zzic;->zza()Ljava/util/Map; HSPLcom/google/android/gms/internal/measurement/zzic;->zza(Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/Runnable;)Lcom/google/android/gms/internal/measurement/zzic; HSPLcom/google/android/gms/internal/measurement/zzic;->zza(Ljava/lang/String;)Ljava/lang/Object; HSPLcom/google/android/gms/internal/measurement/zzic;->zzb()Ljava/util/Map; +HSPLcom/google/android/gms/internal/measurement/zzic;->zzd()V HSPLcom/google/android/gms/internal/measurement/zzic;->zze()Ljava/util/Map; Lcom/google/android/gms/internal/measurement/zzie; HSPLcom/google/android/gms/internal/measurement/zzie;->(Lcom/google/android/gms/internal/measurement/zzic;Landroid/os/Handler;)V +HSPLcom/google/android/gms/internal/measurement/zzie;->onChange(Z)V Lcom/google/android/gms/internal/measurement/zzif; Lcom/google/android/gms/internal/measurement/zzih; Lcom/google/android/gms/internal/measurement/zzii; @@ -3981,6 +3976,7 @@ HSPLcom/google/android/gms/internal/measurement/zzip;->zza(Landroid/content/Cont HSPLcom/google/android/gms/internal/measurement/zzip;->zza(Landroid/content/Context;Landroid/net/Uri;)Z Lcom/google/android/gms/internal/measurement/zziq; HSPLcom/google/android/gms/internal/measurement/zziq;->()V +HSPLcom/google/android/gms/internal/measurement/zziq;->run()V Lcom/google/android/gms/internal/measurement/zzir; HSPLcom/google/android/gms/internal/measurement/zzir;->()V HSPLcom/google/android/gms/internal/measurement/zzir;->(Lcom/google/android/gms/internal/measurement/zziz;Ljava/lang/String;Ljava/lang/Object;Z)V @@ -3996,6 +3992,7 @@ HSPLcom/google/android/gms/internal/measurement/zzir;->zza(Ljava/lang/String;)Lj HSPLcom/google/android/gms/internal/measurement/zzir;->zzb()Ljava/lang/String; HSPLcom/google/android/gms/internal/measurement/zzir;->zzb(Landroid/content/Context;)V HSPLcom/google/android/gms/internal/measurement/zzir;->zzb(Lcom/google/android/gms/internal/measurement/zziy;)Ljava/lang/Object; +HSPLcom/google/android/gms/internal/measurement/zzir;->zzc()V HSPLcom/google/android/gms/internal/measurement/zzir;->zzd()Z HSPLcom/google/android/gms/internal/measurement/zzir;->zze()Ljava/lang/Object; Lcom/google/android/gms/internal/measurement/zzis; @@ -4920,7 +4917,6 @@ HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/g HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzgb;Lcom/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable;Lcom/google/android/gms/measurement/internal/zzp;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlh;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlp;)Lcom/google/android/gms/measurement/internal/zzgb; -PLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlp;Landroid/content/ComponentName;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzok;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Ljava/lang/Runnable;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Ljava/util/concurrent/atomic/AtomicReference;)V @@ -4970,12 +4966,9 @@ HSPLcom/google/android/gms/measurement/internal/zzmj;->run()V Lcom/google/android/gms/measurement/internal/zzmm; HSPLcom/google/android/gms/measurement/internal/zzmm;->(Lcom/google/android/gms/measurement/internal/zzlp;)V HSPLcom/google/android/gms/measurement/internal/zzmm;->onConnected(Landroid/os/Bundle;)V -PLcom/google/android/gms/measurement/internal/zzmm;->onConnectionSuspended(I)V HSPLcom/google/android/gms/measurement/internal/zzmm;->zza()V HSPLcom/google/android/gms/measurement/internal/zzmm;->zza(Lcom/google/android/gms/measurement/internal/zzmm;Z)V PLcom/google/android/gms/measurement/internal/zzmm;->zzb()V -PLcom/google/android/gms/measurement/internal/zzmq;->(Lcom/google/android/gms/measurement/internal/zzmm;)V -PLcom/google/android/gms/measurement/internal/zzmq;->run()V Lcom/google/android/gms/measurement/internal/zzmr; HSPLcom/google/android/gms/measurement/internal/zzmr;->(Lcom/google/android/gms/measurement/internal/zzmm;Lcom/google/android/gms/measurement/internal/zzgb;)V HSPLcom/google/android/gms/measurement/internal/zzmr;->run()V @@ -8011,7 +8004,9 @@ Lkotlin/Result$Companion; HSPLkotlin/Result$Companion;->()V HSPLkotlin/Result$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V Lkotlin/Result$Failure; +HSPLkotlin/Result$Failure;->(Ljava/lang/Throwable;)V Lkotlin/ResultKt; +HSPLkotlin/ResultKt;->createFailure(Ljava/lang/Throwable;)Ljava/lang/Object; HSPLkotlin/ResultKt;->throwOnFailure(Ljava/lang/Object;)V Lkotlin/SynchronizedLazyImpl; HSPLkotlin/SynchronizedLazyImpl;->(Lkotlin/jvm/functions/Function0;Ljava/lang/Object;)V @@ -10301,6 +10296,8 @@ Lorg/sopt/official/feature/auth/Hilt_AuthActivity$1; HSPLorg/sopt/official/feature/auth/Hilt_AuthActivity$1;->(Lorg/sopt/official/feature/auth/Hilt_AuthActivity;)V HSPLorg/sopt/official/feature/auth/Hilt_AuthActivity$1;->onContextAvailable(Landroid/content/Context;)V Lorg/sopt/official/feature/fortune/FortuneActivity_GeneratedInjector; +Lorg/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel_HiltModules$KeyModule; +HSPLorg/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel_HiltModules$KeyModule;->provide()Z Lorg/sopt/official/feature/home/HomeActivity_GeneratedInjector; Lorg/sopt/official/feature/home/HomeViewModel_HiltModules$KeyModule; HSPLorg/sopt/official/feature/home/HomeViewModel_HiltModules$KeyModule;->provide()Z diff --git a/app/src/release/generated/baselineProfiles/startup-prof.txt b/app/src/release/generated/baselineProfiles/startup-prof.txt index 668f43d51..b1d8dc4ac 100644 --- a/app/src/release/generated/baselineProfiles/startup-prof.txt +++ b/app/src/release/generated/baselineProfiles/startup-prof.txt @@ -525,7 +525,6 @@ Landroidx/arch/core/internal/SafeIterableMap$SupportRemove; HSPLandroidx/arch/core/internal/SafeIterableMap$SupportRemove;->()V Landroidx/collection/ArrayMap; HSPLandroidx/collection/ArrayMap;->()V -HSPLandroidx/collection/ArrayMap;->(I)V HSPLandroidx/collection/ArrayMap;->containsKey(Ljava/lang/Object;)Z HSPLandroidx/collection/ArrayMap;->get(Ljava/lang/Object;)Ljava/lang/Object; HSPLandroidx/collection/ArrayMap;->keySet()Ljava/util/Set; @@ -3458,7 +3457,6 @@ HSPLcom/google/android/gms/common/internal/BaseGmsClient;->getUseDynamicLookup() HSPLcom/google/android/gms/common/internal/BaseGmsClient;->isConnected()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->isConnecting()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->onConnectedLocked(Landroid/os/IInterface;)V -PLcom/google/android/gms/common/internal/BaseGmsClient;->onConnectionSuspended(I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->onPostInitHandler(ILandroid/os/IBinder;Landroid/os/Bundle;I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->requiresAccount()Z HSPLcom/google/android/gms/common/internal/BaseGmsClient;->requiresSignIn()Z @@ -3469,7 +3467,6 @@ HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zze()Ljava/lang/Strin HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzf(Lcom/google/android/gms/common/internal/BaseGmsClient;)Ljava/util/ArrayList; HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzg(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/ConnectionResult;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzh(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/internal/IGmsServiceBroker;)V -PLcom/google/android/gms/common/internal/BaseGmsClient;->zzi(Lcom/google/android/gms/common/internal/BaseGmsClient;ILandroid/os/IInterface;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzj(Lcom/google/android/gms/common/internal/BaseGmsClient;Lcom/google/android/gms/common/internal/zzk;)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzl(ILandroid/os/Bundle;I)V HSPLcom/google/android/gms/common/internal/BaseGmsClient;->zzn(Lcom/google/android/gms/common/internal/BaseGmsClient;IILandroid/os/IInterface;)Z @@ -3489,7 +3486,6 @@ Lcom/google/android/gms/common/internal/GmsClientSupervisor; HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->()V HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->()V HSPLcom/google/android/gms/common/internal/GmsClientSupervisor;->getInstance(Landroid/content/Context;)Lcom/google/android/gms/common/internal/GmsClientSupervisor; -PLcom/google/android/gms/common/internal/GmsClientSupervisor;->zzb(Ljava/lang/String;Ljava/lang/String;ILandroid/content/ServiceConnection;Ljava/lang/String;Z)V Lcom/google/android/gms/common/internal/IGmsCallbacks; Lcom/google/android/gms/common/internal/IGmsServiceBroker; Lcom/google/android/gms/common/internal/Objects; @@ -3581,7 +3577,6 @@ HSPLcom/google/android/gms/common/internal/zzd;->zzc(ILandroid/os/IBinder;Lcom/g Lcom/google/android/gms/common/internal/zze; HSPLcom/google/android/gms/common/internal/zze;->(Lcom/google/android/gms/common/internal/BaseGmsClient;I)V HSPLcom/google/android/gms/common/internal/zze;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V -PLcom/google/android/gms/common/internal/zze;->onServiceDisconnected(Landroid/content/ComponentName;)V Lcom/google/android/gms/common/internal/zzf; HSPLcom/google/android/gms/common/internal/zzf;->(Lcom/google/android/gms/common/internal/BaseGmsClient;ILandroid/os/IBinder;Landroid/os/Bundle;)V HSPLcom/google/android/gms/common/internal/zzf;->zzd()Z @@ -3606,8 +3601,6 @@ HSPLcom/google/android/gms/common/internal/zzo;->zzb(Landroid/content/Context;)L Lcom/google/android/gms/common/internal/zzp; HSPLcom/google/android/gms/common/internal/zzp;->(Lcom/google/android/gms/common/internal/zzs;Lcom/google/android/gms/common/internal/zzo;)V HSPLcom/google/android/gms/common/internal/zzp;->onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V -PLcom/google/android/gms/common/internal/zzp;->onServiceDisconnected(Landroid/content/ComponentName;)V -PLcom/google/android/gms/common/internal/zzp;->zza()I HSPLcom/google/android/gms/common/internal/zzp;->zzd(Landroid/content/ServiceConnection;Landroid/content/ServiceConnection;Ljava/lang/String;)V HSPLcom/google/android/gms/common/internal/zzp;->zze(Ljava/lang/String;Ljava/util/concurrent/Executor;)V PLcom/google/android/gms/common/internal/zzp;->zzf(Landroid/content/ServiceConnection;Ljava/lang/String;)V @@ -3956,9 +3949,11 @@ HSPLcom/google/android/gms/internal/measurement/zzic;->zza()Ljava/util/Map; HSPLcom/google/android/gms/internal/measurement/zzic;->zza(Landroid/content/ContentResolver;Landroid/net/Uri;Ljava/lang/Runnable;)Lcom/google/android/gms/internal/measurement/zzic; HSPLcom/google/android/gms/internal/measurement/zzic;->zza(Ljava/lang/String;)Ljava/lang/Object; HSPLcom/google/android/gms/internal/measurement/zzic;->zzb()Ljava/util/Map; +HSPLcom/google/android/gms/internal/measurement/zzic;->zzd()V HSPLcom/google/android/gms/internal/measurement/zzic;->zze()Ljava/util/Map; Lcom/google/android/gms/internal/measurement/zzie; HSPLcom/google/android/gms/internal/measurement/zzie;->(Lcom/google/android/gms/internal/measurement/zzic;Landroid/os/Handler;)V +HSPLcom/google/android/gms/internal/measurement/zzie;->onChange(Z)V Lcom/google/android/gms/internal/measurement/zzif; Lcom/google/android/gms/internal/measurement/zzih; Lcom/google/android/gms/internal/measurement/zzii; @@ -3981,6 +3976,7 @@ HSPLcom/google/android/gms/internal/measurement/zzip;->zza(Landroid/content/Cont HSPLcom/google/android/gms/internal/measurement/zzip;->zza(Landroid/content/Context;Landroid/net/Uri;)Z Lcom/google/android/gms/internal/measurement/zziq; HSPLcom/google/android/gms/internal/measurement/zziq;->()V +HSPLcom/google/android/gms/internal/measurement/zziq;->run()V Lcom/google/android/gms/internal/measurement/zzir; HSPLcom/google/android/gms/internal/measurement/zzir;->()V HSPLcom/google/android/gms/internal/measurement/zzir;->(Lcom/google/android/gms/internal/measurement/zziz;Ljava/lang/String;Ljava/lang/Object;Z)V @@ -3996,6 +3992,7 @@ HSPLcom/google/android/gms/internal/measurement/zzir;->zza(Ljava/lang/String;)Lj HSPLcom/google/android/gms/internal/measurement/zzir;->zzb()Ljava/lang/String; HSPLcom/google/android/gms/internal/measurement/zzir;->zzb(Landroid/content/Context;)V HSPLcom/google/android/gms/internal/measurement/zzir;->zzb(Lcom/google/android/gms/internal/measurement/zziy;)Ljava/lang/Object; +HSPLcom/google/android/gms/internal/measurement/zzir;->zzc()V HSPLcom/google/android/gms/internal/measurement/zzir;->zzd()Z HSPLcom/google/android/gms/internal/measurement/zzir;->zze()Ljava/lang/Object; Lcom/google/android/gms/internal/measurement/zzis; @@ -4920,7 +4917,6 @@ HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/g HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzgb;Lcom/google/android/gms/common/internal/safeparcel/AbstractSafeParcelable;Lcom/google/android/gms/measurement/internal/zzp;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlh;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlp;)Lcom/google/android/gms/measurement/internal/zzgb; -PLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzlp;Landroid/content/ComponentName;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Lcom/google/android/gms/measurement/internal/zzok;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Ljava/lang/Runnable;)V HSPLcom/google/android/gms/measurement/internal/zzlp;->zza(Ljava/util/concurrent/atomic/AtomicReference;)V @@ -4970,12 +4966,9 @@ HSPLcom/google/android/gms/measurement/internal/zzmj;->run()V Lcom/google/android/gms/measurement/internal/zzmm; HSPLcom/google/android/gms/measurement/internal/zzmm;->(Lcom/google/android/gms/measurement/internal/zzlp;)V HSPLcom/google/android/gms/measurement/internal/zzmm;->onConnected(Landroid/os/Bundle;)V -PLcom/google/android/gms/measurement/internal/zzmm;->onConnectionSuspended(I)V HSPLcom/google/android/gms/measurement/internal/zzmm;->zza()V HSPLcom/google/android/gms/measurement/internal/zzmm;->zza(Lcom/google/android/gms/measurement/internal/zzmm;Z)V PLcom/google/android/gms/measurement/internal/zzmm;->zzb()V -PLcom/google/android/gms/measurement/internal/zzmq;->(Lcom/google/android/gms/measurement/internal/zzmm;)V -PLcom/google/android/gms/measurement/internal/zzmq;->run()V Lcom/google/android/gms/measurement/internal/zzmr; HSPLcom/google/android/gms/measurement/internal/zzmr;->(Lcom/google/android/gms/measurement/internal/zzmm;Lcom/google/android/gms/measurement/internal/zzgb;)V HSPLcom/google/android/gms/measurement/internal/zzmr;->run()V @@ -8011,7 +8004,9 @@ Lkotlin/Result$Companion; HSPLkotlin/Result$Companion;->()V HSPLkotlin/Result$Companion;->(Lkotlin/jvm/internal/DefaultConstructorMarker;)V Lkotlin/Result$Failure; +HSPLkotlin/Result$Failure;->(Ljava/lang/Throwable;)V Lkotlin/ResultKt; +HSPLkotlin/ResultKt;->createFailure(Ljava/lang/Throwable;)Ljava/lang/Object; HSPLkotlin/ResultKt;->throwOnFailure(Ljava/lang/Object;)V Lkotlin/SynchronizedLazyImpl; HSPLkotlin/SynchronizedLazyImpl;->(Lkotlin/jvm/functions/Function0;Ljava/lang/Object;)V @@ -10301,6 +10296,8 @@ Lorg/sopt/official/feature/auth/Hilt_AuthActivity$1; HSPLorg/sopt/official/feature/auth/Hilt_AuthActivity$1;->(Lorg/sopt/official/feature/auth/Hilt_AuthActivity;)V HSPLorg/sopt/official/feature/auth/Hilt_AuthActivity$1;->onContextAvailable(Landroid/content/Context;)V Lorg/sopt/official/feature/fortune/FortuneActivity_GeneratedInjector; +Lorg/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel_HiltModules$KeyModule; +HSPLorg/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel_HiltModules$KeyModule;->provide()Z Lorg/sopt/official/feature/home/HomeActivity_GeneratedInjector; Lorg/sopt/official/feature/home/HomeViewModel_HiltModules$KeyModule; HSPLorg/sopt/official/feature/home/HomeViewModel_HiltModules$KeyModule;->provide()Z diff --git a/data/fortune/.gitignore b/data/fortune/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/data/fortune/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/data/fortune/build.gradle.kts b/data/fortune/build.gradle.kts new file mode 100644 index 000000000..d16316277 --- /dev/null +++ b/data/fortune/build.gradle.kts @@ -0,0 +1,40 @@ +/* + * MIT License + * Copyright 2023-2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + sopt("feature") +} + +android { + namespace = "org.sopt.official.data.fortune" +} + +dependencies { + implementation(projects.domain.fortune) + implementation(projects.core.network) + implementation(projects.core.common) + implementation(platform(libs.okhttp.bom)) + implementation(libs.bundles.okhttp) +} diff --git a/data/fortune/consumer-rules.pro b/data/fortune/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/data/fortune/src/main/AndroidManifest.xml b/data/fortune/src/main/AndroidManifest.xml new file mode 100644 index 000000000..6e03b9302 --- /dev/null +++ b/data/fortune/src/main/AndroidManifest.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/di/ApiModule.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/di/ApiModule.kt new file mode 100644 index 000000000..133612b8b --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/di/ApiModule.kt @@ -0,0 +1,44 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.di + +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.sopt.official.common.di.AppRetrofit +import org.sopt.official.data.fortune.remote.api.FortuneApi +import retrofit2.Retrofit +import retrofit2.create +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object ApiModule { + + @Provides + @Singleton + internal fun provideFortuneApi(@AppRetrofit(true) retrofit: Retrofit): FortuneApi = retrofit.create() +} diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/di/RepositoryModule.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/di/RepositoryModule.kt new file mode 100644 index 000000000..d6283fb0a --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/di/RepositoryModule.kt @@ -0,0 +1,42 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import org.sopt.official.data.fortune.repository.DefaultFortuneRepository +import org.sopt.official.domain.fortune.repository.FortuneRepository +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal interface RepositoryModule { + + @Binds + @Singleton + abstract fun bindDefaultFortuneRepository(defaultFortuneRepository: DefaultFortuneRepository): FortuneRepository +} diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/mapper/FortuneMapper.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/mapper/FortuneMapper.kt new file mode 100644 index 000000000..8e1673477 --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/mapper/FortuneMapper.kt @@ -0,0 +1,42 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.mapper + +import org.sopt.official.data.fortune.remote.response.TodayFortuneCardResponse +import org.sopt.official.data.fortune.remote.response.TodayFortuneWordResponse +import org.sopt.official.domain.fortune.model.TodayFortuneCard +import org.sopt.official.domain.fortune.model.TodayFortuneWord + +internal fun TodayFortuneCardResponse.toDomain(): TodayFortuneCard = TodayFortuneCard( + description = description, + imageColorCode = imageColorCode, + imageUrl = imageUrl, + name = name, +) + +internal fun TodayFortuneWordResponse.toDomain(): TodayFortuneWord = TodayFortuneWord( + userName = userName, + title = title, +) diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/api/FortuneApi.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/api/FortuneApi.kt new file mode 100644 index 000000000..2898bce3c --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/api/FortuneApi.kt @@ -0,0 +1,41 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.remote.api + +import org.sopt.official.data.fortune.remote.response.TodayFortuneCardResponse +import org.sopt.official.data.fortune.remote.response.TodayFortuneWordResponse +import retrofit2.http.GET +import retrofit2.http.Query + +internal interface FortuneApi { + + @GET("fortune/word") + suspend fun getTodayFortuneWord( + @Query("todayDate") todayDate: String, + ): TodayFortuneWordResponse + + @GET("fortune/card/today") + suspend fun getTodayFortuneCard(): TodayFortuneCardResponse +} diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneCardResponse.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneCardResponse.kt new file mode 100644 index 000000000..56a68179d --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneCardResponse.kt @@ -0,0 +1,40 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.remote.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +internal data class TodayFortuneCardResponse( + @SerialName("description") + val description: String, + @SerialName("imageColorCode") + val imageColorCode: String, + @SerialName("imageUrl") + val imageUrl: String, + @SerialName("name") + val name: String, +) diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneWordResponse.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneWordResponse.kt new file mode 100644 index 000000000..1882c5bea --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/remote/response/TodayFortuneWordResponse.kt @@ -0,0 +1,36 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.remote.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +internal data class TodayFortuneWordResponse( + @SerialName("userName") + val userName: String, + @SerialName("title") + val title: String, +) diff --git a/data/fortune/src/main/java/org/sopt/official/data/fortune/repository/DefaultFortuneRepository.kt b/data/fortune/src/main/java/org/sopt/official/data/fortune/repository/DefaultFortuneRepository.kt new file mode 100644 index 000000000..77a64c995 --- /dev/null +++ b/data/fortune/src/main/java/org/sopt/official/data/fortune/repository/DefaultFortuneRepository.kt @@ -0,0 +1,41 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.data.fortune.repository + +import org.sopt.official.data.fortune.mapper.toDomain +import org.sopt.official.data.fortune.remote.api.FortuneApi +import org.sopt.official.domain.fortune.model.TodayFortuneCard +import org.sopt.official.domain.fortune.model.TodayFortuneWord +import org.sopt.official.domain.fortune.repository.FortuneRepository +import javax.inject.Inject + +internal class DefaultFortuneRepository @Inject constructor( + private val fortuneApi: FortuneApi, +) : FortuneRepository { + + override suspend fun fetchTodayFortuneWord(date: String): TodayFortuneWord = fortuneApi.getTodayFortuneWord(date).toDomain() + + override suspend fun fetchTodayFortuneCard(): TodayFortuneCard = fortuneApi.getTodayFortuneCard().toDomain() +} diff --git a/domain/fortune/.gitignore b/domain/fortune/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/domain/fortune/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/domain/fortune/build.gradle.kts b/domain/fortune/build.gradle.kts new file mode 100644 index 000000000..0adbfe1a8 --- /dev/null +++ b/domain/fortune/build.gradle.kts @@ -0,0 +1,36 @@ +/* + * MIT License + * Copyright 2023-2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +plugins { + sopt("kotlin") +} + +kotlin { + jvmToolchain(17) +} + +dependencies { + implementation(libs.javax.inject) +} diff --git a/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneCard.kt b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneCard.kt new file mode 100644 index 000000000..58393fc65 --- /dev/null +++ b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneCard.kt @@ -0,0 +1,32 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.domain.fortune.model + +data class TodayFortuneCard( + val description: String, + val imageColorCode: String, + val imageUrl: String, + val name: String, +) diff --git a/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneWord.kt b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneWord.kt new file mode 100644 index 000000000..88d6b3128 --- /dev/null +++ b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/model/TodayFortuneWord.kt @@ -0,0 +1,30 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.domain.fortune.model + +data class TodayFortuneWord( + val userName: String, + val title: String, +) diff --git a/domain/fortune/src/main/java/org/sopt/official/domain/fortune/repository/FortuneRepository.kt b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/repository/FortuneRepository.kt new file mode 100644 index 000000000..8d38c7b58 --- /dev/null +++ b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/repository/FortuneRepository.kt @@ -0,0 +1,33 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.domain.fortune.repository + +import org.sopt.official.domain.fortune.model.TodayFortuneCard +import org.sopt.official.domain.fortune.model.TodayFortuneWord + +interface FortuneRepository { + suspend fun fetchTodayFortuneWord(date: String): TodayFortuneWord + suspend fun fetchTodayFortuneCard(): TodayFortuneCard +} diff --git a/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayDateUseCase.kt b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayDateUseCase.kt new file mode 100644 index 000000000..dd8747fad --- /dev/null +++ b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayDateUseCase.kt @@ -0,0 +1,38 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.domain.fortune.usecase + +import java.text.SimpleDateFormat +import java.util.Locale +import javax.inject.Inject + +class GetTodayDateUseCase @Inject constructor() { + + operator fun invoke(): String { + val currentDate = System.currentTimeMillis() + + return SimpleDateFormat("yyyy-MM-dd", Locale.KOREAN).format(currentDate) + } +} diff --git a/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayFortuneUseCase.kt b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayFortuneUseCase.kt new file mode 100644 index 000000000..b8f8ff159 --- /dev/null +++ b/domain/fortune/src/main/java/org/sopt/official/domain/fortune/usecase/GetTodayFortuneUseCase.kt @@ -0,0 +1,37 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.domain.fortune.usecase + +import org.sopt.official.domain.fortune.model.TodayFortuneWord +import org.sopt.official.domain.fortune.repository.FortuneRepository +import javax.inject.Inject + +class GetTodayFortuneUseCase @Inject constructor( + private val fortuneRepository: FortuneRepository, + private val getTodayDateUseCase: GetTodayDateUseCase, +) { + + suspend operator fun invoke(): TodayFortuneWord = fortuneRepository.fetchTodayFortuneWord(getTodayDateUseCase()) +} diff --git a/feature/fortune/build.gradle.kts b/feature/fortune/build.gradle.kts index aba67f215..de172d530 100644 --- a/feature/fortune/build.gradle.kts +++ b/feature/fortune/build.gradle.kts @@ -25,6 +25,7 @@ plugins { sopt("feature") sopt("compose") + sopt("test") } android { @@ -32,6 +33,9 @@ android { } dependencies { + // domain + implementation(projects.domain.fortune) + // core implementation(projects.core.common) implementation(projects.core.designsystem) diff --git a/feature/fortune/src/androidTest/java/org/sopt/official/feature/fortune/fortuneDetail/FortuneDetailScreenTest.kt b/feature/fortune/src/androidTest/java/org/sopt/official/feature/fortune/fortuneDetail/FortuneDetailScreenTest.kt new file mode 100644 index 000000000..879ed5487 --- /dev/null +++ b/feature/fortune/src/androidTest/java/org/sopt/official/feature/fortune/fortuneDetail/FortuneDetailScreenTest.kt @@ -0,0 +1,78 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.fortuneDetail + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.ui.semantics.SemanticsProperties +import androidx.compose.ui.semantics.getOrNull +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import org.junit.Rule +import org.junit.Test +import org.sopt.official.designsystem.SoptTheme +import org.sopt.official.feature.fortune.feature.fortuneDetail.FortuneDetailScreen +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState + +internal class FortuneDetailScreenTest { + + @get:Rule + val composeRule = createComposeRule() + + @Test + fun 서버통신이_성공하면_이름_솝마디_날짜가_노출된다() { + // given: + val date = "2024-09-26" + val name = "이현우" + val content = "안녕하세요안녕하세요안녕하세요안녕하세요안녕하세요" + + // when: + + composeRule.setContent { + SoptTheme { + FortuneDetailScreen( + paddingValue = PaddingValues(), + date = date, + onFortuneAmuletClick = { }, + uiState = FortuneDetailUiState.TodaySentence( + userName = name, + content = content, + ) + ) + } + } + + // then: + val todayFortune = composeRule.onNodeWithContentDescription("todaySentence") + .fetchSemanticsNode().config.getOrNull(SemanticsProperties.Text)?.joinToString(separator = "").orEmpty() + + composeRule.waitForIdle() + + composeRule.onNodeWithText(date).assertIsDisplayed() + assert(todayFortune.contains(name)) + assert(todayFortune.contains(content)) + } +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/FoundationScreen.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/FoundationScreen.kt index 9164495c1..cb155d8f6 100644 --- a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/FoundationScreen.kt +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/FoundationScreen.kt @@ -37,8 +37,8 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController import org.sopt.official.designsystem.SoptTheme import org.sopt.official.feature.fortune.component.FortuneTopBar -import org.sopt.official.feature.fortune.feature.fortundDetail.navigation.FortuneDetail -import org.sopt.official.feature.fortune.feature.fortundDetail.navigation.fortuneDetailNavGraph +import org.sopt.official.feature.fortune.feature.fortuneDetail.navigation.FortuneDetail +import org.sopt.official.feature.fortune.feature.fortuneDetail.navigation.fortuneDetailNavGraph import org.sopt.official.feature.fortune.feature.fortuneAmulet.navigation.FortuneAmulet import org.sopt.official.feature.fortune.feature.fortuneAmulet.navigation.fortuneAmuletNavGraph import org.sopt.official.feature.fortune.feature.home.navigation.Home diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailRoute.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailRoute.kt new file mode 100644 index 000000000..088cf58bf --- /dev/null +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailRoute.kt @@ -0,0 +1,48 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.feature.fortuneDetail + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle + +@Composable +internal fun FortuneDetailRoute( + paddingValue: PaddingValues, + date: String, + onFortuneAmuletClick: () -> Unit, + viewModel: FortuneDetailViewModel = hiltViewModel(), +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + + FortuneDetailScreen( + paddingValue = paddingValue, + date = date, + onFortuneAmuletClick = onFortuneAmuletClick, + uiState = uiState, + ) +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/FortuneDetailScreen.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailScreen.kt similarity index 55% rename from feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/FortuneDetailScreen.kt rename to feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailScreen.kt index c438930af..d8dac0c88 100644 --- a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/FortuneDetailScreen.kt +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailScreen.kt @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package org.sopt.official.feature.fortune.feature.fortundDetail +package org.sopt.official.feature.fortune.feature.fortuneDetail import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues @@ -30,65 +30,60 @@ 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.material3.Button -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.sopt.official.designsystem.SoptTheme +import org.sopt.official.feature.fortune.feature.fortuneDetail.component.TodayFortuneDashboard +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.Error +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.Loading +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.TodaySentence +import timber.log.Timber @Composable -fun FortuneDetailRoute( +internal fun FortuneDetailScreen( paddingValue: PaddingValues, date: String, - navigateToFortuneAmulet: () -> Unit, -) { - FortuneDetailScreen( - paddingValue = paddingValue, - date = date, - navigateToFortuneAmulet = navigateToFortuneAmulet - ) -} - -@Composable -fun FortuneDetailScreen( - paddingValue: PaddingValues, - date: String, - navigateToFortuneAmulet: () -> Unit, + onFortuneAmuletClick: () -> Unit, + modifier: Modifier = Modifier, + uiState: FortuneDetailUiState = Loading, ) { Column( - modifier = Modifier - .padding(paddingValue) - .fillMaxSize(), - horizontalAlignment = Alignment.CenterHorizontally + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier.fillMaxSize().padding(paddingValues = paddingValue), ) { - Text( - text = "Fortune Detail Screen: $date", - color = SoptTheme.colors.onBackground - ) + Spacer(modifier = Modifier.height(height = 16.dp)) + when (uiState) { + is TodaySentence -> { + TodayFortuneDashboard( + date = date, + todaySentence = uiState.message, + ) + } - Spacer(modifier = Modifier.weight(1f)) - - Button( - onClick = navigateToFortuneAmulet - ) { - Text(text = "Go to Fortune Amulet") + is Error -> Timber.e(uiState.errorMessage) + is Loading -> { + // 로딩 뷰 + } } - Spacer(modifier = Modifier.height(50.dp)) } } - @Preview @Composable -fun FortuneDetailScreenPreview() { +private fun FortuneDetailScreenPreview() { SoptTheme { FortuneDetailScreen( - paddingValue = PaddingValues(16.dp), + paddingValue = PaddingValues(vertical = 16.dp), date = "2024-09-09", - navigateToFortuneAmulet = {} + onFortuneAmuletClick = {}, + uiState = TodaySentence( + userName = "누누", + content = "오늘 하루종일 기분 좋을 것 같은 날이네요.", + ), ) } } diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel.kt new file mode 100644 index 000000000..bc860bb77 --- /dev/null +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/FortuneDetailViewModel.kt @@ -0,0 +1,67 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.feature.fortuneDetail + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.sopt.official.domain.fortune.usecase.GetTodayFortuneUseCase +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.Error +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.Loading +import org.sopt.official.feature.fortune.feature.fortuneDetail.model.FortuneDetailUiState.TodaySentence +import javax.inject.Inject + +@HiltViewModel +internal class FortuneDetailViewModel @Inject constructor( + getTodayFortuneUseCase: GetTodayFortuneUseCase, +) : ViewModel() { + private val _uiState: MutableStateFlow = MutableStateFlow(Loading) + val uiState: StateFlow get() = _uiState.asStateFlow() + + init { + viewModelScope.launch { + runCatching { + getTodayFortuneUseCase() + }.onSuccess { result -> + _uiState.update { + TodaySentence( + userName = result.userName, + content = result.title, + ) + } + }.onFailure { error -> + _uiState.update { + Error(error) + } + } + } + } +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/FortuneDetailBox.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/FortuneDetailBox.kt new file mode 100644 index 000000000..d720e9ec6 --- /dev/null +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/FortuneDetailBox.kt @@ -0,0 +1,67 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.feature.fortuneDetail.component + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.official.designsystem.Gray700 + +@Composable +internal fun TodayFortuneBox( + content: @Composable () -> Unit, + modifier: Modifier = Modifier, +) { + Box( + contentAlignment = Alignment.Center, + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 20.dp) + .background( + color = Gray700, + shape = RoundedCornerShape(12.dp), + ), + ) { + content() + } +} + +@Preview(showBackground = true) +@Composable +private fun TodayFortuneBoxPreview() { + TodayFortuneBox( + content = { Text("123") }, + modifier = Modifier.background(color = Color.White), + ) +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/TodayFortuneDashboard.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/TodayFortuneDashboard.kt new file mode 100644 index 000000000..eef1aa214 --- /dev/null +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/component/TodayFortuneDashboard.kt @@ -0,0 +1,100 @@ +/* + * MIT License + * Copyright 2023-2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.feature.fortuneDetail.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.style.LineBreak +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.sopt.official.designsystem.Gray100 +import org.sopt.official.designsystem.Gray30 +import org.sopt.official.designsystem.SoptTheme +import org.sopt.official.feature.fortune.R + +@Composable +internal fun TodayFortuneDashboard( + date: String, + todaySentence: String, + modifier: Modifier = Modifier, +) { + TodayFortuneBox( + content = { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier, + ) { + Spacer(modifier = Modifier.height(height = 32.dp)) + Image( + painter = painterResource(R.drawable.img_fortune_title), + contentDescription = "오늘의 솝마디", + ) + Spacer(modifier = Modifier.height(height = 10.dp)) + Text( + text = date, + style = SoptTheme.typography.title18SB, + color = Gray100, + ) + Spacer(modifier = Modifier.height(height = 20.dp)) + Text( + text = todaySentence, + style = SoptTheme.typography.title24SB.copy( + lineBreak = LineBreak.Simple, + ), + color = Gray30, + textAlign = TextAlign.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 68.dp) + .semantics { contentDescription = "todaySentence" }, + ) + Spacer(modifier = Modifier.height(height = 36.dp)) + } + } + ) +} + +@Preview(showBackground = true) +@Composable +private fun TodayFortuneDashboardPreview() { + SoptTheme { + TodayFortuneDashboard( + date = "2024-09-09", + todaySentence = "hi my name is Sehun kim, nice to meet you", + ) + } +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/model/FortuneDetailUiState.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/model/FortuneDetailUiState.kt new file mode 100644 index 000000000..08a5904dd --- /dev/null +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/model/FortuneDetailUiState.kt @@ -0,0 +1,47 @@ +/* + * MIT License + * Copyright 2024 SOPT - Shout Our Passion Together + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.sopt.official.feature.fortune.feature.fortuneDetail.model + +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.Stable + +@Stable +internal sealed interface FortuneDetailUiState { + + @Immutable + data class TodaySentence( + val userName: String, + val content: String, + ) : FortuneDetailUiState { + val message: String + get() = "${userName}님,\n${content}" + } + + @Immutable + data object Loading : FortuneDetailUiState + + @Immutable + data class Error(val errorMessage: Throwable) : FortuneDetailUiState +} diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/navigation/FortuneDetailNavGraph.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/navigation/FortuneDetailNavGraph.kt similarity index 90% rename from feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/navigation/FortuneDetailNavGraph.kt rename to feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/navigation/FortuneDetailNavGraph.kt index 731995b46..25c9369e0 100644 --- a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortundDetail/navigation/FortuneDetailNavGraph.kt +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/fortuneDetail/navigation/FortuneDetailNavGraph.kt @@ -22,14 +22,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package org.sopt.official.feature.fortune.feature.fortundDetail.navigation +package org.sopt.official.feature.fortune.feature.fortuneDetail.navigation import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import androidx.navigation.toRoute import kotlinx.serialization.Serializable -import org.sopt.official.feature.fortune.feature.fortundDetail.FortuneDetailRoute +import org.sopt.official.feature.fortune.feature.fortuneDetail.FortuneDetailRoute @Serializable data class FortuneDetail(val date: String) @@ -43,7 +43,7 @@ fun NavGraphBuilder.fortuneDetailNavGraph( FortuneDetailRoute( paddingValue = paddingValue, date = items.date, - navigateToFortuneAmulet = navigateToFortuneAmulet + onFortuneAmuletClick = navigateToFortuneAmulet ) } } diff --git a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/home/navigation/HomeNavGraph.kt b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/home/navigation/HomeNavGraph.kt index 03473bc03..adb65ced5 100644 --- a/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/home/navigation/HomeNavGraph.kt +++ b/feature/fortune/src/main/java/org/sopt/official/feature/fortune/feature/home/navigation/HomeNavGraph.kt @@ -28,7 +28,6 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import kotlinx.serialization.Serializable -import org.sopt.official.feature.fortune.feature.fortuneAmulet.navigation.FortuneAmulet import org.sopt.official.feature.fortune.feature.home.HomeRoute @Serializable @@ -38,7 +37,7 @@ fun NavGraphBuilder.homeNavGraph( paddingValue: PaddingValues, navigateToFortuneDetail: (String) -> Unit, ) { - composable { + composable { HomeRoute( paddingValue = paddingValue, navigateToFortuneDetail = navigateToFortuneDetail diff --git a/feature/mypage/src/main/java/org/sopt/official/feature/mypage/component/MyPageSection.kt b/feature/mypage/src/main/java/org/sopt/official/feature/mypage/component/MyPageSection.kt index 3499c5916..5db556a3d 100644 --- a/feature/mypage/src/main/java/org/sopt/official/feature/mypage/component/MyPageSection.kt +++ b/feature/mypage/src/main/java/org/sopt/official/feature/mypage/component/MyPageSection.kt @@ -1,6 +1,6 @@ /* * MIT License - * Copyright 2024 SOPT - Shout Our Passion Together + * Copyright 2023-2024 SOPT - Shout Our Passion Together * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7a8fee7a9..1e68afd9e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -54,7 +54,7 @@ timber = "5.0.1" compose-destination = "1.11.6" coil = "2.7.0" lottie = "6.5.2" -dotsindicator = "5.0" +dotsindicator = "5.1.0" google-services = "4.4.2" crashlytics = "3.0.2" diff --git a/settings.gradle.kts b/settings.gradle.kts index 81a7a14e0..0340a6ea4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,6 +30,8 @@ include( ":data:notification", ":data:soptamp", ":data:poke", + ":data:fortune", + ":domain:fortune", ":domain:mypage", ":domain:notification", ":domain:soptamp",