├── .github
├── ISSUE_TEMPLATE
│ └── genti-issue-template.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── firebase_distribution_builder.yml
│ └── pr_checker.yml
├── .gitignore
├── LICENSE
├── README.md
├── app
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── android
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_genti_launcher-playstore.png
│ ├── java
│ │ └── kr
│ │ │ └── genti
│ │ │ └── android
│ │ │ └── MyApp.kt
│ └── res
│ │ ├── drawable
│ │ └── ic_genti_launcher_background.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_genti_launcher.xml
│ │ └── ic_genti_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_genti_launcher.webp
│ │ ├── ic_genti_launcher_foreground.webp
│ │ └── ic_genti_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_genti_launcher.webp
│ │ ├── ic_genti_launcher_foreground.webp
│ │ └── ic_genti_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_genti_launcher.webp
│ │ ├── ic_genti_launcher_foreground.webp
│ │ └── ic_genti_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_genti_launcher.webp
│ │ ├── ic_genti_launcher_foreground.webp
│ │ └── ic_genti_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_genti_launcher.webp
│ │ ├── ic_genti_launcher_foreground.webp
│ │ └── ic_genti_launcher_round.webp
│ │ ├── values
│ │ └── theme.xml
│ │ └── xml
│ │ └── file_paths.xml
│ └── test
│ └── java
│ └── kr
│ └── genti
│ └── android
│ └── ExampleUnitTest.kt
├── build-logic
├── convention
│ ├── build.gradle.kts
│ └── src
│ │ └── main
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── convention
│ │ ├── Constants.kt
│ │ ├── config
│ │ ├── CommonPlugin.kt
│ │ ├── ComposePlugin.kt
│ │ ├── HiltPlugin.kt
│ │ ├── KotlinPlugin.kt
│ │ ├── TestPlugin.kt
│ │ └── VersionPlugin.kt
│ │ ├── extension
│ │ ├── DependencyHandlerScopeExt.kt
│ │ ├── ProjectExt.kt
│ │ └── VersionCatalogExt.kt
│ │ └── plugin
│ │ ├── AndroidApplicationPlugin.kt
│ │ ├── AndroidComposePlugin.kt
│ │ ├── AndroidLibraryPlugin.kt
│ │ └── JavaLibraryPlugin.kt
├── gradle.properties
└── settings.gradle.kts
├── build.gradle.kts
├── core
├── common
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── common
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── java
│ │ │ └── kr
│ │ │ │ └── genti
│ │ │ │ └── common
│ │ │ │ ├── extension
│ │ │ │ ├── ContextExt.kt
│ │ │ │ ├── ModifierExt.kt
│ │ │ │ ├── StringExt.kt
│ │ │ │ └── UriExt.kt
│ │ │ │ ├── manager
│ │ │ │ ├── AmplitudeManager.kt
│ │ │ │ ├── AppUpdateManager.kt
│ │ │ │ ├── ImageManager.kt
│ │ │ │ ├── LauncherManager.kt
│ │ │ │ ├── NetworkMonitorManager.kt
│ │ │ │ └── PermissionManager.kt
│ │ │ │ └── util
│ │ │ │ └── DoubleBackHandler.kt
│ │ └── res
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── common
│ │ ├── ExampleUnitTest.kt
│ │ └── PermissionManagerTest.kt
├── datastore
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── datastore
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── datastore
│ │ │ ├── di
│ │ │ └── SharedPrefModule.kt
│ │ │ └── local
│ │ │ ├── UserSharedPref.kt
│ │ │ └── UserSharedPrefImpl.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── datastore
│ │ └── ExampleUnitTest.kt
├── designsystem
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── designsystem
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── java
│ │ │ └── kr
│ │ │ │ └── genti
│ │ │ │ └── designsystem
│ │ │ │ ├── component
│ │ │ │ ├── button
│ │ │ │ │ ├── CloseButton.kt
│ │ │ │ │ ├── GentiButton.kt
│ │ │ │ │ ├── GentiGradationButton.kt
│ │ │ │ │ ├── GentiGradationIconButton.kt
│ │ │ │ │ └── GentiSelectButton.kt
│ │ │ │ ├── dialog
│ │ │ │ │ ├── GentiBottomSheet.kt
│ │ │ │ │ ├── GentiErrorDialog.kt
│ │ │ │ │ ├── GentiImageDetailDialog.kt
│ │ │ │ │ ├── GentiNotiDialog.kt
│ │ │ │ │ ├── GentiRatingDialog.kt
│ │ │ │ │ ├── GentiTextFieldDialog.kt
│ │ │ │ │ └── GentiWarningDialog.kt
│ │ │ │ ├── item
│ │ │ │ │ ├── GentiAsyncImage.kt
│ │ │ │ │ ├── GentiAsyncUriImage.kt
│ │ │ │ │ ├── GentiCheckedText.kt
│ │ │ │ │ ├── GentiPageIndicator.kt
│ │ │ │ │ └── GentiRatingBar.kt
│ │ │ │ ├── layout
│ │ │ │ │ ├── GentiLoadingScreen.kt
│ │ │ │ │ ├── GentiPullToRefreshBox.kt
│ │ │ │ │ ├── GentiTopBar.kt
│ │ │ │ │ └── GentiTopBottomShadow.kt
│ │ │ │ └── snackbar
│ │ │ │ │ └── GentiSnackBar.kt
│ │ │ │ ├── event
│ │ │ │ └── SnackbarTrigger.kt
│ │ │ │ └── theme
│ │ │ │ ├── Color.kt
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Type.kt
│ │ └── res
│ │ │ ├── drawable
│ │ │ ├── ic_back.xml
│ │ │ ├── ic_blank.xml
│ │ │ ├── ic_check.xml
│ │ │ ├── ic_close.xml
│ │ │ ├── ic_download.xml
│ │ │ ├── ic_download_no_border.xml
│ │ │ ├── ic_drag_handle.xml
│ │ │ ├── ic_female.xml
│ │ │ ├── ic_genti_launcher.png
│ │ │ ├── ic_info.xml
│ │ │ ├── ic_kakao.xml
│ │ │ ├── ic_male.xml
│ │ │ ├── ic_next.xml
│ │ │ ├── ic_play.xml
│ │ │ ├── ic_setting.xml
│ │ │ ├── ic_star.xml
│ │ │ ├── ic_verify.png
│ │ │ ├── img_alarm.png
│ │ │ ├── img_alert_circle.png
│ │ │ ├── img_alert_triangle.png
│ │ │ ├── img_empty_image.xml
│ │ │ ├── img_glow.png
│ │ │ ├── img_gradation_black_bottom.xml
│ │ │ ├── img_gradation_black_top.xml
│ │ │ ├── img_gradation_image_bottom.xml
│ │ │ ├── img_login_bg.png
│ │ │ ├── img_number_one.xml
│ │ │ ├── img_number_two.xml
│ │ │ ├── img_onboarding_first.png
│ │ │ ├── img_onboarding_second.png
│ │ │ ├── img_onboarding_third.png
│ │ │ ├── img_parent_ex_1.png
│ │ │ ├── img_parent_ex_2.png
│ │ │ ├── img_parent_ex_3.png
│ │ │ ├── img_photo_add.png
│ │ │ ├── img_profile_create_active.xml
│ │ │ ├── img_profile_create_inactive.xml
│ │ │ ├── img_profile_making.png
│ │ │ ├── img_ratio_2_3.xml
│ │ │ ├── img_ratio_3_2.xml
│ │ │ ├── img_selfie_one.png
│ │ │ ├── img_selfie_three.png
│ │ │ ├── img_selfie_two.png
│ │ │ ├── img_shine.png
│ │ │ ├── img_tooltip_feed.png
│ │ │ ├── img_tooltip_finished.png
│ │ │ ├── img_tooltip_verify.png
│ │ │ ├── img_verify_bg.png
│ │ │ ├── logo_genti_2d.png
│ │ │ ├── mock_img_2_3.png
│ │ │ └── mock_img_3_2.png
│ │ │ ├── font
│ │ │ ├── pretendard_bold.ttf
│ │ │ ├── pretendard_light.ttf
│ │ │ ├── pretendard_medium.ttf
│ │ │ ├── pretendard_regular.ttf
│ │ │ └── pretendard_semibold.ttf
│ │ │ ├── raw
│ │ │ ├── lottie_loading.json
│ │ │ ├── lottie_loading_create.json
│ │ │ ├── lottie_loading_image.json
│ │ │ ├── lottie_splash.json
│ │ │ └── lottie_waiting.json
│ │ │ └── values
│ │ │ └── strings.xml
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── designsystem
│ │ └── ExampleUnitTest.kt
├── navigation
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── navigation
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── navigation
│ │ │ ├── GenerateRoute.kt
│ │ │ ├── MainTabRoute.kt
│ │ │ ├── OnboardingRoute.kt
│ │ │ ├── ResultRoute.kt
│ │ │ ├── Route.kt
│ │ │ └── SettingRoute.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── navigation
│ │ └── ExampleUnitTest.kt
└── network
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ ├── androidTest
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── network
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── network
│ │ ├── AuthInterceptor.kt
│ │ ├── RetrofitModule.kt
│ │ ├── RetrofitQualifier.kt
│ │ └── StringExt.kt
│ └── test
│ └── java
│ └── kr
│ └── genti
│ └── network
│ └── ExampleUnitTest.kt
├── data
├── build.gradle.kts
├── consumer-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── data
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── data
│ │ ├── dataSource
│ │ ├── AuthDataSource.kt
│ │ ├── CreateDataSource.kt
│ │ ├── FeedDataSource.kt
│ │ ├── GenerateDataSource.kt
│ │ └── InfoDataSource.kt
│ │ ├── dataSourceImpl
│ │ ├── AuthDataSourceImpl.kt
│ │ ├── CreateDataSourceImpl.kt
│ │ ├── FeedDataSourceImpl.kt
│ │ ├── GenerateDataSourceImpl.kt
│ │ └── InfoDataSourceImpl.kt
│ │ ├── di
│ │ ├── DataSourceModule.kt
│ │ ├── RepositoryModule.kt
│ │ └── ServiceModule.kt
│ │ ├── dto
│ │ ├── BaseResponse.kt
│ │ ├── request
│ │ │ ├── AuthRequestDto.kt
│ │ │ ├── CreateRequestDto.kt
│ │ │ ├── CreateTwoRequestDto.kt
│ │ │ ├── ImageBucketRequestDto.kt
│ │ │ ├── KeyRequestDto.kt
│ │ │ ├── PurchaseValidRequestDto.kt
│ │ │ ├── ReissueRequestDto.kt
│ │ │ ├── ReportRequestDto.kt
│ │ │ └── SignupRequestDto.kt
│ │ └── response
│ │ │ ├── AuthTokenDto.kt
│ │ │ ├── FeedItemDto.kt
│ │ │ ├── GenerateStatusDto.kt
│ │ │ ├── ImageBucketDto.kt
│ │ │ ├── ImageDto.kt
│ │ │ ├── OpenchatDto.kt
│ │ │ ├── PicturePagedListDto.kt
│ │ │ ├── PromptExampleDto.kt
│ │ │ ├── ReissueTokenDto.kt
│ │ │ ├── ServerAvailableDto.kt
│ │ │ └── SignUpUserDto.kt
│ │ ├── repositoryImpl
│ │ ├── AuthRepositoryImpl.kt
│ │ ├── CreateRepositoryImpl.kt
│ │ ├── FeedRepositoryImpl.kt
│ │ ├── GenerateRepositoryImpl.kt
│ │ ├── InfoRepositoryImpl.kt
│ │ ├── UploadRepositoryImpl.kt
│ │ └── UserRepositoryImpl.kt
│ │ ├── service
│ │ ├── AuthService.kt
│ │ ├── CreateService.kt
│ │ ├── FeedService.kt
│ │ ├── GenerateService.kt
│ │ ├── InfoService.kt
│ │ └── UploadService.kt
│ │ └── util
│ │ └── ContentUriRequestBody.kt
│ └── test
│ └── java
│ └── kr
│ └── genti
│ └── data
│ └── ExampleUnitTest.kt
├── domain
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ └── kr
│ └── genti
│ └── domain
│ ├── entity
│ ├── request
│ │ ├── AuthRequestModel.kt
│ │ ├── CreateRequestModel.kt
│ │ ├── CreateTwoRequestModel.kt
│ │ ├── ImageBucketRequestModel.kt
│ │ ├── KeyRequestModel.kt
│ │ ├── PurchaseValidRequestModel.kt
│ │ ├── ReissueRequestModel.kt
│ │ ├── ReportRequestModel.kt
│ │ └── SignupRequestModel.kt
│ └── response
│ │ ├── AuthTokenModel.kt
│ │ ├── FeedItemModel.kt
│ │ ├── GenerateStatusModel.kt
│ │ ├── ImageBucketModel.kt
│ │ ├── ImageFileModel.kt
│ │ ├── ImageModel.kt
│ │ ├── OpenchatModel.kt
│ │ ├── PicturePagedListModel.kt
│ │ ├── PromptExampleModel.kt
│ │ ├── ReissueTokenModel.kt
│ │ ├── ServerAvailableModel.kt
│ │ └── SignUpUserModel.kt
│ ├── enums
│ ├── FileType.kt
│ ├── Gender.kt
│ ├── GenerateStatus.kt
│ ├── PictureNumber.kt
│ └── PictureRatio.kt
│ ├── repository
│ ├── AuthRepository.kt
│ ├── CreateRepository.kt
│ ├── FeedRepository.kt
│ ├── GenerateRepository.kt
│ ├── InfoRepository.kt
│ ├── UploadRepository.kt
│ └── UserRepository.kt
│ └── usecase
│ ├── auth
│ ├── GetNewTokensFromOauthUseCase.kt
│ ├── ReissueOldTokensUseCase.kt
│ └── SignUpUserUseCase.kt
│ ├── feed
│ └── GetFeedItemListUseCase.kt
│ ├── generate
│ ├── CheckPurchaseValidUseCase.kt
│ ├── CheckServerAvailableUseCase.kt
│ ├── GetPromptExampleListUseCase.kt
│ ├── GetThreeImageBucketUseCase.kt
│ └── SendGenerateRequestUseCase.kt
│ ├── profile
│ └── GetGeneratedPictureListUseCase.kt
│ ├── result
│ ├── ForceGenerateInDebugUseCase.kt
│ ├── GetCurrentGenerateStatusUseCase.kt
│ ├── ReportUnwantedResultUseCase.kt
│ ├── ResetGenerateStatusUseCase.kt
│ ├── SkipGenerateRatingUseCase.kt
│ └── SubmitGenerateRatingUseCase.kt
│ ├── setting
│ ├── DeleteUserUseCase.kt
│ └── LogoutUserUseCase.kt
│ ├── upload
│ └── UploadImageToBucketUseCase.kt
│ └── verify
│ ├── CheckUserVerifiedUseCase.kt
│ ├── CheckVerifyImageUploadedUseCase.kt
│ └── GetVerifyImageBucketUseCase.kt
├── feature
├── feed
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── feed
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── feed
│ │ │ ├── FeedIntent.kt
│ │ │ ├── FeedScreen.kt
│ │ │ ├── FeedSideEffect.kt
│ │ │ ├── FeedState.kt
│ │ │ ├── FeedViewModel.kt
│ │ │ ├── component
│ │ │ ├── FeedBottomTooltip.kt
│ │ │ ├── FeedHeader.kt
│ │ │ ├── FeedImagesListScreen.kt
│ │ │ └── FeedItem.kt
│ │ │ └── navigation
│ │ │ └── FeedNavigation.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── feed
│ │ └── FeedViewModelTest.kt
├── generate
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── generate
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── generate
│ │ │ ├── GenerateIntent.kt
│ │ │ ├── GenerateRoute.kt
│ │ │ ├── GenerateSideEffect.kt
│ │ │ ├── GenerateState.kt
│ │ │ ├── GenerateViewModel.kt
│ │ │ ├── ImageSixSelectScreen.kt
│ │ │ ├── ImageThreeSelectScreen.kt
│ │ │ ├── NumberSelectScreen.kt
│ │ │ ├── PromptInputScreen.kt
│ │ │ ├── RatioSelectScreen.kt
│ │ │ ├── billing
│ │ │ ├── BillingCallback.kt
│ │ │ └── BillingManager.kt
│ │ │ ├── component
│ │ │ ├── GenerateProgressBar.kt
│ │ │ ├── ImagePersonItem.kt
│ │ │ ├── ImageThreeExample.kt
│ │ │ ├── ImageThreeSelected.kt
│ │ │ ├── PromptExampleItem.kt
│ │ │ └── PromptExamplePager.kt
│ │ │ ├── model
│ │ │ ├── GenerateStage.kt
│ │ │ └── GenerateType.kt
│ │ │ └── navigation
│ │ │ └── GenerateNavigation.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── generate
│ │ └── GenerateViewModelTest.kt
├── main
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── main
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── java
│ │ │ └── kr
│ │ │ │ └── genti
│ │ │ │ └── main
│ │ │ │ ├── MainActivity.kt
│ │ │ │ ├── MainIntent.kt
│ │ │ │ ├── MainScreen.kt
│ │ │ │ ├── MainSideEffect.kt
│ │ │ │ ├── MainState.kt
│ │ │ │ ├── MainViewModel.kt
│ │ │ │ ├── component
│ │ │ │ ├── GenerateForceButton.kt
│ │ │ │ ├── GenerateSelectDialog.kt
│ │ │ │ ├── GenerateSelectItem.kt
│ │ │ │ ├── MainBottomBar.kt
│ │ │ │ ├── MainBottomBtn.kt
│ │ │ │ └── MainNavHost.kt
│ │ │ │ ├── config
│ │ │ │ └── GentiMessagingService.kt
│ │ │ │ └── navigation
│ │ │ │ ├── MainNavigator.kt
│ │ │ │ └── MainTab.kt
│ │ └── res
│ │ │ └── drawable
│ │ │ ├── menu_create.png
│ │ │ ├── menu_feed_selected.xml
│ │ │ ├── menu_feed_unselected.xml
│ │ │ ├── menu_profile_selected.xml
│ │ │ └── menu_profile_unselected.xml
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── main
│ │ └── MainViewModelTest.kt
├── onboarding
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── onboarding
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── onboarding
│ │ │ ├── component
│ │ │ ├── KakaoLoginButton.kt
│ │ │ ├── MovingBackgroundImage.kt
│ │ │ ├── TutorialFadeInBackground.kt
│ │ │ └── TutorialItem.kt
│ │ │ ├── login
│ │ │ ├── LoginIntent.kt
│ │ │ ├── LoginScreen.kt
│ │ │ ├── LoginSideEffect.kt
│ │ │ ├── LoginState.kt
│ │ │ └── LoginViewModel.kt
│ │ │ ├── model
│ │ │ └── TutorialStage.kt
│ │ │ ├── navigation
│ │ │ └── OnboardingNavigation.kt
│ │ │ ├── signup
│ │ │ ├── SignupIntent.kt
│ │ │ ├── SignupScreen.kt
│ │ │ ├── SignupSideEffect.kt
│ │ │ ├── SignupState.kt
│ │ │ └── SignupViewModel.kt
│ │ │ ├── splash
│ │ │ ├── SplashIntent.kt
│ │ │ ├── SplashScreen.kt
│ │ │ ├── SplashSideEffect.kt
│ │ │ ├── SplashState.kt
│ │ │ └── SplashViewModel.kt
│ │ │ └── tutorial
│ │ │ ├── TutorialIntent.kt
│ │ │ ├── TutorialScreen.kt
│ │ │ ├── TutorialSideEffect.kt
│ │ │ ├── TutorialState.kt
│ │ │ └── TutorialViewModel.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── onboarding
│ │ └── ExampleUnitTest.kt
├── profile
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── profile
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── profile
│ │ │ ├── ProfileIntent.kt
│ │ │ ├── ProfileScreen.kt
│ │ │ ├── ProfileSideEffect.kt
│ │ │ ├── ProfileState.kt
│ │ │ ├── ProfileViewModel.kt
│ │ │ ├── component
│ │ │ ├── ProfileEmptyScreen.kt
│ │ │ ├── ProfileGenerateItem.kt
│ │ │ ├── ProfileGeneratingBanner.kt
│ │ │ ├── ProfileImagesGridScreen.kt
│ │ │ └── ProfileTopBar.kt
│ │ │ └── navigation
│ │ │ └── ProfileNavigation.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── profile
│ │ └── ProfileViewModelTest.kt
├── result
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── result
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ └── java
│ │ │ └── kr
│ │ │ └── genti
│ │ │ └── result
│ │ │ ├── component
│ │ │ └── BackgroundBlurImage.kt
│ │ │ ├── finished
│ │ │ ├── FinishedIntent.kt
│ │ │ ├── FinishedScreen.kt
│ │ │ ├── FinishedSideEffect.kt
│ │ │ ├── FinishedState.kt
│ │ │ └── FinishedViewModel.kt
│ │ │ ├── navigation
│ │ │ └── ResultNavigation.kt
│ │ │ ├── verify
│ │ │ ├── VerifyAfterScreen.kt
│ │ │ ├── VerifyBeforeScreen.kt
│ │ │ ├── VerifyIntent.kt
│ │ │ ├── VerifyRoute.kt
│ │ │ ├── VerifySideEffect.kt
│ │ │ ├── VerifyState.kt
│ │ │ └── VerifyViewModel.kt
│ │ │ └── waiting
│ │ │ ├── WaitingIntent.kt
│ │ │ ├── WaitingScreen.kt
│ │ │ ├── WaitingSideEffect.kt
│ │ │ ├── WaitingState.kt
│ │ │ └── WaitingViewModel.kt
│ │ └── test
│ │ └── java
│ │ └── kr
│ │ └── genti
│ │ └── result
│ │ └── ExampleUnitTest.kt
└── setting
│ ├── build.gradle.kts
│ ├── consumer-rules.pro
│ └── src
│ ├── androidTest
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── setting
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ └── java
│ │ └── kr
│ │ └── genti
│ │ └── setting
│ │ ├── SettingIntent.kt
│ │ ├── SettingScreen.kt
│ │ ├── SettingSideEffect.kt
│ │ ├── SettingState.kt
│ │ ├── SettingViewModel.kt
│ │ ├── component
│ │ └── SettingItem.kt
│ │ └── navigation
│ │ └── SettingNavigation.kt
│ └── test
│ └── java
│ └── kr
│ └── genti
│ └── setting
│ └── SettingViewModelTest.kt
├── gradle.properties
├── gradle
├── libs.versions.toml
├── projectDependencyGraph.gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.github/ISSUE_TEMPLATE/genti-issue-template.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Genti issue template
3 | about: Genti issue template
4 | title: "[TAG] where / what"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | ## 🚩 TO DO
11 | - [ ] task1
12 | - [ ] task2
13 | - [ ] task3
14 |
15 |
16 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | - closed #issue number
2 |
3 | ## *⛳️ Work Description*
4 | - task1
5 | - task2
6 | - task3
7 |
8 | ## *📸 Screenshot*
9 |
10 |
11 |
12 | ## *📢 To Reviewers*
13 | -
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Genti
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/kr/genti/android/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.android
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.android", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/ic_genti_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/ic_genti_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/java/kr/genti/android/MyApp.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.android
2 |
3 | import android.app.Application
4 | import androidx.appcompat.app.AppCompatDelegate
5 | import com.kakao.sdk.common.KakaoSdk
6 | import dagger.hilt.android.HiltAndroidApp
7 | import kr.genti.android.BuildConfig.AMPLITUDE_KEY
8 | import kr.genti.android.BuildConfig.NATIVE_APP_KEY
9 | import kr.genti.common.manager.AmplitudeManager
10 | import kr.genti.common.manager.AppUpdateManager
11 | import kr.genti.common.manager.ImageManager
12 | import kr.genti.common.manager.PermissionManager
13 | import timber.log.Timber
14 |
15 | @HiltAndroidApp
16 | class MyApp : Application() {
17 | override fun onCreate() {
18 | super.onCreate()
19 |
20 | initTimber()
21 | initKakaoSDK()
22 | initManagers()
23 | setDayMode()
24 | }
25 |
26 | private fun initTimber() {
27 | if (BuildConfig.DEBUG) Timber.plant(Timber.DebugTree())
28 | }
29 |
30 | private fun initKakaoSDK() {
31 | KakaoSdk.init(this, NATIVE_APP_KEY)
32 | }
33 |
34 | private fun initManagers() {
35 | AmplitudeManager.init(this, AMPLITUDE_KEY)
36 | AppUpdateManager.init(this)
37 | ImageManager.init(this)
38 | }
39 |
40 | private fun setDayMode() {
41 | AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_genti_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_genti_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_genti_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-hdpi/ic_genti_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_genti_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-hdpi/ic_genti_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_genti_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-hdpi/ic_genti_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_genti_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-mdpi/ic_genti_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_genti_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-mdpi/ic_genti_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_genti_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-mdpi/ic_genti_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_genti_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xhdpi/ic_genti_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_genti_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xhdpi/ic_genti_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_genti_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xhdpi/ic_genti_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxhdpi/ic_genti_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher_foreground.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/app/src/main/res/mipmap-xxxhdpi/ic_genti_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/test/java/kr/genti/android/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.android
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/Constants.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention
2 |
3 | import org.gradle.api.JavaVersion
4 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget
5 |
6 | object Constants {
7 | const val PACKAGE_NAME = "kr.genti.android"
8 |
9 | const val COMPILE_SDK = 35
10 | const val MIN_SDK = 28
11 | const val TARGET_SDK = 35
12 |
13 | const val VERSION_CODE = 26
14 | const val VERSION_NAME = "3.0.0"
15 |
16 | val JVM_VERSION = JvmTarget.JVM_11
17 | val JAVA_VERSION = JavaVersion.VERSION_11
18 | }
19 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/CommonPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import kr.genti.convention.extension.getLibrary
4 | import kr.genti.convention.extension.implementation
5 | import kr.genti.convention.extension.libs
6 | import org.gradle.api.Plugin
7 | import org.gradle.api.Project
8 | import org.gradle.kotlin.dsl.dependencies
9 |
10 | /**
11 | * 모든 Android 프로젝트에서 공통적으로 적용할 Gradle 플러그인을 정의하는 커스텀 플러그인입니다.
12 | */
13 | class CommonPlugin : Plugin {
14 | override fun apply(target: Project) = with(target) {
15 | dependencies {
16 | implementation(libs.getLibrary("timber"))
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/ComposePlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import kr.genti.convention.extension.androidLibraryExtension
4 | import kr.genti.convention.extension.getBundle
5 | import kr.genti.convention.extension.getLibrary
6 | import kr.genti.convention.extension.getPlugin
7 | import kr.genti.convention.extension.implementation
8 | import kr.genti.convention.extension.libs
9 | import org.gradle.api.Plugin
10 | import org.gradle.api.Project
11 | import org.gradle.kotlin.dsl.dependencies
12 |
13 | /**
14 | * Jetpack Compose, Navigation 등 화면 관련 Gradle 플러그인을 정의하는 커스텀 플러그인입니다.
15 | */
16 | class ComposePlugin : Plugin {
17 | override fun apply(target: Project) = with(target) {
18 | pluginManager.apply {
19 | apply(libs.getPlugin("kotlin-compose"))
20 | }
21 |
22 | androidLibraryExtension.apply {
23 | buildFeatures {
24 | compose = true
25 | }
26 | }
27 |
28 | dependencies {
29 | implementation(platform(libs.getLibrary("androidx-compose-bom")))
30 | implementation(libs.getBundle("compose"))
31 | implementation(libs.getBundle("navigation"))
32 | implementation(libs.getBundle("ui"))
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/HiltPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import kr.genti.convention.extension.getLibrary
4 | import kr.genti.convention.extension.getPlugin
5 | import kr.genti.convention.extension.implementation
6 | import kr.genti.convention.extension.ksp
7 | import kr.genti.convention.extension.libs
8 | import org.gradle.api.Plugin
9 | import org.gradle.api.Project
10 | import org.gradle.kotlin.dsl.dependencies
11 |
12 | /**
13 | * Hilt 관련 Gradle 플러그인을 정의하는 커스텀 플러그인입니다.
14 | */
15 | class HiltPlugin : Plugin {
16 | override fun apply(target: Project) = with(target) {
17 | pluginManager.apply {
18 | apply(libs.getPlugin("ksp"))
19 | apply(libs.getPlugin("hilt"))
20 | }
21 |
22 | dependencies {
23 | implementation(libs.getLibrary("hilt-android"))
24 | ksp(libs.getLibrary("hilt-android-compiler"))
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/KotlinPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import kr.genti.convention.Constants
4 | import kr.genti.convention.extension.applyKotlinCompilerOptions
5 | import kr.genti.convention.extension.getBundle
6 | import kr.genti.convention.extension.getPlugin
7 | import kr.genti.convention.extension.implementation
8 | import kr.genti.convention.extension.libs
9 | import org.gradle.api.Plugin
10 | import org.gradle.api.Project
11 | import org.gradle.kotlin.dsl.dependencies
12 |
13 | /**
14 | * Kotlin & Coroutines 관련 Gradle 플러그인을 정의하는 커스텀 플러그인입니다.
15 | */
16 | class KotlinPlugin : Plugin {
17 | override fun apply(target: Project) = with(target) {
18 | pluginManager.apply {
19 | apply(libs.getPlugin("kotlin-android"))
20 | apply(libs.getPlugin("kotlin-parcelize"))
21 | apply(libs.getPlugin("kotlin-serialization"))
22 | }
23 |
24 | applyKotlinCompilerOptions(Constants.JVM_VERSION)
25 |
26 | dependencies {
27 | implementation(libs.getBundle("kotlinx"))
28 | implementation(libs.getBundle("coroutines"))
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/TestPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import kr.genti.convention.extension.androidTestImplementation
4 | import kr.genti.convention.extension.applyJUnitPlatform
5 | import kr.genti.convention.extension.getLibrary
6 | import kr.genti.convention.extension.libs
7 | import kr.genti.convention.extension.testImplementation
8 | import kr.genti.convention.extension.testRuntimeOnly
9 | import org.gradle.api.Plugin
10 | import org.gradle.api.Project
11 | import org.gradle.kotlin.dsl.dependencies
12 |
13 | /**
14 | * Test 관련 Gradle 플러그인을 정의하는 커스텀 플러그인입니다.
15 | */
16 | class TestPlugin : Plugin {
17 | override fun apply(target: Project) = with(target) {
18 |
19 | applyJUnitPlatform()
20 |
21 | dependencies {
22 | testImplementation(platform(libs.getLibrary("junit-bom")))
23 | testRuntimeOnly(libs.getLibrary("junit-jupiter-engine"))
24 | testImplementation(libs.getLibrary("junit-jupiter-api"))
25 | testImplementation(libs.getLibrary("junit-jupiter-params"))
26 | testImplementation(libs.getLibrary("junit-vintage-engine"))
27 | testImplementation(libs.getLibrary("junit-platform-launcher"))
28 |
29 | testImplementation(libs.getLibrary("mockk"))
30 |
31 | testImplementation(libs.getLibrary("junit"))
32 | androidTestImplementation(libs.getLibrary("androidx-junit"))
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/config/VersionPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.config
2 |
3 | import com.android.build.gradle.AppExtension
4 | import kr.genti.convention.Constants
5 | import org.gradle.api.Plugin
6 | import org.gradle.api.Project
7 |
8 | class VersionPlugin : Plugin {
9 | override fun apply(target: Project) = with(target) {
10 | with(extensions) {
11 | extraProperties["versionName"] = Constants.VERSION_NAME
12 | extraProperties["versionCode"] = Constants.VERSION_CODE
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/extension/VersionCatalogExt.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.extension
2 |
3 | import org.gradle.api.artifacts.ExternalModuleDependencyBundle
4 | import org.gradle.api.artifacts.MinimalExternalModuleDependency
5 | import org.gradle.api.artifacts.VersionCatalog
6 | import org.gradle.api.provider.Provider
7 |
8 | /**
9 | * Gradle의 Version Catalog(libs.versions.toml)를 간결하게 활용하기 위한 확장 함수 모음
10 | *
11 | * - 기존의 `findBundle(...)`, `findLibrary(...)`, `findPlugin(...)`을 더 직관적으로 사용할 수 있도록 개선합니다.
12 | * - Catalog에서 라이브러리, 번들, 플러그인을 조회할 때, 존재하지 않으면 예외를 던져 문제를 조기에 감지할 수 있습니다.
13 | */
14 |
15 | fun VersionCatalog.getBundle(bundleName: String): Provider =
16 | findBundle(bundleName).orElseThrow {
17 | NoSuchElementException("Bundle with name $bundleName not found in the catalog")
18 | }
19 |
20 | fun VersionCatalog.getLibrary(libraryName: String): Provider =
21 | findLibrary(libraryName).orElseThrow {
22 | NoSuchElementException("Library with name $libraryName not found in the catalog")
23 | }
24 |
25 | fun VersionCatalog.getPlugin(pluginName: String): String =
26 | findPlugin(pluginName)
27 | .orElseThrow {
28 | NoSuchElementException("Plugin with name $pluginName not found in the catalog")
29 | }
30 | .get().pluginId
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidComposePlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.plugin
2 |
3 | import kr.genti.convention.config.ComposePlugin
4 | import org.gradle.api.Plugin
5 | import org.gradle.api.Project
6 | import org.gradle.kotlin.dsl.apply
7 |
8 | /**
9 | * Jetpack Compose 설정이 적용된 Android 라이브러리 모듈 Gradle 플러그인
10 | *
11 | * - 기존 AndroidLibraryPlugin에 ComposePlugin을 추가적으로 적용합니다.
12 | * - Jetpack Compose를 사용하는 Android 라이브러리 (ex. presentation 모듈)에 적용됩니다.
13 | */
14 | class AndroidComposePlugin : Plugin {
15 | override fun apply(target: Project) {
16 | with(target) {
17 | pluginManager.apply {
18 | apply()
19 | apply()
20 | }
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/build-logic/convention/src/main/java/kr/genti/convention/plugin/JavaLibraryPlugin.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.convention.plugin
2 |
3 | import kr.genti.convention.Constants
4 | import kr.genti.convention.extension.applyKotlinCompilerOptions
5 | import kr.genti.convention.extension.getBundle
6 | import kr.genti.convention.extension.getLibrary
7 | import kr.genti.convention.extension.getPlugin
8 | import kr.genti.convention.extension.implementation
9 | import kr.genti.convention.extension.javaLibraryExtension
10 | import kr.genti.convention.extension.libs
11 | import org.gradle.api.Plugin
12 | import org.gradle.api.Project
13 | import org.gradle.kotlin.dsl.dependencies
14 |
15 | /**
16 | * 순수 Kotlin/Java 모듈을 위한 Gradle 플러그인
17 | *
18 | * - Gradle 플러그인을 적용하여 Kotlin 및 Java의 설정을 자동으로 구성합니다.
19 | * - Android 관련 속성이 없는 순수 Kotlin/Java 라이브러리 모듈 (ex. domain 모듈)에 적용됩니다.
20 | */
21 | class JavaLibraryPlugin : Plugin {
22 | override fun apply(target: Project) =
23 | with(target) {
24 | pluginManager.apply {
25 | apply(libs.getPlugin("java-library"))
26 | apply(libs.getPlugin("kotlin-jvm"))
27 | }
28 |
29 | javaLibraryExtension.apply {
30 | sourceCompatibility = Constants.JAVA_VERSION
31 | targetCompatibility = Constants.JAVA_VERSION
32 | }
33 |
34 | applyKotlinCompilerOptions(Constants.JVM_VERSION)
35 |
36 | dependencies {
37 | implementation(libs.getBundle("kotlinx"))
38 | implementation(libs.getLibrary("kotlinx-coroutines-core"))
39 | implementation(libs.getLibrary("javax-inject"))
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/build-logic/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.parallel=true
2 | org.gradle.caching=true
3 | org.gradle.configureondemand=true
--------------------------------------------------------------------------------
/build-logic/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2 |
3 | dependencyResolutionManagement {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | }
8 | versionCatalogs {
9 | create("libs") {
10 | from(files("../gradle/libs.versions.toml"))
11 | }
12 | }
13 | }
14 |
15 | rootProject.name = "build-logic"
16 | include(":convention")
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | plugins {
9 | alias(libs.plugins.android.application) apply false
10 | alias(libs.plugins.android.library) apply false
11 | alias(libs.plugins.kotlin.android) apply false
12 | alias(libs.plugins.kotlin.serialization) apply false
13 | alias(libs.plugins.kotlin.parcelize) apply false
14 | alias(libs.plugins.kotlin.compose) apply false
15 | alias(libs.plugins.kotlin.jvm) apply false
16 | alias(libs.plugins.ksp) apply false
17 | alias(libs.plugins.hilt) apply false
18 | alias(libs.plugins.google.services) apply false
19 | alias(libs.plugins.firebase.crashlytics) apply false
20 | }
21 |
22 | apply {
23 | from("gradle/projectDependencyGraph.gradle")
24 | }
--------------------------------------------------------------------------------
/core/common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.core.common"
7 |
8 | buildFeatures {
9 | buildConfig = true
10 | }
11 | }
12 |
13 | dependencies {
14 | implementation(libs.amplitude)
15 | implementation(libs.app.update)
16 | }
17 |
--------------------------------------------------------------------------------
/core/common/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/common/consumer-rules.pro
--------------------------------------------------------------------------------
/core/common/src/androidTest/java/kr/genti/common/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.march.common.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/common/src/main/java/kr/genti/common/extension/ContextExt.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common.extension
2 |
3 | import android.content.Context
4 | import android.widget.Toast
5 |
6 | fun Context.toast(message: String) {
7 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
8 | }
9 |
10 | fun Context.longToast(message: String) {
11 | Toast.makeText(this, message, Toast.LENGTH_LONG).show()
12 | }
13 |
--------------------------------------------------------------------------------
/core/common/src/main/java/kr/genti/common/extension/StringExt.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common.extension
2 |
3 | import java.text.BreakIterator
4 |
5 | fun String.getGraphemeLength(): Int {
6 | val breakIterator: BreakIterator = BreakIterator.getCharacterInstance()
7 |
8 | breakIterator.setText(this)
9 |
10 | var count = 0
11 | while (breakIterator.next() != BreakIterator.DONE) {
12 | count++
13 | }
14 |
15 | return count
16 | }
17 |
18 | fun String.breakLines(): String = this.replace(Regex("\\s+"), " ")
--------------------------------------------------------------------------------
/core/common/src/main/java/kr/genti/common/extension/UriExt.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common.extension
2 |
3 | import android.content.ContentResolver
4 | import android.net.Uri
5 | import android.provider.OpenableColumns
6 |
7 | fun Uri.getFileName(contentResolver: ContentResolver): String? {
8 | var result: String? = null
9 | if (this.scheme == "content") {
10 | val cursor = contentResolver.query(this, null, null, null, null)
11 | try {
12 | if (cursor != null && cursor.moveToFirst()) {
13 | val columnIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
14 | if (columnIndex != -1) result = cursor.getString(columnIndex)
15 | }
16 | } finally {
17 | cursor?.close()
18 | }
19 | }
20 | if (result == null) {
21 | result = this.path
22 | val cut = result?.lastIndexOf('/')
23 | if (cut != -1) result = result?.substring(cut!! + 1)
24 | }
25 | return result
26 | }
27 |
--------------------------------------------------------------------------------
/core/common/src/main/java/kr/genti/common/util/DoubleBackHandler.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common.util
2 |
3 | import androidx.activity.compose.BackHandler
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.runtime.getValue
6 | import androidx.compose.runtime.mutableLongStateOf
7 | import androidx.compose.runtime.remember
8 | import androidx.compose.runtime.setValue
9 | import androidx.navigation.NavController
10 |
11 | @Composable
12 | fun DoubleBackHandler(
13 | navController: NavController,
14 | timeInterval: Long = 2_000L,
15 | onFirstBack: () -> Unit,
16 | onSecondBack: () -> Unit
17 | ) {
18 | var lastBackTime by remember { mutableLongStateOf(0L) }
19 |
20 | BackHandler {
21 | val now = System.currentTimeMillis()
22 |
23 | when {
24 | navController.previousBackStackEntry != null -> navController.popBackStack()
25 |
26 | now - lastBackTime >= timeInterval -> {
27 | lastBackTime = now
28 | onFirstBack()
29 | }
30 |
31 | else -> onSecondBack()
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/core/common/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/core/common/src/test/java/kr/genti/common/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.common
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/datastore/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidLibrary")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.core.datastore"
7 | }
--------------------------------------------------------------------------------
/core/datastore/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/datastore/consumer-rules.pro
--------------------------------------------------------------------------------
/core/datastore/src/androidTest/java/kr/genti/datastore/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.datastore
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.datastore.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/datastore/src/main/java/kr/genti/datastore/di/SharedPrefModule.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.datastore.di
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.qualifiers.ApplicationContext
9 | import dagger.hilt.components.SingletonComponent
10 | import kr.genti.datastore.local.UserSharedPref
11 | import kr.genti.datastore.local.UserSharedPrefImpl
12 | import javax.inject.Singleton
13 |
14 | @Module
15 | @InstallIn(SingletonComponent::class)
16 | object SharedPrefModule {
17 | @Provides
18 | @Singleton
19 | fun provideSharedPreferences(
20 | @ApplicationContext context: Context,
21 | ): SharedPreferences = context.getSharedPreferences(context.packageName, Context.MODE_PRIVATE)
22 |
23 | @Provides
24 | @Singleton
25 | fun provideSharedPref(sharedPrefImpl: UserSharedPrefImpl): UserSharedPref = sharedPrefImpl
26 | }
27 |
--------------------------------------------------------------------------------
/core/datastore/src/main/java/kr/genti/datastore/local/UserSharedPref.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.datastore.local
2 |
3 | interface UserSharedPref {
4 | var accessToken: String
5 | var refreshToken: String
6 | var userRole: String
7 |
8 | fun clearInfo()
9 | }
10 |
--------------------------------------------------------------------------------
/core/datastore/src/main/java/kr/genti/datastore/local/UserSharedPrefImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.datastore.local
2 |
3 | import android.content.SharedPreferences
4 | import androidx.core.content.edit
5 | import javax.inject.Inject
6 |
7 | class UserSharedPrefImpl
8 | @Inject
9 | constructor(
10 | private val dataStore: SharedPreferences,
11 | ) : UserSharedPref {
12 | override var accessToken: String
13 | get() = dataStore.getString(ACCESS_TOKEN, "").orEmpty()
14 | set(value) = dataStore.edit { putString(ACCESS_TOKEN, value) }
15 |
16 | override var refreshToken: String
17 | get() = dataStore.getString(REFRESH_TOKEN, "").orEmpty()
18 | set(value) = dataStore.edit { putString(REFRESH_TOKEN, value) }
19 |
20 | override var userRole: String
21 | get() = dataStore.getString(USER_ROLE, "").orEmpty()
22 | set(value) = dataStore.edit { putString(USER_ROLE, value) }
23 |
24 | override fun clearInfo() {
25 | dataStore.edit().clear().apply()
26 | }
27 |
28 | companion object {
29 | private const val ACCESS_TOKEN = "ACCESS_TOKEN"
30 | private const val REFRESH_TOKEN = "REFRESH_TOKEN"
31 | private const val USER_ROLE = "USER_ROLE"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/core/datastore/src/test/java/kr/genti/datastore/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.datastore
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/designsystem/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.core.designsystem"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.core.common)
11 | }
--------------------------------------------------------------------------------
/core/designsystem/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/consumer-rules.pro
--------------------------------------------------------------------------------
/core/designsystem/src/androidTest/java/kr/genti/designsystem/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.designsystem.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/designsystem/src/main/java/kr/genti/designsystem/component/button/CloseButton.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem.component.button
2 |
3 | import androidx.compose.foundation.layout.BoxScope
4 | import androidx.compose.foundation.layout.padding
5 | import androidx.compose.material3.Icon
6 | import androidx.compose.runtime.Composable
7 | import androidx.compose.ui.Alignment
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.graphics.vector.ImageVector
10 | import androidx.compose.ui.res.vectorResource
11 | import androidx.compose.ui.unit.dp
12 | import kr.genti.common.extension.noRippleClickable
13 | import kr.genti.core.designsystem.R
14 | import kr.genti.designsystem.theme.White
15 |
16 | @Composable
17 | fun BoxScope.CloseButton(
18 | modifier: Modifier = Modifier,
19 | onCloseBtnClicked: () -> Unit = {}
20 | ) {
21 | Icon(
22 | imageVector = ImageVector.vectorResource(id = R.drawable.ic_close),
23 | contentDescription = null,
24 | tint = White,
25 | modifier = modifier
26 | .padding(16.dp)
27 | .padding(top = 16.dp)
28 | .align(Alignment.TopEnd)
29 | .noRippleClickable { onCloseBtnClicked() }
30 | )
31 | }
--------------------------------------------------------------------------------
/core/designsystem/src/main/java/kr/genti/designsystem/component/item/GentiRatingBar.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem.component.item
2 |
3 | import androidx.compose.foundation.layout.Row
4 | import androidx.compose.material3.Icon
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.vector.ImageVector
8 | import androidx.compose.ui.res.vectorResource
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import kr.genti.common.extension.noRippleClickable
11 | import kr.genti.core.designsystem.R
12 | import kr.genti.designsystem.theme.Disabled
13 | import kr.genti.designsystem.theme.GentiGreen
14 |
15 | @Composable
16 | fun GentiRatingBar(
17 | rating: Int = 5,
18 | onRatingChanged: (Int) -> Unit = {},
19 | ) {
20 | Row {
21 | for (index in 1..5) {
22 | Icon(
23 | imageVector = ImageVector.vectorResource(R.drawable.ic_star),
24 | contentDescription = null,
25 | tint = if (index <= rating) GentiGreen else Disabled,
26 | modifier = Modifier.noRippleClickable { onRatingChanged(index) }
27 | )
28 | }
29 | }
30 | }
31 |
32 | @Preview
33 | @Composable
34 | private fun PreviewGentiRatingBar() {
35 | GentiRatingBar(
36 | rating = 3
37 | )
38 | }
--------------------------------------------------------------------------------
/core/designsystem/src/main/java/kr/genti/designsystem/component/layout/GentiPullToRefreshBox.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem.component.layout
2 |
3 | import androidx.compose.foundation.layout.BoxScope
4 | import androidx.compose.material3.ExperimentalMaterial3Api
5 | import androidx.compose.material3.pulltorefresh.PullToRefreshBox
6 | import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults.Indicator
7 | import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.ui.Alignment
10 | import androidx.compose.ui.Modifier
11 | import kr.genti.designsystem.theme.Gray
12 | import kr.genti.designsystem.theme.White80
13 |
14 | @OptIn(ExperimentalMaterial3Api::class)
15 | @Composable
16 | fun GentiPullToRefreshBox(
17 | modifier: Modifier = Modifier,
18 | isRefreshing: Boolean = false,
19 | onRefresh: () -> Unit = {},
20 | content: @Composable BoxScope.() -> Unit = {}
21 | ) {
22 | val refreshState = rememberPullToRefreshState()
23 |
24 | PullToRefreshBox(
25 | modifier = modifier,
26 | isRefreshing = isRefreshing,
27 | state = refreshState,
28 | onRefresh = onRefresh,
29 | indicator = {
30 | Indicator(
31 | modifier = Modifier.align(Alignment.TopCenter),
32 | isRefreshing = isRefreshing,
33 | containerColor = White80,
34 | color = Gray,
35 | state = refreshState
36 | )
37 | }
38 | ) {
39 | content()
40 | }
41 | }
--------------------------------------------------------------------------------
/core/designsystem/src/main/java/kr/genti/designsystem/event/SnackbarTrigger.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem.event
2 |
3 | import androidx.compose.runtime.staticCompositionLocalOf
4 |
5 | val LocalSnackBarTrigger = staticCompositionLocalOf<(Int) -> Unit> {
6 | error("LocalSnackBarTrigger not provided")
7 | }
--------------------------------------------------------------------------------
/core/designsystem/src/main/java/kr/genti/designsystem/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | // Brand Color
6 | val GentiGreen = Color(0xFF49F155)
7 | val GentiGradationStart = Color(0xFF6CEE2A)
8 | val GentiGradationEnd = Color(0xFF1CF48B)
9 | val GentiGradationEnd66 = Color(0x661CF48B)
10 | val GentiGradationDarkStart = Color(0xFF06261C)
11 | val GentiGradationDarkEnd = Color(0xFF0E2612)
12 |
13 | // System Color
14 | val Black = Color(0xFF030F0F)
15 | val Gray = Color(0xFF192222)
16 | val GrayBtn = Color(0xFF0D2D2B)
17 | val Disabled = Color(0xFF495959)
18 |
19 | // Etc.
20 | val KakaoYellow = Color(0xFFFEE500)
21 | val Red = Color(0xFFF1532F)
22 |
23 | // White
24 | val White = Color(0xFFFFFFFF)
25 | val White80 = Color(0xCCFFFFFF)
26 | val White60 = Color(0x99FFFFFF)
27 | val White40 = Color(0x66FFFFFF)
28 | val White30 = Color(0x4DFFFFFF)
29 | val White20 = Color(0x33FFFFFF)
30 | val White10 = Color(0x1AFFFFFF)
31 |
32 | // Transparent
33 | val Transparent = Color(0x00000000)
34 | val Transparent70 = Color(0xB3000000)
35 | val Transparent60 = Color(0x99000000)
36 | val Transparent50 = Color(0x80000000)
37 | val Transparent30 = Color(0x4D000000)
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_download.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_download_no_border.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_drag_handle.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_female.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_genti_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/ic_genti_launcher.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_kakao.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_male.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_next.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_play.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_star.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/ic_verify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/ic_verify.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_alarm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_alarm.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_alert_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_alert_circle.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_alert_triangle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_alert_triangle.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_empty_image.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
14 |
15 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_glow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_glow.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_gradation_black_bottom.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_gradation_black_top.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_gradation_image_bottom.xml:
--------------------------------------------------------------------------------
1 |
7 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_login_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_login_bg.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_number_one.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_onboarding_first.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_onboarding_first.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_onboarding_second.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_onboarding_second.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_onboarding_third.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_onboarding_third.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_parent_ex_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_parent_ex_1.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_parent_ex_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_parent_ex_2.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_parent_ex_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_parent_ex_3.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_photo_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_photo_add.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_profile_making.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_profile_making.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_ratio_2_3.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_ratio_3_2.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_selfie_one.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_selfie_one.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_selfie_three.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_selfie_three.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_selfie_two.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_selfie_two.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_shine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_shine.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_tooltip_feed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_tooltip_feed.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_tooltip_finished.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_tooltip_finished.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_tooltip_verify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_tooltip_verify.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/img_verify_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/img_verify_bg.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/logo_genti_2d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/logo_genti_2d.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/mock_img_2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/mock_img_2_3.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/drawable/mock_img_3_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/drawable/mock_img_3_2.png
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/font/pretendard_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/font/pretendard_bold.ttf
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/font/pretendard_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/font/pretendard_light.ttf
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/font/pretendard_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/font/pretendard_medium.ttf
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/font/pretendard_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/font/pretendard_regular.ttf
--------------------------------------------------------------------------------
/core/designsystem/src/main/res/font/pretendard_semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/designsystem/src/main/res/font/pretendard_semibold.ttf
--------------------------------------------------------------------------------
/core/designsystem/src/test/java/kr/genti/designsystem/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.designsystem
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/navigation/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.core.navigation"
7 | }
8 |
--------------------------------------------------------------------------------
/core/navigation/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/navigation/consumer-rules.pro
--------------------------------------------------------------------------------
/core/navigation/src/androidTest/java/kr/genti/navigation/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.navigation.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/GenerateRoute.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | interface GenerateRoute : Route {
6 | @Serializable
7 | data class Generate(val isParentPic: Boolean) : GenerateRoute
8 | }
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/MainTabRoute.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | interface MainTabRoute : Route {
6 | @Serializable
7 | data object Feed : MainTabRoute
8 |
9 | @Serializable
10 | data object Generate : MainTabRoute
11 |
12 | @Serializable
13 | data object Profile : MainTabRoute
14 | }
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/OnboardingRoute.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | interface OnboardingRoute : Route {
6 | @Serializable
7 | data object Splash : OnboardingRoute
8 |
9 | @Serializable
10 | data object Login : OnboardingRoute
11 |
12 | @Serializable
13 | data object Signup : OnboardingRoute
14 |
15 | @Serializable
16 | data object Tutorial : OnboardingRoute
17 | }
18 |
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/ResultRoute.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | interface ResultRoute : Route {
6 | @Serializable
7 | data object Verify : ResultRoute
8 |
9 | @Serializable
10 | data class Waiting(
11 | val isParentPic: Boolean
12 | ) : ResultRoute
13 |
14 | @Serializable
15 | data class Finished(
16 | val responseId: Long,
17 | val imageUrl: String,
18 | val isGaro: Boolean,
19 | val isParentPic: Boolean
20 | ) : ResultRoute
21 | }
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/Route.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | interface Route
--------------------------------------------------------------------------------
/core/navigation/src/main/java/kr/genti/navigation/SettingRoute.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | interface SettingRoute : Route {
6 | @Serializable
7 | data object Setting : SettingRoute
8 | }
--------------------------------------------------------------------------------
/core/navigation/src/test/java/kr/genti/navigation/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.navigation
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/core/network/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import kr.genti.convention.extension.implementation
2 | import java.util.Properties
3 |
4 | plugins {
5 | id("kr.genti.androidLibrary")
6 | }
7 |
8 | android {
9 | namespace = "kr.genti.core.network"
10 |
11 | val properties = Properties().apply {
12 | load(rootProject.file("local.properties").inputStream())
13 | }
14 |
15 | buildTypes {
16 | debug {
17 | buildConfigField("String", "BASE_URL", properties["test.base.url"].toString())
18 | }
19 | release {
20 | buildConfigField("String", "BASE_URL", properties["base.url"].toString())
21 | }
22 | }
23 |
24 | buildFeatures {
25 | buildConfig = true
26 | }
27 | }
28 |
29 | dependencies {
30 | implementation(projects.domain)
31 |
32 | implementation(platform(libs.okhttp.bom))
33 | implementation(libs.bundles.okhttp)
34 | implementation(platform(libs.retrofit.bom))
35 | implementation(libs.bundles.retrofit)
36 | implementation(libs.phoenix)
37 | }
--------------------------------------------------------------------------------
/core/network/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/core/network/consumer-rules.pro
--------------------------------------------------------------------------------
/core/network/src/androidTest/java/kr/genti/network/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.network
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.network.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/core/network/src/main/java/kr/genti/network/RetrofitQualifier.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.network
2 |
3 | import javax.inject.Qualifier
4 |
5 | object RetrofitQualifier {
6 | @Qualifier
7 | @Retention(AnnotationRetention.BINARY)
8 | annotation class JWT
9 |
10 | @Qualifier
11 | @Retention(AnnotationRetention.BINARY)
12 | annotation class NOTOKEN
13 | }
14 |
--------------------------------------------------------------------------------
/core/network/src/main/java/kr/genti/network/StringExt.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.network
2 |
3 | fun String?.isJsonObject(): Boolean = this?.startsWith("{") == true && this.endsWith("}")
4 |
5 | fun String?.isJsonArray(): Boolean = this?.startsWith("[") == true && this.endsWith("]")
--------------------------------------------------------------------------------
/core/network/src/test/java/kr/genti/network/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.network
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/data/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import kr.genti.convention.extension.implementation
2 |
3 | plugins {
4 | id("kr.genti.androidLibrary")
5 | }
6 |
7 | android {
8 | namespace = "kr.genti.data"
9 | }
10 |
11 | dependencies {
12 | implementation(projects.domain)
13 | implementation(projects.core.network)
14 | implementation(projects.core.datastore)
15 |
16 | implementation(platform(libs.okhttp.bom))
17 | implementation(libs.bundles.okhttp)
18 | implementation(platform(libs.retrofit.bom))
19 | implementation(libs.bundles.retrofit)
20 | }
21 |
--------------------------------------------------------------------------------
/data/consumer-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/data/src/androidTest/java/kr/genti/data/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.data", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSource/AuthDataSource.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSource
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.AuthRequestDto
5 | import kr.genti.data.dto.request.ReissueRequestDto
6 | import kr.genti.data.dto.response.AuthTokenDto
7 | import kr.genti.data.dto.response.ReissueTokenDto
8 |
9 | interface AuthDataSource {
10 | suspend fun postReissueTokens(request: ReissueRequestDto): BaseResponse
11 |
12 | suspend fun postOauthDataToGetToken(request: AuthRequestDto): BaseResponse
13 | }
14 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSource/CreateDataSource.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSource
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.CreateRequestDto
5 | import kr.genti.data.dto.request.CreateTwoRequestDto
6 | import kr.genti.data.dto.request.KeyRequestDto
7 | import kr.genti.data.dto.request.PurchaseValidRequestDto
8 | import kr.genti.data.dto.request.ImageBucketRequestDto
9 | import kr.genti.data.dto.response.PromptExampleDto
10 | import kr.genti.data.dto.response.ImageBucketDto
11 |
12 | interface CreateDataSource {
13 | suspend fun getSingleImageBucket(request: ImageBucketRequestDto): BaseResponse
14 |
15 | suspend fun getThreeImageBucket(request: List): BaseResponse>
16 |
17 | suspend fun postToCreate(request: CreateRequestDto): BaseResponse
18 |
19 | suspend fun postToCreateOne(request: CreateRequestDto): BaseResponse
20 |
21 | suspend fun postToCreateTwo(request: CreateTwoRequestDto): BaseResponse
22 |
23 | suspend fun postToVerify(request: KeyRequestDto): BaseResponse
24 |
25 | suspend fun getPromptExample(type: String): BaseResponse>
26 |
27 | suspend fun postToValidatePurchase(request: PurchaseValidRequestDto): BaseResponse
28 | }
29 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSource/FeedDataSource.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSource
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.response.FeedItemDto
5 |
6 | interface FeedDataSource {
7 | suspend fun getExampleItems(): BaseResponse>
8 | }
9 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSource/GenerateDataSource.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSource
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.ReportRequestDto
5 | import kr.genti.data.dto.response.GenerateStatusDto
6 | import kr.genti.data.dto.response.OpenchatDto
7 | import kr.genti.data.dto.response.PicturePagedListDto
8 | import kr.genti.data.dto.response.ServerAvailableDto
9 |
10 | interface GenerateDataSource {
11 | suspend fun getGenerateStatus(): BaseResponse
12 |
13 | suspend fun getGeneratedPictureList(
14 | page: Int,
15 | size: Int,
16 | ): BaseResponse
17 |
18 | suspend fun postGenerateReport(request: ReportRequestDto): BaseResponse
19 |
20 | suspend fun postGenerateRate(
21 | responseId: Int,
22 | star: Int,
23 | ): BaseResponse
24 |
25 | suspend fun postVerifyGenerateState(responseId: Int): BaseResponse
26 |
27 | suspend fun getCanceledToReset(requestId: String): BaseResponse
28 |
29 | suspend fun getOpenchatData(): BaseResponse
30 |
31 | suspend fun getIsUserVerified(): BaseResponse
32 |
33 | suspend fun getIsServerAvailable(): BaseResponse
34 |
35 | suspend fun patchStatusInDevelop(): BaseResponse
36 | }
37 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSource/InfoDataSource.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSource
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.SignupRequestDto
5 | import kr.genti.data.dto.response.SignUpUserDto
6 |
7 | interface InfoDataSource {
8 | suspend fun postSignupData(request: SignupRequestDto): BaseResponse
9 |
10 | suspend fun postUserLogout(): BaseResponse
11 |
12 | suspend fun deleteUser(): BaseResponse
13 | }
14 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSourceImpl/AuthDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSourceImpl
2 |
3 | import kr.genti.data.dataSource.AuthDataSource
4 | import kr.genti.data.dto.BaseResponse
5 | import kr.genti.data.dto.request.AuthRequestDto
6 | import kr.genti.data.dto.request.ReissueRequestDto
7 | import kr.genti.data.dto.response.AuthTokenDto
8 | import kr.genti.data.dto.response.ReissueTokenDto
9 | import kr.genti.data.service.AuthService
10 | import javax.inject.Inject
11 |
12 | data class AuthDataSourceImpl
13 | @Inject
14 | constructor(
15 | private val authService: AuthService,
16 | ) : AuthDataSource {
17 | override suspend fun postReissueTokens(request: ReissueRequestDto): BaseResponse =
18 | authService.postReissueTokens(request)
19 |
20 | override suspend fun postOauthDataToGetToken(request: AuthRequestDto): BaseResponse =
21 | authService.postOauthDataToGetToken(request)
22 | }
23 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSourceImpl/FeedDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSourceImpl
2 |
3 | import kr.genti.data.dataSource.FeedDataSource
4 | import kr.genti.data.dto.BaseResponse
5 | import kr.genti.data.dto.response.FeedItemDto
6 | import kr.genti.data.service.FeedService
7 | import javax.inject.Inject
8 |
9 | data class FeedDataSourceImpl
10 | @Inject
11 | constructor(
12 | private val feedService: FeedService,
13 | ) : FeedDataSource {
14 | override suspend fun getExampleItems(): BaseResponse> = feedService.getExampleItems()
15 | }
16 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dataSourceImpl/InfoDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dataSourceImpl
2 |
3 | import kr.genti.data.dataSource.InfoDataSource
4 | import kr.genti.data.dto.BaseResponse
5 | import kr.genti.data.dto.request.SignupRequestDto
6 | import kr.genti.data.dto.response.SignUpUserDto
7 | import kr.genti.data.service.InfoService
8 | import javax.inject.Inject
9 |
10 | data class InfoDataSourceImpl
11 | @Inject
12 | constructor(
13 | private val infoService: InfoService,
14 | ) : InfoDataSource {
15 | override suspend fun postSignupData(request: SignupRequestDto): BaseResponse = infoService.postSignupData(request)
16 |
17 | override suspend fun postUserLogout(): BaseResponse = infoService.postUserLogout()
18 |
19 | override suspend fun deleteUser(): BaseResponse = infoService.deleteUser()
20 | }
21 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/di/DataSourceModule.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.di
2 |
3 | import dagger.Module
4 | import dagger.Provides
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.components.SingletonComponent
7 | import kr.genti.data.dataSource.AuthDataSource
8 | import kr.genti.data.dataSource.CreateDataSource
9 | import kr.genti.data.dataSource.FeedDataSource
10 | import kr.genti.data.dataSource.GenerateDataSource
11 | import kr.genti.data.dataSource.InfoDataSource
12 | import kr.genti.data.dataSourceImpl.AuthDataSourceImpl
13 | import kr.genti.data.dataSourceImpl.CreateDataSourceImpl
14 | import kr.genti.data.dataSourceImpl.FeedDataSourceImpl
15 | import kr.genti.data.dataSourceImpl.GenerateDataSourceImpl
16 | import kr.genti.data.dataSourceImpl.InfoDataSourceImpl
17 | import javax.inject.Singleton
18 |
19 | @Module
20 | @InstallIn(SingletonComponent::class)
21 | object DataSourceModule {
22 | @Provides
23 | @Singleton
24 | fun provideAuthDataSource(authDataSourceImpl: AuthDataSourceImpl): AuthDataSource = authDataSourceImpl
25 |
26 | @Provides
27 | @Singleton
28 | fun provideInfoDataSource(infoDataSourceImpl: InfoDataSourceImpl): InfoDataSource = infoDataSourceImpl
29 |
30 | @Provides
31 | @Singleton
32 | fun provideCreateDataSource(createDataSourceImpl: CreateDataSourceImpl): CreateDataSource = createDataSourceImpl
33 |
34 | @Provides
35 | @Singleton
36 | fun provideFeedDataSource(feedDataSourceImpl: FeedDataSourceImpl): FeedDataSource = feedDataSourceImpl
37 |
38 | @Provides
39 | @Singleton
40 | fun provideGenerateDataSource(generateDataSourceImpl: GenerateDataSourceImpl): GenerateDataSource = generateDataSourceImpl
41 | }
42 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class BaseResponse(
8 | @SerialName("success")
9 | val success: Boolean,
10 | @SerialName("response")
11 | val response: T,
12 | @SerialName("errorCode")
13 | val errorCode: String?,
14 | @SerialName("errorMessage")
15 | val errorMessage: String?,
16 | )
17 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/AuthRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.AuthRequestModel
6 |
7 | @Serializable
8 | data class AuthRequestDto(
9 | @SerialName("accessToken")
10 | val accessToken: String,
11 | @SerialName("fcmToken")
12 | val fcmToken: String,
13 | ) {
14 | companion object {
15 | fun AuthRequestModel.toDto() = AuthRequestDto(accessToken, fcmToken)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.data.dto.request.KeyRequestDto.Companion.toDto
6 | import kr.genti.domain.entity.request.CreateRequestModel
7 | import kr.genti.domain.enums.PictureRatio
8 |
9 | @Serializable
10 | data class CreateRequestDto(
11 | @SerialName("prompt")
12 | val prompt: String,
13 | @SerialName("facePictureList")
14 | val imageS3KeyList: List,
15 | @SerialName("pictureRatio")
16 | val pictureRatio: PictureRatio,
17 | ) {
18 | companion object {
19 | fun CreateRequestModel.toDto() =
20 | CreateRequestDto(
21 | prompt,
22 | imageS3KeyList.map { it.toDto() },
23 | pictureRatio,
24 | )
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/CreateTwoRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.data.dto.request.KeyRequestDto.Companion.toDto
6 | import kr.genti.domain.entity.request.CreateTwoRequestModel
7 | import kr.genti.domain.enums.PictureRatio
8 |
9 | @Serializable
10 | data class CreateTwoRequestDto(
11 | @SerialName("prompt")
12 | val prompt: String,
13 | @SerialName("facePictureList")
14 | val facePictureList: List,
15 | @SerialName("otherFacePictureList")
16 | val otherFacePictureList: List,
17 | @SerialName("pictureRatio")
18 | val pictureRatio: PictureRatio,
19 | ) {
20 | companion object {
21 | fun CreateTwoRequestModel.toDto() =
22 | CreateTwoRequestDto(
23 | prompt,
24 | facePictureList.map { it.toDto() },
25 | otherFacePictureList.map { it.toDto() },
26 | pictureRatio,
27 | )
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/ImageBucketRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.ImageBucketRequestModel
6 | import kr.genti.domain.enums.FileType
7 |
8 | @Serializable
9 | data class ImageBucketRequestDto(
10 | @SerialName("fileType")
11 | val fileType: FileType,
12 | @SerialName("fileName")
13 | val fileName: String,
14 | ) {
15 | companion object {
16 | fun ImageBucketRequestModel.toDto() = ImageBucketRequestDto(fileType, fileName)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/KeyRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.KeyRequestModel
6 |
7 | @Serializable
8 | data class KeyRequestDto(
9 | @SerialName("key")
10 | val key: String?,
11 | ) {
12 | companion object {
13 | fun KeyRequestModel.toDto() = KeyRequestDto(key)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/PurchaseValidRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.PurchaseValidRequestModel
6 |
7 | @Serializable
8 | data class PurchaseValidRequestDto(
9 | @SerialName("packageName")
10 | val packageName: String,
11 | @SerialName("productId")
12 | val productId: String,
13 | @SerialName("purchaseToken")
14 | val purchaseToken: String,
15 | ) {
16 | companion object {
17 | fun PurchaseValidRequestModel.toDto() = PurchaseValidRequestDto(
18 | packageName,
19 | productId,
20 | purchaseToken
21 | )
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/ReissueRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.ReissueRequestModel
6 |
7 | @Serializable
8 | data class ReissueRequestDto(
9 | @SerialName("accessToken")
10 | val accessToken: String,
11 | @SerialName("refreshToken")
12 | val refreshToken: String,
13 | ) {
14 | companion object {
15 | fun ReissueRequestModel.toDto() = ReissueRequestDto(accessToken, refreshToken)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/ReportRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.ReportRequestModel
6 |
7 | @Serializable
8 | data class ReportRequestDto(
9 | @SerialName("pictureGenerateResponseId")
10 | val pictureGenerateResponseId: Long,
11 | @SerialName("content")
12 | val content: String,
13 | ) {
14 | companion object {
15 | fun ReportRequestModel.toDto() = ReportRequestDto(pictureGenerateResponseId, content)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/request/SignupRequestDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.request
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.request.SignupRequestModel
6 |
7 | @Serializable
8 | data class SignupRequestDto(
9 | @SerialName("birthYear")
10 | val birthYear: String,
11 | @SerialName("sex")
12 | val sex: String,
13 | @SerialName("phoneNumber")
14 | val phoneNumber: String?,
15 | ) {
16 | companion object {
17 | fun SignupRequestModel.toDto() = SignupRequestDto(birthYear, sex, phoneNumber)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/AuthTokenDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.AuthTokenModel
6 |
7 | @Serializable
8 | data class AuthTokenDto(
9 | @SerialName("accessToken")
10 | val accessToken: String,
11 | @SerialName("refreshToken")
12 | val refreshToken: String,
13 | @SerialName("userRoleString")
14 | val userRoleString: String,
15 | ) {
16 | fun toModel() = AuthTokenModel(accessToken, refreshToken, userRoleString)
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/FeedItemDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.FeedItemModel
6 |
7 | @Serializable
8 | data class FeedItemDto(
9 | @SerialName("picture")
10 | val picture: ImageDto,
11 | @SerialName("prompt")
12 | val prompt: String,
13 | ) {
14 | fun toModel() =
15 | FeedItemModel(
16 | picture.toModel(),
17 | prompt,
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/GenerateStatusDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.GenerateStatusModel
6 | import kr.genti.domain.enums.GenerateStatus
7 |
8 | @Serializable
9 | data class GenerateStatusDto(
10 | @SerialName("pictureGenerateRequestId")
11 | val pictureGenerateRequestId: Long?,
12 | @SerialName("status")
13 | val status: GenerateStatus,
14 | @SerialName("pictureGenerateResponse")
15 | val pictureGenerateResponse: GenerateResponseDto?,
16 | @SerialName("paid")
17 | val paid: Boolean?,
18 | ) {
19 | @Serializable
20 | data class GenerateResponseDto(
21 | @SerialName("pictureGenerateResponseId")
22 | val pictureGenerateResponseId: Long,
23 | @SerialName("pictureCompleted")
24 | val pictureCompleted: ImageDto?,
25 | ) {
26 | fun toModel() =
27 | GenerateStatusModel.GenerateResponseModel(
28 | pictureGenerateResponseId,
29 | pictureCompleted?.toModel(),
30 | )
31 | }
32 |
33 | fun toModel() =
34 | GenerateStatusModel(
35 | pictureGenerateRequestId,
36 | status,
37 | pictureGenerateResponse?.toModel(),
38 | paid,
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/ImageBucketDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.ImageBucketModel
6 |
7 | @Serializable
8 | data class ImageBucketDto(
9 | @SerialName("fileName")
10 | val fileName: String,
11 | @SerialName("url")
12 | val presignedUrl: String,
13 | @SerialName("s3Key")
14 | val s3Key: String,
15 | ) {
16 | fun toModel() = ImageBucketModel(fileName, presignedUrl, s3Key)
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/ImageDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.ImageModel
6 | import kr.genti.domain.enums.PictureRatio.Companion.toPictureRatio
7 |
8 | @Serializable
9 | data class ImageDto(
10 | @SerialName("id")
11 | val id: Long,
12 | @SerialName("url")
13 | val url: String,
14 | @SerialName("pictureRatio")
15 | val pictureRatio: String,
16 | ) {
17 | fun toModel() =
18 | ImageModel(
19 | id,
20 | url,
21 | pictureRatio.toPictureRatio(),
22 | )
23 | }
24 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/OpenchatDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.OpenchatModel
6 |
7 | @Serializable
8 | data class OpenchatDto(
9 | @SerialName("accessible")
10 | val accessible: Boolean,
11 | @SerialName("count")
12 | val count: Int?,
13 | @SerialName("url")
14 | val url: String?,
15 | ) {
16 | fun toModel() = OpenchatModel(accessible, count, url)
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/PicturePagedListDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.PicturePagedListModel
6 |
7 | @Serializable
8 | data class PicturePagedListDto(
9 | @SerialName("totalPages") val totalPages: Int,
10 | @SerialName("content") val content: List,
11 | ) {
12 | fun toModel() =
13 | PicturePagedListModel(
14 | totalPages,
15 | content.map { it.toModel() },
16 | )
17 | }
18 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/PromptExampleDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.PromptExampleModel
6 |
7 | @Serializable
8 | data class PromptExampleDto(
9 | @SerialName("url")
10 | val url: String,
11 | @SerialName("prompt")
12 | val prompt: String,
13 | ) {
14 | fun toModel() = PromptExampleModel(url, prompt)
15 | }
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/ReissueTokenDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.ReissueTokenModel
6 |
7 | @Serializable
8 | data class ReissueTokenDto(
9 | @SerialName("accessToken")
10 | val accessToken: String,
11 | @SerialName("refreshToken")
12 | val refreshToken: String,
13 | ) {
14 | fun toModel() = ReissueTokenModel(accessToken, refreshToken)
15 | }
16 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/ServerAvailableDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.ServerAvailableModel
6 |
7 | @Serializable
8 | data class ServerAvailableDto(
9 | @SerialName("status")
10 | val status: Boolean,
11 | @SerialName("message")
12 | val message: String?,
13 | ) {
14 | fun toModel() = ServerAvailableModel(status, message)
15 | }
16 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/dto/response/SignUpUserDto.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.dto.response
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kr.genti.domain.entity.response.SignUpUserModel
6 |
7 | @Serializable
8 | data class SignUpUserDto(
9 | @SerialName("email")
10 | val email: String,
11 | @SerialName("lastLoginOauthPlatform")
12 | val lastLoginOauthPlatform: String,
13 | @SerialName("nickname")
14 | val nickname: String,
15 | @SerialName("birthYear")
16 | val birthYear: String,
17 | @SerialName("sex")
18 | val sex: String,
19 | ) {
20 | fun toModel() = SignUpUserModel(email, lastLoginOauthPlatform, nickname, birthYear, sex)
21 | }
22 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/repositoryImpl/AuthRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.repositoryImpl
2 |
3 | import kr.genti.data.dataSource.AuthDataSource
4 | import kr.genti.data.dto.request.AuthRequestDto.Companion.toDto
5 | import kr.genti.data.dto.request.ReissueRequestDto.Companion.toDto
6 | import kr.genti.domain.entity.request.AuthRequestModel
7 | import kr.genti.domain.entity.request.ReissueRequestModel
8 | import kr.genti.domain.entity.response.AuthTokenModel
9 | import kr.genti.domain.entity.response.ReissueTokenModel
10 | import kr.genti.domain.repository.AuthRepository
11 | import javax.inject.Inject
12 |
13 | class AuthRepositoryImpl
14 | @Inject
15 | constructor(
16 | private val authDataSource: AuthDataSource,
17 | ) : AuthRepository {
18 | override suspend fun postReissueTokens(request: ReissueRequestModel): ReissueTokenModel =
19 | authDataSource.postReissueTokens(request.toDto()).response.toModel()
20 |
21 | override suspend fun postOauthDataToGetToken(request: AuthRequestModel): AuthTokenModel =
22 | authDataSource.postOauthDataToGetToken(request.toDto()).response.toModel()
23 | }
24 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/repositoryImpl/FeedRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.repositoryImpl
2 |
3 | import kr.genti.data.dataSource.FeedDataSource
4 | import kr.genti.domain.entity.response.FeedItemModel
5 | import kr.genti.domain.repository.FeedRepository
6 | import javax.inject.Inject
7 |
8 | class FeedRepositoryImpl
9 | @Inject
10 | constructor(
11 | private val feedDataSource: FeedDataSource,
12 | ) : FeedRepository {
13 | override suspend fun getExampleItems(): List =
14 | feedDataSource.getExampleItems().response.map { it.toModel() }
15 | }
16 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/repositoryImpl/InfoRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.repositoryImpl
2 |
3 | import kr.genti.data.dataSource.InfoDataSource
4 | import kr.genti.data.dto.request.SignupRequestDto.Companion.toDto
5 | import kr.genti.domain.entity.request.SignupRequestModel
6 | import kr.genti.domain.entity.response.SignUpUserModel
7 | import kr.genti.domain.repository.InfoRepository
8 | import javax.inject.Inject
9 |
10 | class InfoRepositoryImpl
11 | @Inject
12 | constructor(
13 | private val infoDataSource: InfoDataSource,
14 | ) : InfoRepository {
15 | override suspend fun postSignupData(request: SignupRequestModel): SignUpUserModel =
16 | infoDataSource.postSignupData(request.toDto()).response.toModel()
17 |
18 | override suspend fun postUserLogout(): Boolean =
19 | infoDataSource.postUserLogout().response
20 |
21 | override suspend fun deleteUser(): Boolean =
22 | infoDataSource.deleteUser().response
23 | }
24 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/repositoryImpl/UploadRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.repositoryImpl
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import dagger.hilt.android.qualifiers.ApplicationContext
6 | import kr.genti.data.service.UploadService
7 | import kr.genti.data.util.ContentUriRequestBody
8 | import kr.genti.domain.repository.UploadRepository
9 | import javax.inject.Inject
10 |
11 | class UploadRepositoryImpl
12 | @Inject
13 | constructor(
14 | @ApplicationContext private val context: Context,
15 | private val uploadService: UploadService,
16 | ) : UploadRepository {
17 | override suspend fun uploadImage(
18 | preSignedURL: String,
19 | imageUri: String,
20 | ): Unit =
21 | uploadService.putS3Image(
22 | preSignedURL,
23 | ContentUriRequestBody(context, Uri.parse(imageUri)),
24 | )
25 | }
26 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/repositoryImpl/UserRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.repositoryImpl
2 |
3 | import kr.genti.datastore.local.UserSharedPref
4 | import kr.genti.domain.repository.UserRepository
5 | import javax.inject.Inject
6 |
7 | class UserRepositoryImpl
8 | @Inject
9 | constructor(
10 | private val userSharedPref: UserSharedPref,
11 | ) : UserRepository {
12 | override fun getAccessToken(): String = userSharedPref.accessToken
13 |
14 | override fun getRefreshToken(): String = userSharedPref.refreshToken
15 |
16 | override fun getUserRole(): String = userSharedPref.userRole
17 |
18 | override fun setTokens(
19 | accessToken: String,
20 | refreshToken: String,
21 | ) {
22 | userSharedPref.accessToken = accessToken
23 | userSharedPref.refreshToken = refreshToken
24 | }
25 |
26 | override fun setUserRole(userRole: String) {
27 | userSharedPref.userRole = userRole
28 | }
29 |
30 | override fun clearInfo() {
31 | userSharedPref.clearInfo()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/service/AuthService.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.service
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.AuthRequestDto
5 | import kr.genti.data.dto.request.ReissueRequestDto
6 | import kr.genti.data.dto.response.AuthTokenDto
7 | import kr.genti.data.dto.response.ReissueTokenDto
8 | import retrofit2.http.Body
9 | import retrofit2.http.POST
10 |
11 | interface AuthService {
12 | @POST("auth/v1/reissue")
13 | suspend fun postReissueTokens(
14 | @Body request: ReissueRequestDto,
15 | ): BaseResponse
16 |
17 | @POST("auth/v1/login/oauth2/token/kakao")
18 | suspend fun postOauthDataToGetToken(
19 | @Body request: AuthRequestDto,
20 | ): BaseResponse
21 | }
22 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/service/FeedService.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.service
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.response.FeedItemDto
5 | import retrofit2.http.GET
6 |
7 | interface FeedService {
8 | @GET("api/v1/users/examples/with-picture")
9 | suspend fun getExampleItems(): BaseResponse>
10 | }
11 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/service/InfoService.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.service
2 |
3 | import kr.genti.data.dto.BaseResponse
4 | import kr.genti.data.dto.request.SignupRequestDto
5 | import kr.genti.data.dto.response.SignUpUserDto
6 | import retrofit2.http.Body
7 | import retrofit2.http.DELETE
8 | import retrofit2.http.POST
9 |
10 | interface InfoService {
11 | @POST("api/v2/users/signup")
12 | suspend fun postSignupData(
13 | @Body request: SignupRequestDto,
14 | ): BaseResponse
15 |
16 | @POST("api/v1/users/logout")
17 | suspend fun postUserLogout(): BaseResponse
18 |
19 | @DELETE("api/v1/users")
20 | suspend fun deleteUser(): BaseResponse
21 | }
22 |
--------------------------------------------------------------------------------
/data/src/main/java/kr/genti/data/service/UploadService.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data.service
2 |
3 | import okhttp3.RequestBody
4 | import retrofit2.http.Body
5 | import retrofit2.http.PUT
6 | import retrofit2.http.Url
7 |
8 | interface UploadService {
9 | @PUT
10 | suspend fun putS3Image(
11 | @Url preSignedURL: String,
12 | @Body image: RequestBody,
13 | )
14 | }
15 |
--------------------------------------------------------------------------------
/data/src/test/java/kr/genti/data/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.data
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/domain/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.javaLibrary")
3 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/AuthRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class AuthRequestModel(
4 | val accessToken: String,
5 | val fcmToken: String,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | import kr.genti.domain.enums.PictureRatio
4 |
5 | data class CreateRequestModel(
6 | val prompt: String,
7 | val imageS3KeyList: List,
8 | val pictureRatio: PictureRatio,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateTwoRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | import kr.genti.domain.enums.PictureRatio
4 |
5 | data class CreateTwoRequestModel(
6 | val prompt: String,
7 | val facePictureList: List,
8 | val otherFacePictureList: List,
9 | val pictureRatio: PictureRatio,
10 | )
11 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/ImageBucketRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | import kr.genti.domain.enums.FileType
4 |
5 | data class ImageBucketRequestModel(
6 | val fileType: FileType,
7 | val fileName: String,
8 | )
9 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/KeyRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class KeyRequestModel(
4 | val key: String?,
5 | )
6 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/PurchaseValidRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class PurchaseValidRequestModel(
4 | val packageName: String,
5 | val productId: String,
6 | val purchaseToken: String,
7 | )
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/ReissueRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class ReissueRequestModel(
4 | val accessToken: String,
5 | val refreshToken: String,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/ReportRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class ReportRequestModel(
4 | val pictureGenerateResponseId: Long,
5 | val content: String,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/request/SignupRequestModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.request
2 |
3 | data class SignupRequestModel(
4 | val birthYear: String,
5 | val sex: String,
6 | val phoneNumber: String?,
7 | )
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/AuthTokenModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class AuthTokenModel(
4 | val accessToken: String,
5 | val refreshToken: String,
6 | val userRoleString: String,
7 | )
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/FeedItemModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class FeedItemModel(
4 | val picture: ImageModel,
5 | val prompt: String,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/GenerateStatusModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | import kr.genti.domain.enums.GenerateStatus
4 |
5 | data class GenerateStatusModel(
6 | val requestId: Long?,
7 | val status: GenerateStatus,
8 | val response: GenerateResponseModel?,
9 | val paid: Boolean?,
10 | ) {
11 | data class GenerateResponseModel(
12 | val responseId: Long,
13 | val picture: ImageModel?,
14 | )
15 |
16 | companion object {
17 | fun emptyGenerateStatusModel() = GenerateStatusModel(
18 | requestId = null,
19 | status = GenerateStatus.EMPTY,
20 | response = null,
21 | paid = null,
22 | )
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/ImageBucketModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class ImageBucketModel(
4 | val fileName: String,
5 | val presignedUrl: String,
6 | val s3Key: String,
7 | )
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/ImageFileModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class ImageFileModel(
4 | var id: Long,
5 | var name: String,
6 | var url: String,
7 | ) {
8 | companion object {
9 | fun emptyImageFileModel() = ImageFileModel(-1, "", "")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/ImageModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | import kr.genti.domain.enums.PictureRatio
4 |
5 | data class ImageModel(
6 | val id: Long,
7 | val url: String,
8 | val pictureRatio: PictureRatio?,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/OpenchatModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class OpenchatModel(
4 | val accessible: Boolean,
5 | val count: Int?,
6 | val url: String?,
7 | )
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/PicturePagedListModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class PicturePagedListModel(
4 | val totalPages: Int,
5 | val content: List,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/PromptExampleModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class PromptExampleModel(
4 | val url: String,
5 | val prompt: String,
6 | )
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/ReissueTokenModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class ReissueTokenModel(
4 | val accessToken: String,
5 | val refreshToken: String,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/ServerAvailableModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class ServerAvailableModel(
4 | val status: Boolean,
5 | val message: String?,
6 | )
7 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/entity/response/SignUpUserModel.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.entity.response
2 |
3 | data class SignUpUserModel(
4 | val email: String,
5 | val lastLoginOauthPlatform: String,
6 | val nickname: String,
7 | val birthYear: String,
8 | val sex: String,
9 | )
10 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/enums/FileType.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.enums
2 |
3 | enum class FileType {
4 | CREATED_IMAGE,
5 | ADMIN_UPLOADED_IMAGE,
6 | USER_UPLOADED_IMAGE,
7 | USER_VERIFICATION_IMAGE,
8 | DEV_USER_VERIFICATION_IMAGE,
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/enums/Gender.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.enums
2 |
3 | enum class Gender {
4 | M,
5 | W,
6 | NONE,
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/enums/GenerateStatus.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.enums
2 |
3 | enum class GenerateStatus {
4 | IN_PROGRESS,
5 | AWAIT_USER_VERIFICATION,
6 | NEW_REQUEST_AVAILABLE,
7 | CANCELED,
8 | EMPTY,
9 | }
10 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/enums/PictureNumber.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.enums
2 |
3 | enum class PictureNumber {
4 | ONE,
5 | TWO,
6 | NONE
7 | ;
8 |
9 | companion object {
10 | fun String.toPictureNumber(): PictureNumber =
11 | when (this) {
12 | "ONE" -> ONE
13 | "TWO" -> TWO
14 | else -> NONE
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/enums/PictureRatio.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.enums
2 |
3 | enum class PictureRatio {
4 | RATIO_SERO,
5 | RATIO_GARO,
6 | NONE
7 | ;
8 |
9 | companion object {
10 | fun String.toPictureRatio(): PictureRatio =
11 | when (this) {
12 | "RATIO_GARO" -> RATIO_GARO
13 | "RATIO_SERO" -> RATIO_SERO
14 | else -> NONE
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/AuthRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | import kr.genti.domain.entity.request.AuthRequestModel
4 | import kr.genti.domain.entity.request.ReissueRequestModel
5 | import kr.genti.domain.entity.response.AuthTokenModel
6 | import kr.genti.domain.entity.response.ReissueTokenModel
7 |
8 | interface AuthRepository {
9 | suspend fun postReissueTokens(request: ReissueRequestModel): ReissueTokenModel
10 |
11 | suspend fun postOauthDataToGetToken(request: AuthRequestModel): AuthTokenModel
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/CreateRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | import kr.genti.domain.entity.request.CreateRequestModel
4 | import kr.genti.domain.entity.request.CreateTwoRequestModel
5 | import kr.genti.domain.entity.request.KeyRequestModel
6 | import kr.genti.domain.entity.request.PurchaseValidRequestModel
7 | import kr.genti.domain.entity.request.ImageBucketRequestModel
8 | import kr.genti.domain.entity.response.PromptExampleModel
9 | import kr.genti.domain.entity.response.ImageBucketModel
10 |
11 | interface CreateRepository {
12 | suspend fun getSingleImageBucket(request: ImageBucketRequestModel): ImageBucketModel
13 |
14 | suspend fun getThreeImageBucket(request: List): List
15 |
16 | suspend fun postToCreate(request: CreateRequestModel): Boolean
17 |
18 | suspend fun postToCreateOne(request: CreateRequestModel): Boolean
19 |
20 | suspend fun postToCreateTwo(request: CreateTwoRequestModel): Boolean
21 |
22 | suspend fun postToVerify(request: KeyRequestModel): Boolean
23 |
24 | suspend fun getPromptExample(type: String): List
25 |
26 | suspend fun postToValidatePurchase(request: PurchaseValidRequestModel): Boolean
27 | }
28 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/FeedRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | import kr.genti.domain.entity.response.FeedItemModel
4 |
5 | interface FeedRepository {
6 | suspend fun getExampleItems(): List
7 | }
8 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/GenerateRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | import kr.genti.domain.entity.request.ReportRequestModel
4 | import kr.genti.domain.entity.response.GenerateStatusModel
5 | import kr.genti.domain.entity.response.OpenchatModel
6 | import kr.genti.domain.entity.response.PicturePagedListModel
7 | import kr.genti.domain.entity.response.ServerAvailableModel
8 |
9 | interface GenerateRepository {
10 | suspend fun getGenerateStatus(): GenerateStatusModel
11 |
12 | suspend fun postGenerateReport(request: ReportRequestModel): Boolean
13 |
14 | suspend fun postGenerateRate(responseId: Int, star: Int): Boolean
15 |
16 | suspend fun postVerifyGenerateState(responseId: Int): Boolean
17 |
18 | suspend fun getCanceledToReset(requestId: String): Boolean
19 |
20 | suspend fun getGeneratedPictureList(page: Int, size: Int): PicturePagedListModel
21 |
22 | suspend fun getOpenchatData(): OpenchatModel
23 |
24 | suspend fun getIsUserVerified(): Boolean
25 |
26 | suspend fun getIsServerAvailable(): ServerAvailableModel
27 |
28 | suspend fun patchStatusInDevelop(): Boolean
29 | }
30 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/InfoRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | import kr.genti.domain.entity.request.SignupRequestModel
4 | import kr.genti.domain.entity.response.SignUpUserModel
5 |
6 | interface InfoRepository {
7 | suspend fun postSignupData(request: SignupRequestModel): SignUpUserModel
8 |
9 | suspend fun postUserLogout(): Boolean
10 |
11 | suspend fun deleteUser(): Boolean
12 | }
13 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/UploadRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | interface UploadRepository {
4 | suspend fun uploadImage(
5 | preSignedURL: String,
6 | imageUri: String,
7 | )
8 | }
9 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/repository/UserRepository.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.repository
2 |
3 | interface UserRepository {
4 | fun getAccessToken(): String
5 |
6 | fun getRefreshToken(): String
7 |
8 | fun getUserRole(): String
9 |
10 | fun setTokens(
11 | accessToken: String,
12 | refreshToken: String,
13 | )
14 |
15 | fun setUserRole(userRole: String)
16 |
17 | fun clearInfo()
18 | }
19 |
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/auth/GetNewTokensFromOauthUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.auth
2 |
3 | import kr.genti.domain.entity.request.AuthRequestModel
4 | import kr.genti.domain.repository.AuthRepository
5 | import kr.genti.domain.repository.UserRepository
6 | import javax.inject.Inject
7 |
8 | class GetNewTokensFromOauthUseCase @Inject constructor(
9 | private val authRepository: AuthRepository,
10 | private val userRepository: UserRepository
11 | ) {
12 | suspend operator fun invoke(
13 | newAccessToken: String,
14 | fcmToken: String
15 | ): Result =
16 | runCatching {
17 | val request = AuthRequestModel(newAccessToken, fcmToken)
18 | val response = authRepository.postOauthDataToGetToken(request)
19 | with(userRepository) {
20 | setTokens(response.accessToken, response.refreshToken)
21 | setUserRole(response.userRoleString)
22 | }
23 | val isAssigned = response.userRoleString == ALREADY_ASSIGNED
24 | return@runCatching isAssigned
25 | }
26 |
27 | companion object {
28 | const val ALREADY_ASSIGNED = "USER"
29 | }
30 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/auth/ReissueOldTokensUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.auth
2 |
3 | import kr.genti.domain.entity.request.ReissueRequestModel
4 | import kr.genti.domain.entity.response.ReissueTokenModel
5 | import kr.genti.domain.repository.AuthRepository
6 | import kr.genti.domain.repository.UserRepository
7 | import javax.inject.Inject
8 |
9 | class ReissueOldTokensUseCase @Inject constructor(
10 | private val authRepository: AuthRepository,
11 | private val userRepository: UserRepository
12 | ) {
13 | suspend operator fun invoke(): Result =
14 | runCatching {
15 | val response = authRepository.postReissueTokens(
16 | ReissueRequestModel(
17 | userRepository.getAccessToken(),
18 | userRepository.getRefreshToken()
19 | )
20 | )
21 | userRepository.setTokens(
22 | response.accessToken,
23 | response.refreshToken
24 | )
25 | return@runCatching response
26 | }
27 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/auth/SignUpUserUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.auth
2 |
3 | import kr.genti.domain.entity.request.SignupRequestModel
4 | import kr.genti.domain.entity.response.SignUpUserModel
5 | import kr.genti.domain.enums.Gender
6 | import kr.genti.domain.repository.InfoRepository
7 | import kr.genti.domain.repository.UserRepository
8 | import javax.inject.Inject
9 |
10 | class SignUpUserUseCase @Inject constructor(
11 | private val infoRepository: InfoRepository,
12 | private val userRepository: UserRepository
13 | ) {
14 | suspend operator fun invoke(
15 | birthYear: String,
16 | gender: Gender,
17 | phoneNumber: String? = null
18 | ): Result =
19 | runCatching {
20 | val request = SignupRequestModel(
21 | birthYear,
22 | gender.toString(),
23 | phoneNumber
24 | )
25 | val response = infoRepository.postSignupData(request)
26 | userRepository.setUserRole(ROLE_USER)
27 | return@runCatching response
28 | }
29 |
30 | companion object {
31 | private const val ROLE_USER = "USER"
32 | }
33 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/feed/GetFeedItemListUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.feed
2 |
3 | import kr.genti.domain.entity.response.FeedItemModel
4 | import kr.genti.domain.repository.FeedRepository
5 | import javax.inject.Inject
6 |
7 | class GetFeedItemListUseCase @Inject constructor(
8 | private val feedRepository: FeedRepository
9 | ) {
10 | suspend operator fun invoke(): Result> =
11 | runCatching {
12 | val response = feedRepository.getExampleItems()
13 | return@runCatching response
14 | }
15 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/generate/CheckPurchaseValidUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.generate
2 |
3 | import kr.genti.domain.entity.request.PurchaseValidRequestModel
4 | import kr.genti.domain.repository.CreateRepository
5 | import javax.inject.Inject
6 |
7 | class CheckPurchaseValidUseCase @Inject constructor(
8 | private val createRepository: CreateRepository,
9 | ) {
10 | suspend operator fun invoke(
11 | packageName: String,
12 | productId: String,
13 | purchaseToken: String,
14 | ): Result =
15 | runCatching {
16 | val request = PurchaseValidRequestModel(
17 | packageName = packageName,
18 | productId = productId,
19 | purchaseToken = purchaseToken
20 | )
21 | val isSuccess = createRepository.postToValidatePurchase(request)
22 | if (isSuccess) {
23 | return@runCatching true
24 | } else {
25 | throw Exception("checking purchase valid failed")
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/generate/CheckServerAvailableUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.generate
2 |
3 | import kr.genti.domain.entity.response.ServerAvailableModel
4 | import kr.genti.domain.repository.GenerateRepository
5 | import javax.inject.Inject
6 |
7 | class CheckServerAvailableUseCase @Inject constructor(
8 | private val generateRepository: GenerateRepository,
9 | ) {
10 | suspend operator fun invoke(): Result =
11 | runCatching {
12 | val response = generateRepository.getIsServerAvailable()
13 | return@runCatching response
14 | }
15 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/generate/GetPromptExampleListUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.generate
2 |
3 | import kr.genti.domain.entity.response.PromptExampleModel
4 | import kr.genti.domain.repository.CreateRepository
5 | import javax.inject.Inject
6 |
7 | class GetPromptExampleListUseCase @Inject constructor(
8 | private val createRepository: CreateRepository,
9 | ) {
10 | suspend operator fun invoke(
11 | generateType: String,
12 | ): Result> =
13 | runCatching {
14 | val response = createRepository.getPromptExample(generateType)
15 | return@runCatching response
16 | }
17 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/generate/GetThreeImageBucketUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.generate
2 |
3 | import kr.genti.domain.entity.request.ImageBucketRequestModel
4 | import kr.genti.domain.entity.response.ImageBucketModel
5 | import kr.genti.domain.entity.response.ImageFileModel
6 | import kr.genti.domain.enums.FileType
7 | import kr.genti.domain.repository.CreateRepository
8 | import javax.inject.Inject
9 |
10 | class GetThreeImageBucketUseCase @Inject constructor(
11 | private val createRepository: CreateRepository,
12 | ) {
13 | suspend operator fun invoke(
14 | selectedImageList: List
15 | ): Result> =
16 | runCatching {
17 | val request = selectedImageList.map { image ->
18 | ImageBucketRequestModel(FileType.USER_UPLOADED_IMAGE, image.name)
19 | }
20 | val response = createRepository.getThreeImageBucket(request)
21 | return@runCatching response
22 | }
23 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/profile/GetGeneratedPictureListUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.profile
2 |
3 | import kr.genti.domain.entity.response.PicturePagedListModel
4 | import kr.genti.domain.repository.GenerateRepository
5 | import javax.inject.Inject
6 |
7 | class GetGeneratedPictureListUseCase @Inject constructor(
8 | private val generateRepository: GenerateRepository
9 | ) {
10 | suspend operator fun invoke(
11 | page: Int,
12 | size: Int = 10
13 | ): Result =
14 | runCatching {
15 | val response = generateRepository.getGeneratedPictureList(
16 | page = page,
17 | size = size
18 | )
19 | return@runCatching response
20 | }
21 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/ForceGenerateInDebugUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.repository.GenerateRepository
4 | import javax.inject.Inject
5 |
6 | class ForceGenerateInDebugUseCase @Inject constructor(
7 | private val generateRepository: GenerateRepository
8 | ) {
9 | suspend operator fun invoke(): Result =
10 | runCatching {
11 | val isSuccess = generateRepository.patchStatusInDevelop()
12 | if (isSuccess) {
13 | return@runCatching true
14 | } else {
15 | throw Exception("force generate in debug failed")
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/GetCurrentGenerateStatusUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.entity.response.GenerateStatusModel
4 | import kr.genti.domain.repository.GenerateRepository
5 | import javax.inject.Inject
6 |
7 | class GetCurrentGenerateStatusUseCase @Inject constructor(
8 | private val generateRepository: GenerateRepository,
9 | ) {
10 | suspend operator fun invoke(): Result =
11 | runCatching {
12 | val response = generateRepository.getGenerateStatus()
13 | return@runCatching response
14 | }
15 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/ReportUnwantedResultUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.entity.request.ReportRequestModel
4 | import kr.genti.domain.repository.GenerateRepository
5 | import javax.inject.Inject
6 |
7 | class ReportUnwantedResultUseCase @Inject constructor(
8 | private val generateRepository: GenerateRepository
9 | ) {
10 | suspend operator fun invoke(
11 | imageResponseId: Long,
12 | reportText: String
13 | ): Result =
14 | runCatching {
15 | val request = ReportRequestModel(
16 | pictureGenerateResponseId = imageResponseId,
17 | content = reportText
18 | )
19 | val isSuccess = generateRepository.postGenerateReport(request)
20 | if (isSuccess) {
21 | return@runCatching true
22 | } else {
23 | throw Exception("reporting generate result failed")
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/ResetGenerateStatusUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.repository.GenerateRepository
4 | import javax.inject.Inject
5 |
6 | class ResetGenerateStatusUseCase @Inject constructor(
7 | private val generateRepository: GenerateRepository
8 | ) {
9 | suspend operator fun invoke(
10 | generateRequestId: Long?
11 | ): Result =
12 | runCatching {
13 | val isSuccess = generateRepository.getCanceledToReset(
14 | requestId = requireNotNull(generateRequestId) { "generateRequestId is null" }.toString()
15 | )
16 | if (isSuccess) {
17 | return@runCatching true
18 | } else {
19 | throw Exception("resetting generate status failed")
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/SkipGenerateRatingUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.repository.GenerateRepository
4 | import javax.inject.Inject
5 |
6 | class SkipGenerateRatingUseCase @Inject constructor(
7 | private val generateRepository: GenerateRepository
8 | ) {
9 | suspend operator fun invoke(
10 | imageResponseId: Long,
11 | ): Result =
12 | runCatching {
13 | val isSuccess = generateRepository.postVerifyGenerateState(
14 | responseId = imageResponseId.toInt()
15 | )
16 | if (isSuccess) {
17 | return@runCatching true
18 | } else {
19 | throw Exception("skipping generate rating failed")
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/result/SubmitGenerateRatingUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.result
2 |
3 | import kr.genti.domain.repository.GenerateRepository
4 | import javax.inject.Inject
5 |
6 | class SubmitGenerateRatingUseCase @Inject constructor(
7 | private val generateRepository: GenerateRepository
8 | ) {
9 | suspend operator fun invoke(
10 | imageResponseId: Long,
11 | starRate: Int
12 | ): Result =
13 | runCatching {
14 | val isSuccess = generateRepository.postGenerateRate(
15 | responseId = imageResponseId.toInt(),
16 | star = starRate,
17 | )
18 | if (isSuccess) {
19 | return@runCatching true
20 | } else {
21 | throw Exception("submitting generate rating failed")
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/setting/DeleteUserUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.setting
2 |
3 | import kr.genti.domain.repository.InfoRepository
4 | import kr.genti.domain.repository.UserRepository
5 | import javax.inject.Inject
6 |
7 | class DeleteUserUseCase @Inject constructor(
8 | private val infoRepository: InfoRepository,
9 | private val userRepository: UserRepository
10 | ) {
11 | suspend operator fun invoke(): Result =
12 | runCatching {
13 | val isSuccess = infoRepository.deleteUser()
14 | userRepository.clearInfo()
15 | if (isSuccess) {
16 | return@runCatching true
17 | } else {
18 | throw Exception("delete failed")
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/setting/LogoutUserUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.setting
2 |
3 | import kr.genti.domain.repository.InfoRepository
4 | import kr.genti.domain.repository.UserRepository
5 | import javax.inject.Inject
6 |
7 | class LogoutUserUseCase @Inject constructor(
8 | private val infoRepository: InfoRepository,
9 | private val userRepository: UserRepository
10 | ) {
11 | suspend operator fun invoke(): Result =
12 | runCatching {
13 | val isSuccess = infoRepository.postUserLogout()
14 | userRepository.clearInfo()
15 | if (isSuccess) {
16 | return@runCatching true
17 | } else {
18 | throw Exception("logout failed")
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/upload/UploadImageToBucketUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.upload
2 |
3 | import kr.genti.domain.repository.UploadRepository
4 | import javax.inject.Inject
5 |
6 | class UploadImageToBucketUseCase @Inject constructor(
7 | private val uploadRepository: UploadRepository,
8 | ) {
9 | suspend operator fun invoke(
10 | bucketUrl: String?,
11 | imageUrl: String?,
12 | ): Result =
13 | runCatching {
14 | val response = uploadRepository.uploadImage(
15 | preSignedURL = requireNotNull(bucketUrl) { "bucketUrl is null" },
16 | imageUri = requireNotNull(imageUrl) { "imageUrl is null" },
17 | )
18 | return@runCatching response
19 | }
20 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/verify/CheckUserVerifiedUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.verify
2 |
3 | import kr.genti.domain.repository.GenerateRepository
4 | import javax.inject.Inject
5 |
6 | class CheckUserVerifiedUseCase @Inject constructor(
7 | private val generateRepository: GenerateRepository,
8 | ) {
9 | suspend operator fun invoke(): Result =
10 | runCatching {
11 | val isVerified = generateRepository.getIsUserVerified()
12 | return@runCatching isVerified
13 | }
14 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/verify/CheckVerifyImageUploadedUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.verify
2 |
3 | import kr.genti.domain.entity.request.KeyRequestModel
4 | import kr.genti.domain.repository.CreateRepository
5 | import javax.inject.Inject
6 |
7 | class CheckVerifyImageUploadedUseCase @Inject constructor(
8 | private val createRepository: CreateRepository,
9 | ) {
10 | suspend operator fun invoke(
11 | bucketKey: String?,
12 | ): Result =
13 | runCatching {
14 | val request = KeyRequestModel(bucketKey)
15 | val isSuccess = createRepository.postToVerify(request)
16 | if (isSuccess) {
17 | return@runCatching true
18 | } else {
19 | throw Exception("checking verify image in bucket failed")
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/domain/src/main/kotlin/kr/genti/domain/usecase/verify/GetVerifyImageBucketUseCase.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.domain.usecase.verify
2 |
3 | import kr.genti.domain.entity.request.ImageBucketRequestModel
4 | import kr.genti.domain.entity.response.ImageBucketModel
5 | import kr.genti.domain.enums.FileType
6 | import kr.genti.domain.repository.CreateRepository
7 | import javax.inject.Inject
8 |
9 | class GetVerifyImageBucketUseCase @Inject constructor(
10 | private val createRepository: CreateRepository,
11 | ) {
12 | suspend operator fun invoke(
13 | imageName: String?,
14 | isDebugMode: Boolean,
15 | ): Result =
16 | runCatching {
17 | val request = ImageBucketRequestModel(
18 | fileType = if (isDebugMode) FileType.DEV_USER_VERIFICATION_IMAGE else FileType.USER_VERIFICATION_IMAGE,
19 | fileName = requireNotNull(imageName) { "imageName is null" },
20 | )
21 | val response = createRepository.getSingleImageBucket(request)
22 | return@runCatching response
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/feed/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.feed"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 | }
--------------------------------------------------------------------------------
/feature/feed/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/feed/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/feed/src/androidTest/java/kr/genti/feed/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.feed.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/feed/src/main/java/kr/genti/feed/FeedIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed
2 |
3 | sealed class FeedIntent {
4 | data object Init: FeedIntent()
5 | data object Refresh: FeedIntent()
6 | data object InfoBtnClick: FeedIntent()
7 | data object TooltipClick: FeedIntent()
8 | data object ListScroll: FeedIntent()
9 | data object BottomSheetDismiss: FeedIntent()
10 | data object MoreBtnClick: FeedIntent()
11 | }
--------------------------------------------------------------------------------
/feature/feed/src/main/java/kr/genti/feed/FeedSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed
2 |
3 | sealed class FeedSideEffect {
4 | data object ShowErrorToast : FeedSideEffect()
5 | data class NavigateToWebsite(val url: String) : FeedSideEffect()
6 | }
--------------------------------------------------------------------------------
/feature/feed/src/main/java/kr/genti/feed/FeedState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed
2 |
3 | import kotlinx.collections.immutable.ImmutableList
4 | import kotlinx.collections.immutable.persistentListOf
5 | import kr.genti.domain.entity.response.FeedItemModel
6 |
7 | data class FeedState(
8 | val itemList: ImmutableList = persistentListOf(),
9 | val isRefreshing: Boolean = false,
10 | val isTooltipVisible: Boolean = false,
11 | val isTooltipClosed: Boolean = false,
12 | val isBottomSheetVisible: Boolean = false,
13 | val isLoading: Boolean = false,
14 | )
--------------------------------------------------------------------------------
/feature/feed/src/main/java/kr/genti/feed/component/FeedBottomTooltip.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed.component
2 |
3 | import androidx.compose.animation.AnimatedVisibility
4 | import androidx.compose.animation.fadeIn
5 | import androidx.compose.animation.fadeOut
6 | import androidx.compose.foundation.Image
7 | import androidx.compose.foundation.layout.Box
8 | import androidx.compose.foundation.layout.padding
9 | import androidx.compose.foundation.layout.width
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.res.painterResource
13 | import androidx.compose.ui.tooling.preview.Preview
14 | import androidx.compose.ui.unit.dp
15 | import kr.genti.common.extension.noRippleClickable
16 | import kr.genti.core.designsystem.R
17 |
18 | @Composable
19 | internal fun FeedBottomTooltip(
20 | modifier: Modifier = Modifier,
21 | isTooltipVisible: Boolean = false,
22 | onTooltipClick: () -> Unit = {}
23 | ) {
24 | Box(modifier = modifier) {
25 | AnimatedVisibility(
26 | visible = isTooltipVisible,
27 | enter = fadeIn(),
28 | exit = fadeOut()
29 | ) {
30 | Image(
31 | painter = painterResource(R.drawable.img_tooltip_feed),
32 | contentDescription = null,
33 | modifier = Modifier
34 | .width(174.dp)
35 | .padding(bottom = 16.dp)
36 | .noRippleClickable { onTooltipClick() }
37 | )
38 | }
39 | }
40 | }
41 |
42 | @Preview
43 | @Composable
44 | private fun FeedBottomTooltipPreview() {
45 | FeedBottomTooltip(isTooltipVisible = true)
46 | }
--------------------------------------------------------------------------------
/feature/feed/src/main/java/kr/genti/feed/navigation/FeedNavigation.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.feed.navigation
2 |
3 | import androidx.compose.foundation.layout.PaddingValues
4 | import androidx.navigation.NavController
5 | import androidx.navigation.NavGraphBuilder
6 | import androidx.navigation.NavOptions
7 | import androidx.navigation.compose.composable
8 | import kr.genti.feed.FeedRoute
9 | import kr.genti.navigation.MainTabRoute
10 |
11 | fun NavController.navigateToFeed(
12 | navOptions: NavOptions? = null
13 | ) {
14 | navigate(MainTabRoute.Feed, navOptions)
15 | }
16 |
17 | fun NavGraphBuilder.feedNavGraph(
18 | paddingValues: PaddingValues
19 | ) {
20 | composable {
21 | FeedRoute(paddingValues)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/feature/generate/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.generate"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 |
15 | implementation(libs.billing.client)
16 | }
--------------------------------------------------------------------------------
/feature/generate/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/generate/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/generate/src/androidTest/java/kr/genti/generate/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.generate.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/GenerateIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate
2 |
3 | import android.net.Uri
4 | import com.android.billingclient.api.Purchase
5 | import kr.genti.domain.enums.PictureNumber
6 | import kr.genti.domain.enums.PictureRatio
7 |
8 | sealed class GenerateIntent {
9 | data class Init(val isParentPic: Boolean) : GenerateIntent()
10 | data object BackBtnClick : GenerateIntent()
11 | data object NextBtnClick : GenerateIntent()
12 | data class NumberSelect(val pictureNumber: PictureNumber) : GenerateIntent()
13 | data object PromptExampleSwipe : GenerateIntent()
14 | data class PromptChange(val prompt: String) : GenerateIntent()
15 | data class RatioSelect(val pictureRatio: PictureRatio) : GenerateIntent()
16 | data class TextFieldFocused(val isFocused: Boolean) : GenerateIntent()
17 | data class ImageSelectBtnClick(val isExtra: Boolean) : GenerateIntent()
18 | data class ImageSelect(val uriList: List) : GenerateIntent()
19 | data class PurchaseSuccess(val purchase: Purchase) : GenerateIntent()
20 | data object PurchaseFailure : GenerateIntent()
21 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/GenerateSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate
2 |
3 | sealed class GenerateSideEffect {
4 | data object ShowErrorToast : GenerateSideEffect()
5 | data class NavigateToWaiting(val isParentPic: Boolean) : GenerateSideEffect()
6 | data object NavigateToBack : GenerateSideEffect()
7 | data object StartImageSelect : GenerateSideEffect()
8 | data object StartPurchaseProduct : GenerateSideEffect()
9 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/GenerateState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate
2 |
3 | import kotlinx.collections.immutable.ImmutableList
4 | import kotlinx.collections.immutable.persistentListOf
5 | import kr.genti.domain.entity.response.ImageFileModel
6 | import kr.genti.domain.entity.response.PromptExampleModel
7 | import kr.genti.domain.enums.PictureNumber
8 | import kr.genti.domain.enums.PictureRatio
9 | import kr.genti.generate.model.GenerateStage
10 | import kr.genti.generate.model.GenerateType
11 | import kr.genti.generate.model.GenerateType.Companion.getGenerateType
12 |
13 | data class GenerateState(
14 | val currentStage: GenerateStage = GenerateStage.INIT,
15 | val currentStep: Int = 0,
16 | val isParentPic: Boolean = false,
17 | val isRequestLoading: Boolean = false,
18 | val isBillingLoading: Boolean = false,
19 | val pictureNumber: PictureNumber = PictureNumber.NONE,
20 | val exampleList: ImmutableList = persistentListOf(),
21 | val prompt: String = "",
22 | val isFocusClearNeeded: Boolean = false,
23 | val pictureRatio: PictureRatio = PictureRatio.NONE,
24 | val isSelectingExtra: Boolean = false,
25 | val imageList: List = listOf(),
26 | val extraImageList: List = listOf(),
27 | ) {
28 | val progress: Float
29 | get() = currentStep / if (!isParentPic) 3F else 4F
30 |
31 | val generateType: GenerateType
32 | get() = getGenerateType(isParentPic, pictureNumber)
33 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/billing/BillingCallback.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate.billing
2 |
3 | import com.android.billingclient.api.Purchase
4 |
5 | interface BillingCallback {
6 | fun onBillingSuccess(purchase: Purchase)
7 | fun onBillingFailure(responseCode: Int)
8 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/component/GenerateProgressBar.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate.component
2 |
3 | import androidx.compose.animation.core.animateFloatAsState
4 | import androidx.compose.animation.core.tween
5 | import androidx.compose.foundation.layout.fillMaxWidth
6 | import androidx.compose.material3.LinearProgressIndicator
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.runtime.getValue
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.tooling.preview.Preview
11 | import androidx.compose.ui.unit.dp
12 | import kr.genti.designsystem.theme.GentiGreen
13 | import kr.genti.designsystem.theme.GentiTheme
14 | import kr.genti.designsystem.theme.White20
15 |
16 | @Composable
17 | internal fun GenerateProgressBar(
18 | modifier: Modifier = Modifier,
19 | progress: Float = 0f,
20 | ) {
21 | val animatedProgress by animateFloatAsState(
22 | targetValue = progress,
23 | animationSpec = tween(durationMillis = 300),
24 | label = ""
25 | )
26 |
27 | LinearProgressIndicator(
28 | progress = { animatedProgress },
29 | modifier = modifier.fillMaxWidth(),
30 | color = GentiGreen,
31 | trackColor = White20,
32 | gapSize = 0.dp,
33 | drawStopIndicator = { }
34 | )
35 | }
36 |
37 | @Preview
38 | @Composable
39 | private fun GenerateProgressBarPreview() {
40 | GentiTheme {
41 | GenerateProgressBar(
42 | progress = 0.33F
43 | )
44 | }
45 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/model/GenerateStage.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate.model
2 |
3 | import kr.genti.domain.enums.PictureNumber
4 |
5 | enum class GenerateStage {
6 | INIT, NUMBER_SELECT, PROMPT_INPUT, RATIO_SELECT, IMAGE_THREE_SELECT, IMAGE_SIX_SELECT, RESULT;
7 |
8 | fun prevStage(isParentPic: Boolean): GenerateStage = when (this) {
9 | NUMBER_SELECT -> INIT
10 | PROMPT_INPUT -> if (isParentPic) NUMBER_SELECT else INIT
11 | RATIO_SELECT -> PROMPT_INPUT
12 | IMAGE_THREE_SELECT -> RATIO_SELECT
13 | IMAGE_SIX_SELECT -> RATIO_SELECT
14 | else -> RESULT
15 | }
16 |
17 | fun nextStage(pictureNumber: PictureNumber): GenerateStage = when (this) {
18 | NUMBER_SELECT -> PROMPT_INPUT
19 | PROMPT_INPUT -> RATIO_SELECT
20 | RATIO_SELECT -> if (pictureNumber != PictureNumber.TWO) IMAGE_THREE_SELECT else IMAGE_SIX_SELECT
21 | else -> RESULT
22 | }
23 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/model/GenerateType.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate.model
2 |
3 | import kr.genti.domain.enums.PictureNumber
4 |
5 | enum class GenerateType {
6 | FREE_ONE,
7 | PAID_ONE,
8 | PAID_TWO,
9 | NONE;
10 |
11 | companion object {
12 | fun getGenerateType(isParent: Boolean, pictureNumber: PictureNumber): GenerateType =
13 | when {
14 | isParent && pictureNumber == PictureNumber.TWO -> PAID_TWO
15 | isParent -> PAID_ONE
16 | else -> FREE_ONE
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/feature/generate/src/main/java/kr/genti/generate/navigation/GenerateNavigation.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.generate.navigation
2 |
3 | import androidx.navigation.NavController
4 | import androidx.navigation.NavGraphBuilder
5 | import androidx.navigation.NavOptions
6 | import androidx.navigation.compose.composable
7 | import androidx.navigation.toRoute
8 | import kr.genti.generate.GenerateRoute
9 | import kr.genti.navigation.GenerateRoute
10 |
11 | fun NavController.navigateToGenerate(
12 | isParentPic: Boolean,
13 | navOptions: NavOptions? = null
14 | ) {
15 | navigate(GenerateRoute.Generate(isParentPic), navOptions)
16 | }
17 |
18 | fun NavGraphBuilder.generateNavGraph(
19 | navigateToWaiting: (Boolean) -> Unit = {},
20 | navigateToBack: () -> Unit = {},
21 | ) {
22 | composable { backStackEntry ->
23 | val items = backStackEntry.toRoute()
24 | GenerateRoute(
25 | isParentPic = items.isParentPic,
26 | navigateToWaiting = navigateToWaiting,
27 | navigateToBack = navigateToBack
28 | )
29 | }
30 | }
--------------------------------------------------------------------------------
/feature/main/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.main"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 | implementation(projects.feature.feed)
15 | implementation(projects.feature.profile)
16 | implementation(projects.feature.onboarding)
17 | implementation(projects.feature.generate)
18 | implementation(projects.feature.result)
19 | implementation(projects.feature.setting)
20 |
21 | implementation(platform(libs.firebase.bom))
22 | implementation(libs.bundles.firebase)
23 | }
24 |
--------------------------------------------------------------------------------
/feature/main/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/main/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/main/src/androidTest/java/kr/genti/main/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.main.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import androidx.activity.enableEdgeToEdge
9 | import dagger.hilt.android.AndroidEntryPoint
10 | import kr.genti.designsystem.theme.GentiTheme
11 | import kr.genti.main.navigation.rememberMainNavigator
12 |
13 | @AndroidEntryPoint
14 | class MainActivity : ComponentActivity() {
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 |
18 | enableEdgeToEdge()
19 |
20 | val intentData = intent.getStringExtra(EXTRA_TYPE)
21 | val isFromNotification = intentData != null
22 |
23 | setContent {
24 | GentiTheme {
25 | val navigator = rememberMainNavigator(isFromNotification = isFromNotification)
26 | MainRoute(navigator = navigator, intentData = intentData)
27 | }
28 | }
29 | }
30 |
31 | companion object {
32 | private const val EXTRA_TYPE = "EXTRA_DEFAULT"
33 |
34 | @JvmStatic
35 | fun getIntent(
36 | context: Context,
37 | type: String? = null,
38 | ) = Intent(context, MainActivity::class.java).apply {
39 | putExtra(EXTRA_TYPE, type)
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/MainIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main
2 |
3 | import kr.genti.main.navigation.MainTab
4 |
5 | sealed class MainIntent {
6 | data class TabSelect(val tab: MainTab) : MainIntent()
7 | data object GenerateBtnClick : MainIntent()
8 | data class PushAlarmReceived(val type: String?) : MainIntent()
9 | data class NetworkChangeMonitored(val isConnected: Boolean) : MainIntent()
10 | data object DialogDismiss : MainIntent()
11 | data object RegenerateDialogBtnClick : MainIntent()
12 | data object FinishedDialogBtnClick : MainIntent()
13 | data class SelectDialogBtnClick(val isParentPic: Boolean) : MainIntent()
14 | data object DebugPatchBtnClick : MainIntent()
15 | }
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/MainSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main
2 |
3 | import kr.genti.main.navigation.MainTab
4 |
5 | sealed class MainSideEffect {
6 | data object ShowErrorToast : MainSideEffect()
7 | data object ShowStatusChangedToast : MainSideEffect()
8 | data class NavigateToTab(val tab: MainTab) : MainSideEffect()
9 | data class NavigateToGenerate(val isParentPic: Boolean) : MainSideEffect()
10 | data object NavigateToVerify : MainSideEffect()
11 | data class NavigateToWaiting(val isParentPic: Boolean) : MainSideEffect()
12 | data class NavigateToFinished(
13 | val responseId: Long,
14 | val imageUrl: String,
15 | val isGaro: Boolean,
16 | val isParentPic: Boolean
17 | ) : MainSideEffect()
18 | }
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/MainState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main
2 |
3 | import kr.genti.domain.entity.response.GenerateStatusModel
4 | import kr.genti.domain.entity.response.GenerateStatusModel.Companion.emptyGenerateStatusModel
5 | import kr.genti.domain.enums.GenerateStatus
6 |
7 | data class MainState(
8 | val currentGenerateStatus: GenerateStatus = GenerateStatus.EMPTY,
9 | val isNotificationReceived: Boolean = false,
10 | val serverUnableMessage: String = "",
11 | val generatedImage: GenerateStatusModel = emptyGenerateStatusModel(),
12 | val isFinishedDialogVisible: Boolean = false,
13 | val isErrorDialogVisible: Boolean = false,
14 | val isUnableDialogVisible: Boolean = false,
15 | val isSelectDialogVisible: Boolean = false,
16 | val isNetworkDialogVisible: Boolean = false
17 | )
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/component/GenerateForceButton.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main.component
2 |
3 | import androidx.compose.animation.AnimatedVisibility
4 | import androidx.compose.animation.fadeIn
5 | import androidx.compose.animation.fadeOut
6 | import androidx.compose.animation.slideIn
7 | import androidx.compose.animation.slideOut
8 | import androidx.compose.foundation.Image
9 | import androidx.compose.foundation.layout.navigationBarsPadding
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.res.painterResource
14 | import androidx.compose.ui.unit.IntOffset
15 | import androidx.compose.ui.unit.dp
16 | import kr.genti.common.extension.noRippleClickable
17 | import kr.genti.core.designsystem.R
18 |
19 | @Composable
20 | internal fun GenerateForceButton(
21 | modifier: Modifier = Modifier,
22 | isVisible: Boolean = false,
23 | onDebugPatchBtnClicked: () -> Unit = {}
24 | ) {
25 | AnimatedVisibility(
26 | visible = isVisible,
27 | enter = fadeIn() + slideIn { IntOffset(0, it.height) },
28 | exit = fadeOut() + slideOut { IntOffset(0, it.height) },
29 | modifier = modifier
30 | .noRippleClickable { onDebugPatchBtnClicked() }
31 | .navigationBarsPadding()
32 | .padding(bottom = 90.dp)
33 | ) {
34 | Image(
35 | painter = painterResource(id = R.drawable.ic_download),
36 | contentDescription = null,
37 | )
38 | }
39 | }
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/component/MainBottomBtn.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main.component
2 |
3 | import androidx.compose.animation.AnimatedVisibility
4 | import androidx.compose.animation.fadeIn
5 | import androidx.compose.animation.fadeOut
6 | import androidx.compose.animation.slideIn
7 | import androidx.compose.animation.slideOut
8 | import androidx.compose.foundation.Image
9 | import androidx.compose.foundation.layout.navigationBarsPadding
10 | import androidx.compose.foundation.layout.offset
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.ui.Modifier
13 | import androidx.compose.ui.res.painterResource
14 | import androidx.compose.ui.unit.IntOffset
15 | import androidx.compose.ui.unit.dp
16 | import kr.genti.common.extension.noRippleClickable
17 | import kr.genti.feature.main.R
18 |
19 | @Composable
20 | internal fun MainBottomBtn(
21 | modifier: Modifier = Modifier,
22 | visible: Boolean = true,
23 | onButtonClick: () -> Unit = {},
24 | ) {
25 | AnimatedVisibility(
26 | visible = visible,
27 | enter = fadeIn() + slideIn { IntOffset(0, it.height) },
28 | exit = fadeOut() + slideOut { IntOffset(0, it.height) },
29 | modifier = modifier
30 | .navigationBarsPadding()
31 | .offset(y = 24.dp)
32 | ) {
33 | Image(
34 | painter = painterResource(R.drawable.menu_create),
35 | contentDescription = null,
36 | modifier = Modifier.noRippleClickable { onButtonClick() }
37 | )
38 | }
39 | }
--------------------------------------------------------------------------------
/feature/main/src/main/java/kr/genti/main/navigation/MainTab.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.main.navigation
2 |
3 | import androidx.annotation.DrawableRes
4 | import androidx.compose.runtime.Composable
5 | import kr.genti.feature.main.R
6 | import kr.genti.navigation.MainTabRoute
7 | import kr.genti.navigation.Route
8 |
9 | enum class MainTab(
10 | val title: String,
11 | @DrawableRes val selectedIconResource: Int,
12 | @DrawableRes val unselectedIconResource: Int,
13 | val route: MainTabRoute,
14 | ) {
15 | FEED(
16 | "피드",
17 | R.drawable.menu_feed_selected,
18 | R.drawable.menu_feed_unselected,
19 | MainTabRoute.Feed
20 | ),
21 | GENERATE(
22 | "생성",
23 | R.drawable.menu_feed_selected,
24 | R.drawable.menu_feed_unselected,
25 | MainTabRoute.Generate
26 | ),
27 | PROFILE(
28 | "프로필",
29 | R.drawable.menu_profile_selected,
30 | R.drawable.menu_profile_unselected,
31 | MainTabRoute.Profile
32 | );
33 |
34 | companion object {
35 | @Composable
36 | fun find(predicate: @Composable (MainTabRoute) -> Boolean): MainTab? {
37 | return entries.find { predicate(it.route) }
38 | }
39 |
40 | @Composable
41 | fun contains(predicate: @Composable (Route) -> Boolean): Boolean {
42 | return entries.map { it.route }.any { predicate(it) }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/feature/main/src/main/res/drawable/menu_create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/main/src/main/res/drawable/menu_create.png
--------------------------------------------------------------------------------
/feature/main/src/main/res/drawable/menu_feed_selected.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/feature/main/src/main/res/drawable/menu_feed_unselected.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/feature/main/src/main/res/drawable/menu_profile_selected.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/feature/main/src/main/res/drawable/menu_profile_unselected.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/feature/onboarding/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.onboarding"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 |
15 | implementation(libs.kakao)
16 | implementation(platform(libs.firebase.bom))
17 | implementation(libs.bundles.firebase)
18 | implementation(libs.phoenix)
19 | }
--------------------------------------------------------------------------------
/feature/onboarding/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/onboarding/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/onboarding/src/androidTest/java/kr/genti/onboarding/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.onboarding.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/component/TutorialFadeInBackground.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.component
2 |
3 | import androidx.compose.animation.AnimatedVisibility
4 | import androidx.compose.animation.core.tween
5 | import androidx.compose.animation.fadeIn
6 | import androidx.compose.animation.fadeOut
7 | import androidx.compose.foundation.Image
8 | import androidx.compose.foundation.layout.fillMaxWidth
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Modifier
11 | import androidx.compose.ui.res.painterResource
12 | import kr.genti.core.designsystem.R
13 | import kr.genti.onboarding.model.TutorialStage
14 |
15 | @Composable
16 | fun TutorialFadeInBackground(
17 | modifier: Modifier = Modifier,
18 | currentStage: TutorialStage = TutorialStage.FIRST,
19 | ) {
20 | AnimatedVisibility(
21 | visible = currentStage == TutorialStage.THIRD,
22 | enter = fadeIn(animationSpec = tween(durationMillis = 500)),
23 | exit = fadeOut(),
24 | modifier = modifier.fillMaxWidth()
25 | ) {
26 | Image(
27 | painter = painterResource(id = R.drawable.img_onboarding_third),
28 | contentDescription = null,
29 | modifier = Modifier.fillMaxWidth()
30 | )
31 | }
32 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/login/LoginIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.login
2 |
3 | sealed class LoginIntent {
4 | data class Init(val isAppLoginAvailable: Boolean) : LoginIntent()
5 | data object LoginBtnClick : LoginIntent()
6 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/login/LoginSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.login
2 |
3 | import com.kakao.sdk.auth.model.OAuthToken
4 |
5 | sealed class LoginSideEffect {
6 | data object ShowErrorToast : LoginSideEffect()
7 |
8 | data object NavigateToSignup : LoginSideEffect()
9 |
10 | data object NavigateToFeed : LoginSideEffect()
11 |
12 | data class StartKakaoAppLogin(
13 | val appLoginCallback: (OAuthToken?, Throwable?) -> Unit
14 | ) : LoginSideEffect()
15 |
16 | data class StartKakaoWebLogin(
17 | val webLoginCallback: (OAuthToken?, Throwable?) -> Unit
18 | ) : LoginSideEffect()
19 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/login/LoginState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.login
2 |
3 | data class LoginState(
4 | val isAppLoginAvailable: Boolean = false,
5 | val isLoading: Boolean = false,
6 | )
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/model/TutorialStage.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.model
2 |
3 | enum class TutorialStage {
4 | FIRST, SECOND, THIRD;
5 |
6 | companion object {
7 | fun getTutorialList() = entries
8 | }
9 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/signup/SignupIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.signup
2 |
3 | import kr.genti.domain.enums.Gender
4 |
5 | sealed class SignupIntent {
6 | data object Init : SignupIntent()
7 | data class GenderSelect(val gender: Gender) : SignupIntent()
8 | data class YearChange(val year: String) : SignupIntent()
9 | data class TextFieldFocused(val isFocused: Boolean) : SignupIntent()
10 | data object SignupBtnClick : SignupIntent()
11 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/signup/SignupSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.signup
2 |
3 | sealed class SignupSideEffect {
4 | data object ShowErrorToast : SignupSideEffect()
5 | data object NavigateToTutorial : SignupSideEffect()
6 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/signup/SignupState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.signup
2 |
3 | import kr.genti.domain.enums.Gender
4 |
5 | data class SignupState(
6 | val selectedGender: Gender = Gender.NONE,
7 | val selectedYear: String = "",
8 | val isGenderSelected: Boolean = false,
9 | val isYearSelected: Boolean = false,
10 | val isAllSelected: Boolean = false,
11 | val isFocusClearNeeded: Boolean = false,
12 | val isLoading: Boolean = false,
13 | )
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/splash/SplashIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.splash
2 |
3 | sealed class SplashIntent {
4 | data object Init : SplashIntent()
5 | data object LottiePlayFinish : SplashIntent()
6 | data class AppUpdateFinish(val isAppUpdateSuccess: Boolean) : SplashIntent()
7 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/splash/SplashSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.splash
2 |
3 | sealed class SplashSideEffect {
4 | data object ShowErrorToast : SplashSideEffect()
5 | data object NavigateToLogin : SplashSideEffect()
6 | data object NavigateToFeed : SplashSideEffect()
7 | data object StartAppUpdate : SplashSideEffect()
8 | data object RestartApp : SplashSideEffect()
9 | data object FinishApp : SplashSideEffect()
10 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/splash/SplashState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.splash
2 |
3 | data class SplashState(
4 | val isLottieFinished: Boolean = false,
5 | val isCheckFinished: Boolean = false,
6 | val isUserSigned: Boolean = false,
7 | )
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/tutorial/TutorialIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.tutorial
2 |
3 | sealed class TutorialIntent {
4 | data object NextBtnClick : TutorialIntent()
5 | data object CloseBtnClick : TutorialIntent()
6 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/tutorial/TutorialSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.tutorial
2 |
3 | sealed class TutorialSideEffect {
4 | data object NavigateToFeed : TutorialSideEffect()
5 | }
--------------------------------------------------------------------------------
/feature/onboarding/src/main/java/kr/genti/onboarding/tutorial/TutorialState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding.tutorial
2 |
3 | import kr.genti.onboarding.model.TutorialStage
4 |
5 | data class TutorialState(
6 | val currentStage: TutorialStage = TutorialStage.FIRST,
7 | )
--------------------------------------------------------------------------------
/feature/onboarding/src/test/java/kr/genti/onboarding/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.onboarding
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/feature/profile/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.profile"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 | }
--------------------------------------------------------------------------------
/feature/profile/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/profile/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/profile/src/androidTest/java/kr/genti/profile/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.profile.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/ProfileIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile
2 |
3 | import kr.genti.domain.entity.response.ImageModel
4 |
5 | sealed class ProfileIntent {
6 | data object Init: ProfileIntent()
7 | data object Refresh: ProfileIntent()
8 | data class ImageItemClick(val item: ImageModel): ProfileIntent()
9 | data object GenerateBtnClick: ProfileIntent()
10 | data object SettingBtnClick: ProfileIntent()
11 | data object LastColumnLoaded: ProfileIntent()
12 | data object SaveBtnClick: ProfileIntent()
13 | data object ShareBtnClick: ProfileIntent()
14 | data object DialogDismiss: ProfileIntent()
15 | }
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/ProfileSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile
2 |
3 | import android.net.Uri
4 |
5 | sealed class ProfileSideEffect {
6 | data object ShowErrorToast : ProfileSideEffect()
7 | data object ShowDownloadToast : ProfileSideEffect()
8 | data object NavigateToGenerate : ProfileSideEffect()
9 | data object NavigateToSetting : ProfileSideEffect()
10 | data object StartPermissionLauncher : ProfileSideEffect()
11 | data class NavigateToShare(val imageUri: Uri) : ProfileSideEffect()
12 | }
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/ProfileState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile
2 |
3 | import kotlinx.collections.immutable.ImmutableList
4 | import kotlinx.collections.immutable.persistentListOf
5 | import kr.genti.domain.entity.response.ImageModel
6 |
7 | data class ProfileState(
8 | val itemList: ImmutableList = persistentListOf(),
9 | val totalPage: Int = 0,
10 | val currentPage: Int = -1,
11 | val isPagingFinish: Boolean = false,
12 | val detailImageId: Long = -1L,
13 | val detailImageUrl: String = "",
14 | val isDetailImageGaro: Boolean = false,
15 | val isDetailDialogShown: Boolean = false,
16 | val isGenerating: Boolean = false,
17 | val isLoading: Boolean = false,
18 | val isRefreshing: Boolean = false
19 | )
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/component/ProfileGenerateItem.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile.component
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.aspectRatio
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.layout.ContentScale
8 | import androidx.compose.ui.res.painterResource
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import kr.genti.common.extension.noRippleClickable
11 | import kr.genti.core.designsystem.R
12 |
13 | @Composable
14 | internal fun ProfileGenerateItem(
15 | modifier: Modifier = Modifier,
16 | isGenerating: Boolean = false,
17 | onBtnClick: () -> Unit = {},
18 | ) {
19 | Image(
20 | painter = painterResource(id = if (!isGenerating) R.drawable.img_profile_create_active else R.drawable.img_profile_create_inactive),
21 | contentDescription = null,
22 | contentScale = ContentScale.Crop,
23 | modifier = modifier
24 | .aspectRatio(1F)
25 | .noRippleClickable { onBtnClick() }
26 | )
27 | }
28 |
29 | @Preview
30 | @Composable
31 | private fun ProfileGenerateItemPreviewActive() {
32 | ProfileGenerateItem(
33 | isGenerating = false
34 | )
35 | }
36 |
37 | @Preview
38 | @Composable
39 | private fun ProfileGenerateItemPreviewInactive() {
40 | ProfileGenerateItem(
41 | isGenerating = true
42 | )
43 | }
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/component/ProfileGeneratingBanner.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile.component
2 |
3 | import androidx.compose.foundation.Image
4 | import androidx.compose.foundation.layout.fillMaxWidth
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.res.painterResource
8 | import kr.genti.core.designsystem.R
9 |
10 | @Composable
11 | internal fun ProfileGenerationBanner(
12 | modifier: Modifier = Modifier,
13 | isGenerating: Boolean = false
14 | ) {
15 | if (isGenerating) {
16 | Image(
17 | painter = painterResource(R.drawable.img_profile_making),
18 | contentDescription = null,
19 | modifier = modifier.fillMaxWidth()
20 | )
21 | }
22 | }
--------------------------------------------------------------------------------
/feature/profile/src/main/java/kr/genti/profile/navigation/ProfileNavigation.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.profile.navigation
2 |
3 | import androidx.compose.foundation.layout.PaddingValues
4 | import androidx.navigation.NavController
5 | import androidx.navigation.NavGraphBuilder
6 | import androidx.navigation.NavOptions
7 | import androidx.navigation.compose.composable
8 | import kr.genti.navigation.MainTabRoute
9 | import kr.genti.profile.ProfileRoute
10 |
11 | fun NavController.navigateToProfile(
12 | navOptions: NavOptions? = null
13 | ) {
14 | navigate(MainTabRoute.Profile, navOptions)
15 | }
16 |
17 | fun NavGraphBuilder.profileNavGraph(
18 | paddingValues: PaddingValues,
19 | navigateToGenerate: () -> Unit = {},
20 | navigateToSetting: () -> Unit = {}
21 | ) {
22 | composable {
23 | ProfileRoute(
24 | paddingValues = paddingValues,
25 | navigateToGenerate = navigateToGenerate,
26 | navigateToSetting = navigateToSetting
27 | )
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/feature/result/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | }
4 |
5 | android {
6 | namespace = "kr.genti.feature.result"
7 | }
8 |
9 | dependencies {
10 | implementation(projects.domain)
11 | implementation(projects.core.common)
12 | implementation(projects.core.navigation)
13 | implementation(projects.core.designsystem)
14 | }
--------------------------------------------------------------------------------
/feature/result/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/result/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/result/src/androidTest/java/kr/genti/result/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.result.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/finished/FinishedIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.finished
2 |
3 | sealed class FinishedIntent {
4 | data class Init(val responseId: Long, val isParentPic: Boolean, val imageUrl: String) :
5 | FinishedIntent()
6 |
7 | data object ImageClick : FinishedIntent()
8 | data object BackButtonClick : FinishedIntent()
9 | data object ReportButtonClick : FinishedIntent()
10 | data object ShareButtonClick : FinishedIntent()
11 | data object DownloadButtonClick : FinishedIntent()
12 | data object DialogDismiss : FinishedIntent()
13 | data class ReportTextChange(val text: String) : FinishedIntent()
14 | data object ReportSubmitButtonClick : FinishedIntent()
15 | data object FinishButtonClick : FinishedIntent()
16 | data class RatingChange(val rating: Int) : FinishedIntent()
17 | data object RatingSubmitButtonClick : FinishedIntent()
18 | data object RatingSkipButtonClick : FinishedIntent()
19 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/finished/FinishedSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.finished
2 |
3 | import android.net.Uri
4 |
5 | sealed class FinishedSideEffect {
6 | data object ShowErrorToast : FinishedSideEffect()
7 | data object ShowDownloadToast : FinishedSideEffect()
8 | data object NavigateToBack : FinishedSideEffect()
9 | data object StartPermissionLauncher : FinishedSideEffect()
10 | data class NavigateToShare(val imageUri: Uri) : FinishedSideEffect()
11 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/finished/FinishedState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.finished
2 |
3 | data class FinishedState(
4 | val responseId: Long = -1,
5 | val isParentPic: Boolean = false,
6 | val imageUrl: String = "",
7 | val reportText: String = "",
8 | val rating: Int = 5,
9 | val isReportSubmitted: Boolean = false,
10 | val isDetailDialogVisible: Boolean = false,
11 | val isReportDialogVisible: Boolean = false,
12 | val isRatingDialogVisible: Boolean = false,
13 | )
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/verify/VerifyIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.verify
2 |
3 | sealed class VerifyIntent {
4 | data class CameraButtonClick(val isFirst: Boolean) : VerifyIntent()
5 | data object CameraPermissionGrant : VerifyIntent()
6 | data object CameraResultSuccess : VerifyIntent()
7 | data object FinishButtonClick : VerifyIntent()
8 | data object BackButtonClick : VerifyIntent()
9 | data object ExitButtonClick : VerifyIntent()
10 | data object ExitDialogDismiss : VerifyIntent()
11 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/verify/VerifySideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.verify
2 |
3 | sealed class VerifySideEffect {
4 | data object ShowErrorToast : VerifySideEffect()
5 | data object NavigateToBack : VerifySideEffect()
6 | data object StartPermissionLauncher : VerifySideEffect()
7 | data object StartCameraLauncher : VerifySideEffect()
8 | data object VerifySuccess: VerifySideEffect()
9 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/verify/VerifyState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.verify
2 |
3 | import android.net.Uri
4 |
5 | data class VerifyState(
6 | val isPhotoTaken: Boolean = false,
7 | val imageUri: Uri? = null,
8 | val imageName: String? = null,
9 | val isLoading: Boolean = false,
10 | val isExitDialogVisible: Boolean = false,
11 | )
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/waiting/WaitingIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.waiting
2 |
3 | sealed class WaitingIntent {
4 | data class Init(val isParentPic: Boolean) : WaitingIntent()
5 | data object ReturnButtonClick : WaitingIntent()
6 | data class AlarmPermissionNeeded(val isNeeded: Boolean) : WaitingIntent()
7 | data class NavigatedToSetting(val isNavigated: Boolean) : WaitingIntent()
8 | data object AlarmDialogRequestButtonClick : WaitingIntent()
9 | data object AlarmDialogReturnButtonClick : WaitingIntent()
10 | data object AlarmRequestGrant : WaitingIntent()
11 | data object AlarmDialogDismiss : WaitingIntent()
12 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/waiting/WaitingSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.waiting
2 |
3 | sealed class WaitingSideEffect {
4 | data object NavigateToBack : WaitingSideEffect()
5 | data object CheckPermission : WaitingSideEffect()
6 | data object StartPermissionLauncher : WaitingSideEffect()
7 | data object GrantPermission : WaitingSideEffect()
8 | }
--------------------------------------------------------------------------------
/feature/result/src/main/java/kr/genti/result/waiting/WaitingState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result.waiting
2 |
3 | data class WaitingState(
4 | val isParentPic: Boolean = false,
5 | val isAlarmDialogVisible: Boolean = false,
6 | val isNavigatedToSetting: Boolean = false,
7 | )
--------------------------------------------------------------------------------
/feature/result/src/test/java/kr/genti/result/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.result
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/feature/setting/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("kr.genti.androidCompose")
3 | id("kr.genti.version")
4 | }
5 |
6 | android {
7 | namespace = "kr.genti.feature.setting"
8 |
9 | defaultConfig {
10 | buildConfigField("String", "VERSION_NAME", "\"${extra["versionName"]}\"")
11 | buildConfigField("String", "VERSION_CODE", "\"${extra["versionCode"]}\"")
12 | }
13 |
14 | buildFeatures {
15 | buildConfig = true
16 | }
17 | }
18 |
19 | dependencies {
20 | implementation(projects.domain)
21 | implementation(projects.core.common)
22 | implementation(projects.core.navigation)
23 | implementation(projects.core.designsystem)
24 |
25 | implementation(libs.phoenix)
26 | }
27 |
--------------------------------------------------------------------------------
/feature/setting/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/feature/setting/consumer-rules.pro
--------------------------------------------------------------------------------
/feature/setting/src/androidTest/java/kr/genti/setting/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.setting
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("kr.genti.setting.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/feature/setting/src/main/java/kr/genti/setting/SettingIntent.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.setting
2 |
3 | sealed class SettingIntent {
4 | data object BackButtonClick : SettingIntent()
5 | data object TermButtonClick : SettingIntent()
6 | data object PrivacyButtonClick : SettingIntent()
7 | data object CompanyButtonClick : SettingIntent()
8 | data object QuestionButtonClick : SettingIntent()
9 | data object LogoutButtonClick : SettingIntent()
10 | data object QuitButtonClick : SettingIntent()
11 | data object LogoutDialogDismiss : SettingIntent()
12 | data object QuitDialogDismiss : SettingIntent()
13 | data object LogoutRequest : SettingIntent()
14 | data object QuitRequest : SettingIntent()
15 | }
--------------------------------------------------------------------------------
/feature/setting/src/main/java/kr/genti/setting/SettingSideEffect.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.setting
2 |
3 | sealed class SettingSideEffect {
4 | data object ShowErrorToast : SettingSideEffect()
5 | data object NavigateToBack : SettingSideEffect()
6 | data class NavigateToWeb(val url: String) : SettingSideEffect()
7 | data object RestartApp : SettingSideEffect()
8 | }
--------------------------------------------------------------------------------
/feature/setting/src/main/java/kr/genti/setting/SettingState.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.setting
2 |
3 | data class SettingState(
4 | val isLogoutDialogVisible: Boolean = false,
5 | val isQuitDialogVisible: Boolean = false,
6 | )
--------------------------------------------------------------------------------
/feature/setting/src/main/java/kr/genti/setting/navigation/SettingNavigation.kt:
--------------------------------------------------------------------------------
1 | package kr.genti.setting.navigation
2 |
3 | import androidx.navigation.NavController
4 | import androidx.navigation.NavGraphBuilder
5 | import androidx.navigation.NavOptions
6 | import androidx.navigation.compose.composable
7 | import kr.genti.navigation.SettingRoute
8 | import kr.genti.setting.SettingRoute
9 |
10 | fun NavController.navigateToSetting(
11 | navOptions: NavOptions? = null
12 | ) {
13 | navigate(SettingRoute.Setting, navOptions)
14 | }
15 |
16 | fun NavGraphBuilder.settingNavGraph(
17 | navigateToBack: () -> Unit = {}
18 | ) {
19 | composable {
20 | SettingRoute(
21 | navigateToBack = navigateToBack
22 | )
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Genti2024/Genti-Android/22801f3c40931e51c3df07457ddb2c78c0c3ecf6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 01 02:58:14 KST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
2 |
3 | pluginManagement {
4 |
5 | includeBuild("build-logic")
6 |
7 | repositories {
8 | google {
9 | content {
10 | includeGroupByRegex("com\\.android.*")
11 | includeGroupByRegex("com\\.google.*")
12 | includeGroupByRegex("androidx.*")
13 | }
14 | }
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | dependencyResolutionManagement {
21 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
22 | repositories {
23 | google()
24 | mavenCentral()
25 |
26 | // KakaoSDK repository
27 | maven(url = "https://devrepo.kakao.com/nexus/content/groups/public/")
28 | }
29 | }
30 |
31 | rootProject.name = "Genti-Android"
32 |
33 | include(":app")
34 | include(":domain")
35 | include(":data")
36 | include(":core:common")
37 | include(":core:datastore")
38 | include(":core:designsystem")
39 | include(":core:navigation")
40 | include(":core:network")
41 | include(":feature:onboarding")
42 | include(":feature:feed")
43 | include(":feature:main")
44 | include(":feature:profile")
45 | include(":feature:generate")
46 | include(":feature:result")
47 | include(":feature:setting")
48 |
--------------------------------------------------------------------------------