diff --git a/.github/workflows/firebase_distribution_builder.yml b/.github/workflows/firebase_distribution_builder.yml
new file mode 100644
index 00000000..1422730d
--- /dev/null
+++ b/.github/workflows/firebase_distribution_builder.yml
@@ -0,0 +1,81 @@
+name: Genti Firebase App Distribution Builder
+
+on:
+ push:
+ branches: [ production ]
+
+defaults:
+ run:
+ shell: bash
+ working-directory: .
+
+jobs:
+ build:
+ name: Firebase App Distribution Builder
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Gradle cache
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+ - name: set up JDK 17
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'temurin'
+ java-version: 17
+
+ - name: Change gradlew permissions
+ run: chmod +x ./gradlew
+
+ - name: Create Local Properties
+ run: touch local.properties
+
+ - name: Access Local Properties
+ env:
+ base_url: ${{ secrets.BASE_URL }}
+ test_base_url: ${{ secrets.TEST_BASE_URL }}
+ native_app_key: ${{ secrets.NATIVE_APP_KEY }}
+ amplitude_api_key: ${{ secrets.AMPLITUDE_API_KEY }}
+ amplitude_test_key: ${{ secrets.AMPLITUDE_TEST_KEY }}
+ run: |
+ echo "base.url=\"$base_url\"" >> local.properties
+ echo "test.base.url=\"$test_base_url\"" >> local.properties
+ echo "native.app.key=\"$native_app_key\"" >> local.properties
+ echo "nativeAppKey=\"$native_app_key\"" >> local.properties
+ echo "amplitude.api.key=\"$amplitude_api_key\"" >> local.properties
+ echo "amplitude.test.key=\"$amplitude_test_key\"" >> local.properties
+
+ - name: Access Keystore Properties
+ env:
+ keystore_file: ${{ secrets.KEYSTORE_FILE }}
+ store_password: ${{ secrets.STORE_PASSWORD }}
+ key_password: ${{ secrets.KEY_PASSWORD }}
+ key_alias: ${{ secrets.KEY_ALIAS }}
+ run: |
+ echo "storeFile=keystore.jks" > keystore.properties
+ echo "storePassword=\"$store_password\"" >> keystore.properties
+ echo "keyAlias=\"$key_alias\"" >> keystore.properties
+ echo "keyPassword=\"$key_password\"" >> keystore.properties
+ echo "$keystore_file" | base64 -d > keystore.jks
+
+ - name: Access Firebase Service
+ run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json
+
+ - name: Build release APK
+ run: ./gradlew assembleRelease --stacktrace
+
+ - name: Upload to Firebase App Distribution
+ uses: wzieba/Firebase-Distribution-Github-Action@v1
+ with:
+ appId: ${{ secrets.FIREBASE_APP_ID }}
+ serviceCredentialsFileContent: ${{ secrets.FIREBASE_APP_DISTRIBUTION_KEY }}
+ groups: tester
+ file: app/build/outputs/apk/release/app-release.apk
\ No newline at end of file
diff --git a/.github/workflows/pr_checker.yml b/.github/workflows/pr_checker.yml
index eda66bdd..96b66cb1 100644
--- a/.github/workflows/pr_checker.yml
+++ b/.github/workflows/pr_checker.yml
@@ -41,5 +41,33 @@ jobs:
- name: Access Local Properties
env:
base_url: ${{ secrets.BASE_URL }}
+ test_base_url: ${{ secrets.TEST_BASE_URL }}
+ native_app_key: ${{ secrets.NATIVE_APP_KEY }}
+ amplitude_api_key: ${{ secrets.AMPLITUDE_API_KEY }}
+ amplitude_test_key: ${{ secrets.AMPLITUDE_TEST_KEY }}
run: |
- echo base.url=\"$base_url\" >> local.properties
\ No newline at end of file
+ echo "base.url=\"$base_url\"" >> local.properties
+ echo "test.base.url=\"$test_base_url\"" >> local.properties
+ echo "native.app.key=\"$native_app_key\"" >> local.properties
+ echo "nativeAppKey=\"$native_app_key\"" >> local.properties
+ echo "amplitude.api.key=\"$amplitude_api_key\"" >> local.properties
+ echo "amplitude.test.key=\"$amplitude_test_key\"" >> local.properties
+
+ - name: Access Keystore Properties
+ env:
+ keystore_file: ${{ secrets.KEYSTORE_FILE }}
+ store_password: ${{ secrets.STORE_PASSWORD }}
+ key_password: ${{ secrets.KEY_PASSWORD }}
+ key_alias: ${{ secrets.KEY_ALIAS }}
+ run: |
+ echo "storeFile=keystore.jks" > keystore.properties
+ echo "storePassword=\"$store_password\"" >> keystore.properties
+ echo "keyAlias=\"$key_alias\"" >> keystore.properties
+ echo "keyPassword=\"$key_password\"" >> keystore.properties
+ echo "$keystore_file" | base64 -d > keystore.jks
+
+ - name: Access Firebase Service
+ run: echo '${{ secrets.GOOGLE_SERVICES_JSON }}' > ./app/google-services.json
+
+ - name: Build debug APK
+ run: ./gradlew assembleDebug --stacktrace
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index ffe9ebf8..4214c82c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,6 +115,9 @@ captures/
# Google Services (e.g. APIs or Firebase)
google-services.json
+# Local configuration file (sdk path, etc)
+keystore.properties
+
# Android Patch
gen-external-apklibs
diff --git a/README.md b/README.md
index dffe1678..49b1d6da 100644
--- a/README.md
+++ b/README.md
@@ -7,19 +7,36 @@
-## TEAM _ 안드로이드 단독 개발
-![2024-08-01_00-28-32](https://github.com/user-attachments/assets/5179534b-09d6-428d-aa67-92afd1163cc7)
+## TEAM
+![2024-08-01_00-28-32](https://github.com/user-attachments/assets/64bb2fa3-cd67-430a-ae53-ff20c76d53b7)
+
+### Android Contributor
+
+[![contributors](https://contrib.rocks/image?repo=Genti2024/Genti-Android)](https://github.com/Genti2024/Genti-Android/contributors)
+
+
+
+## PRODUCT
+![Group 8245](https://github.com/user-attachments/assets/6616126f-8be8-4011-afc8-d312145cd5e9)
## SOLUTIONS
-![2024-08-01_00-34-24](https://github.com/user-attachments/assets/649fb66d-6788-4d6c-a6de-f4b673f9623b)
-![2024-08-01_00-34-43](https://github.com/user-attachments/assets/897c4340-d6d9-4f1a-b9bd-ff4c69675864)
+![Group 8250](https://github.com/user-attachments/assets/c96de744-a45f-4512-9896-cd4c6b278ecb)
+![Group 8251](https://github.com/user-attachments/assets/45c89b6e-6c74-498d-b498-aaa1bad0484f)
+![Group 8252](https://github.com/user-attachments/assets/27210a73-d53c-479c-be24-bc9fe4c5a060)
+
+
+
+## PROGRESS
+![Group 8249](https://github.com/user-attachments/assets/30ab4785-68f0-4490-8bbe-a2b0a9a269e6)
+![Group 8248](https://github.com/user-attachments/assets/a78918f8-14e5-4853-b0f2-806e880d086a)
+![Group 8247](https://github.com/user-attachments/assets/cf32392b-c7f1-4966-9439-ffe150bdc4d0)
## ACHIEVEMENT
-- 2024 정주영 창업경진대회 (아산나눔재단) 사업실행팀 선발
+- 2024 정주영 창업경진대회 (아산나눔재단) 사업실행팀 선발 및 본상 수상
- 2024 고려대 KU 창업동아리 아이디어 트랙 선정
- 2024 동국대 아이디어 사업화 지원사업 선발
- 2024 KUCT 딥테크 스타트업 프론티어 선발전 도전상 수상
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 7bfec101..091d41e4 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,28 +1,14 @@
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
+import java.util.Properties
plugins {
- id("com.android.application")
- kotlin("android")
- kotlin("kapt")
- id("kotlin-parcelize")
- id("dagger.hilt.android.plugin")
+ id("kr.genti.androidApplication")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
android {
- namespace = Constants.packageName
- compileSdk = Constants.compileSdk
-
defaultConfig {
- applicationId = Constants.packageName
- minSdk = Constants.minSdk
- targetSdk = Constants.targetSdk
- versionCode = Constants.versionCode
- versionName = Constants.versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
-
buildConfigField(
"String",
"NATIVE_APP_KEY",
@@ -31,6 +17,19 @@ android {
manifestPlaceholders["NATIVE_APP_KEY"] =
gradleLocalProperties(rootDir).getProperty("nativeAppKey")
+
+ val keystorePropertiesFile = rootProject.file("keystore.properties")
+ val keystoreProperties = Properties()
+ keystoreProperties.load(keystorePropertiesFile.inputStream())
+
+ signingConfigs {
+ create("release") {
+ storeFile = file(keystoreProperties["storeFile"] as String)
+ storePassword = keystoreProperties["storePassword"] as String
+ keyAlias = keystoreProperties["keyAlias"] as String
+ keyPassword = keystoreProperties["keyPassword"] as String
+ }
+ }
}
buildTypes {
@@ -57,72 +56,17 @@ android {
"AMPLITUDE_KEY",
gradleLocalProperties(rootDir).getProperty("amplitude.api.key"),
)
-
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro",
- )
}
}
-
- compileOptions {
- sourceCompatibility = Versions.javaVersion
- targetCompatibility = Versions.javaVersion
- }
-
- kotlinOptions {
- jvmTarget = Versions.jvmVersion
- }
-
- buildFeatures {
- buildConfig = true
- dataBinding = true
- viewBinding = true
- }
}
dependencies {
- implementation(project(":core"))
- implementation(project(":data"))
- implementation(project(":domain"))
- implementation(project(":presentation"))
-
- KotlinDependencies.run {
- implementation(kotlin)
- implementation(coroutines)
- implementation(jsonSerialization)
- }
-
- AndroidXDependencies.run {
- implementation(coreKtx)
- implementation(appCompat)
- implementation(hilt)
- }
-
- KaptDependencies.run {
- kapt(hiltCompiler)
- }
-
- TestDependencies.run {
- testImplementation(jUnit)
- androidTestImplementation(androidTest)
- androidTestImplementation(espresso)
- }
-
- RetrofitDependencies.run {
- implementation(platform(okHttpBom))
- implementation(okHttp)
- implementation(okHttpLoggingInterceptor)
- implementation(retrofit)
- implementation(retrofitJsonConverter)
- }
-
- ThirdPartyDependencies.run {
- implementation(timber)
- }
-
- KakaoDependencies.run {
- implementation(user)
- }
+ implementation(projects.core)
+ implementation(projects.data)
+ implementation(projects.domain)
+ implementation(projects.presentation)
+
+ implementation(platform(libs.okhttp.bom))
+ implementation(libs.bundles.networking)
+ implementation(libs.kakao)
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5cdd7497..d92d8e9c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -54,17 +54,18 @@
android:screenOrientation="portrait" />
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="adjustResize" />
diff --git a/app/src/main/java/kr/genti/android/di/AuthInterceptor.kt b/app/src/main/java/kr/genti/android/di/AuthInterceptor.kt
index ee7ff2dd..fa784976 100644
--- a/app/src/main/java/kr/genti/android/di/AuthInterceptor.kt
+++ b/app/src/main/java/kr/genti/android/di/AuthInterceptor.kt
@@ -18,69 +18,70 @@ import timber.log.Timber
import javax.inject.Inject
class AuthInterceptor
- @Inject
- constructor(
- private val authRepository: AuthRepository,
- private val userRepository: UserRepository,
- @ApplicationContext private val context: Context,
- ) : Interceptor {
- override fun intercept(chain: Interceptor.Chain): Response {
- val originalRequest = chain.request()
+@Inject
+constructor(
+ private val authRepository: AuthRepository,
+ private val userRepository: UserRepository,
+ @ApplicationContext private val context: Context,
+) : Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ val originalRequest = chain.request()
- Timber.tag("okhttp").d("ACCESS TOKEN : ${userRepository.getAccessToken()}")
+ Timber.tag("okhttp").d("ACCESS TOKEN : ${userRepository.getAccessToken()}")
- val authRequest =
- if (userRepository.getAccessToken().isNotBlank()) {
- originalRequest.newBuilder().newAuthBuilder().build()
- } else {
- originalRequest
- }
+ val authRequest =
+ if (userRepository.getAccessToken().isNotBlank()) {
+ originalRequest.newBuilder().newAuthBuilder().build()
+ } else {
+ originalRequest
+ }
- val response = chain.proceed(authRequest)
+ val response = chain.proceed(authRequest)
- if (response.code == CODE_TOKEN_EXPIRED) {
- try {
- runBlocking {
- authRepository.postReissueTokens(
- ReissueRequestModel(
- userRepository.getAccessToken(),
- userRepository.getRefreshToken(),
- ),
- )
- }.onSuccess { data ->
- userRepository.setTokens(
- data.accessToken,
- data.refreshToken,
- )
- response.close()
+ if (response.code == CODE_TOKEN_EXPIRED) {
+ try {
+ runBlocking {
+ authRepository.postReissueTokens(
+ ReissueRequestModel(
+ userRepository.getAccessToken(),
+ userRepository.getRefreshToken(),
+ ),
+ )
+ }.onSuccess { data ->
+ userRepository.setTokens(
+ data.accessToken,
+ data.refreshToken,
+ )
+ response.close()
- val newRequest =
- authRequest.newBuilder().removeHeader(AUTHORIZATION).newAuthBuilder()
- .build()
- return chain.proceed(newRequest)
- }
- } catch (t: Throwable) {
- Timber.d(t.message)
+ val newRequest =
+ authRequest.newBuilder().removeHeader(AUTHORIZATION).newAuthBuilder()
+ .build()
+ return chain.proceed(newRequest)
}
+ } catch (t: Throwable) {
+ Timber.d(t.message)
+ }
- userRepository.clearInfo()
+ userRepository.clearInfo()
- Handler(Looper.getMainLooper()).post {
- context.toast(TOKEN_EXPIRED_ERROR)
- Intent(context, LoginActivity::class.java).apply {
- addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
- context.startActivity(this)
- }
+ Handler(Looper.getMainLooper()).post {
+ context.toast(TOKEN_EXPIRED_ERROR)
+ Intent(context, LoginActivity::class.java).apply {
+ addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ context.startActivity(this)
}
}
- return response
}
+ return response
+ }
- private fun Request.Builder.newAuthBuilder() = this.addHeader(AUTHORIZATION, userRepository.getAccessToken())
+ private fun Request.Builder.newAuthBuilder() =
+ this.addHeader(AUTHORIZATION, userRepository.getAccessToken())
- companion object {
- private const val CODE_TOKEN_EXPIRED = 401
- private const val TOKEN_EXPIRED_ERROR = "토큰이 만료되었어요\n다시 로그인 해주세요"
- private const val AUTHORIZATION = "Authorization"
- }
+ companion object {
+ private const val CODE_TOKEN_EXPIRED = 401
+ private const val TOKEN_EXPIRED_ERROR = "토큰이 만료되었어요\n다시 로그인 해주세요"
+ private const val AUTHORIZATION = "Authorization"
}
+}
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
new file mode 100644
index 00000000..f38db1c9
--- /dev/null
+++ b/build-logic/convention/build.gradle.kts
@@ -0,0 +1,47 @@
+plugins {
+ `kotlin-dsl`
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+dependencies {
+ implementation(libs.android.gradlePlugin)
+ implementation(libs.kotlin.gradlePlugin)
+}
+
+gradlePlugin {
+ plugins {
+ register("AndroidApplicationPlugin") {
+ id = "kr.genti.androidApplication"
+ implementationClass = "kr.genti.convention.plugin.AndroidApplicationPlugin"
+ }
+ register("AndroidLibraryPlugin") {
+ id = "kr.genti.androidLibrary"
+ implementationClass = "kr.genti.convention.plugin.AndroidLibraryPlugin"
+ }
+ register("JavaLibraryPlugin") {
+ id = "kr.genti.javaLibrary"
+ implementationClass = "kr.genti.convention.plugin.JavaLibraryPlugin"
+ }
+
+ register("KotlinPlugin") {
+ id = "kr.genti.kotlin"
+ implementationClass = "kr.genti.convention.plugin.KotlinPlugin"
+ }
+ register("HiltPlugin") {
+ id = "kr.genti.hilt"
+ implementationClass = "kr.genti.convention.plugin.HiltPlugin"
+ }
+ register("TestPlugin") {
+ id = "kr.genti.test"
+ implementationClass = "kr.genti.convention.plugin.TestPlugin"
+ }
+ register("versionPlugin") {
+ id = "kr.genti.version"
+ implementationClass = "kr.genti.convention.plugin.VersionPlugin"
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/Constants.kt b/build-logic/convention/src/main/java/kr/genti/convention/Constants.kt
new file mode 100644
index 00000000..3dd7e4ce
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/Constants.kt
@@ -0,0 +1,17 @@
+package kr.genti.convention
+
+import org.gradle.api.JavaVersion
+
+object Constants {
+ const val packageName = "kr.genti.android"
+
+ const val compileSdk = 34
+ const val minSdk = 28
+ const val targetSdk = 34
+
+ const val versionCode = 19
+ const val versionName = "2.1.0"
+
+ const val jvmVersion = "17"
+ val JAVA_VERSION = JavaVersion.VERSION_17
+}
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/config/CommonPluginConfig.kt b/build-logic/convention/src/main/java/kr/genti/convention/config/CommonPluginConfig.kt
new file mode 100644
index 00000000..448685b5
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/config/CommonPluginConfig.kt
@@ -0,0 +1,28 @@
+package kr.genti.convention.config
+
+import kr.genti.convention.extension.getLibrary
+import kr.genti.convention.extension.implementation
+import kr.genti.convention.plugin.HiltPlugin
+import kr.genti.convention.plugin.KotlinPlugin
+import kr.genti.convention.plugin.TestPlugin
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.apply
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.getByType
+
+fun Project.configureAndroidCommonPlugin() {
+ apply()
+ apply()
+ apply()
+ with(plugins) {
+ apply("kotlin-parcelize")
+ apply("org.jetbrains.kotlin.plugin.serialization")
+ }
+
+ val libs = extensions.getByType().named("libs")
+ dependencies {
+ implementation(libs.getLibrary("material-design"))
+ implementation(libs.getLibrary("timber"))
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/extension/CommonExt.kt b/build-logic/convention/src/main/java/kr/genti/convention/extension/CommonExt.kt
new file mode 100644
index 00000000..89880084
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/extension/CommonExt.kt
@@ -0,0 +1,9 @@
+package kr.genti.convention.extension
+
+import com.android.build.api.dsl.CommonExtension
+import org.gradle.api.plugins.ExtensionAware
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
+
+fun CommonExtension<*, *, *, *, *>.kotlinOptions(block: KotlinJvmOptions.() -> Unit) {
+ (this as ExtensionAware).extensions.configure("kotlinOptions", block)
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/extension/DependencyHandlerScopeExt.kt b/build-logic/convention/src/main/java/kr/genti/convention/extension/DependencyHandlerScopeExt.kt
new file mode 100644
index 00000000..ec5fb735
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/extension/DependencyHandlerScopeExt.kt
@@ -0,0 +1,47 @@
+package kr.genti.convention.extension
+
+import org.gradle.api.Project
+import org.gradle.api.file.ConfigurableFileCollection
+import org.gradle.api.file.ConfigurableFileTree
+import org.gradle.api.provider.Provider
+import org.gradle.kotlin.dsl.DependencyHandlerScope
+
+fun DependencyHandlerScope.implementation(project: Project) {
+ "implementation"(project)
+}
+
+fun DependencyHandlerScope.implementation(provider: Provider<*>) {
+ "implementation"(provider)
+}
+
+fun DependencyHandlerScope.implementation(fileTree: ConfigurableFileTree) {
+ "implementation"(fileTree)
+}
+
+fun DependencyHandlerScope.implementation(fileCollection: ConfigurableFileCollection) {
+ "implementation"(fileCollection)
+}
+
+fun DependencyHandlerScope.debugImplementation(provider: Provider<*>) {
+ "debugImplementation"(provider)
+}
+
+fun DependencyHandlerScope.releaseImplementation(provider: Provider<*>) {
+ "releaseImplementation"(provider)
+}
+
+fun DependencyHandlerScope.kapt(provider: Provider<*>) {
+ "kapt"(provider)
+}
+
+fun DependencyHandlerScope.coreLibraryDesugaring(provider: Provider<*>) {
+ "coreLibraryDesugaring"(provider)
+}
+
+fun DependencyHandlerScope.androidTestImplementation(provider: Provider<*>) {
+ "androidTestImplementation"(provider)
+}
+
+fun DependencyHandlerScope.testImplementation(provider: Provider<*>) {
+ "testImplementation"(provider)
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/extension/ProjectExt.kt b/build-logic/convention/src/main/java/kr/genti/convention/extension/ProjectExt.kt
new file mode 100644
index 00000000..47746cd5
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/extension/ProjectExt.kt
@@ -0,0 +1,9 @@
+package kr.genti.convention.extension
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.getByType
+
+val Project.libs: VersionCatalog
+ get() = extensions.getByType().named("libs")
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/extension/VersionCatalogExt.kt b/build-logic/convention/src/main/java/kr/genti/convention/extension/VersionCatalogExt.kt
new file mode 100644
index 00000000..c8f9686b
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/extension/VersionCatalogExt.kt
@@ -0,0 +1,16 @@
+package kr.genti.convention.extension
+
+import org.gradle.api.artifacts.ExternalModuleDependencyBundle
+import org.gradle.api.artifacts.MinimalExternalModuleDependency
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.provider.Provider
+
+fun VersionCatalog.getBundle(bundleName: String): Provider =
+ findBundle(bundleName).orElseThrow {
+ NoSuchElementException("Bundle with name $bundleName not found in the catalog")
+ }
+
+fun VersionCatalog.getLibrary(libraryName: String): Provider =
+ findLibrary(libraryName).orElseThrow {
+ NoSuchElementException("Library with name $libraryName not found in the catalog")
+ }
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidApplicationPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidApplicationPlugin.kt
new file mode 100644
index 00000000..b70907ce
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidApplicationPlugin.kt
@@ -0,0 +1,60 @@
+package kr.genti.convention.plugin
+
+import com.android.build.api.dsl.ApplicationExtension
+import kr.genti.convention.Constants
+import kr.genti.convention.config.configureAndroidCommonPlugin
+import kr.genti.convention.extension.kotlinOptions
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidApplicationPlugin : Plugin {
+ override fun apply(target: Project) =
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.application")
+ }
+
+ extensions.configure {
+ configureAndroidCommonPlugin()
+
+ namespace = Constants.packageName
+ compileSdk = Constants.compileSdk
+
+ defaultConfig {
+ applicationId = Constants.packageName
+ targetSdk = Constants.targetSdk
+ minSdk = Constants.minSdk
+ versionCode = Constants.versionCode
+ versionName = Constants.versionName
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ compileOptions {
+ sourceCompatibility = Constants.JAVA_VERSION
+ targetCompatibility = Constants.JAVA_VERSION
+ }
+
+ kotlinOptions {
+ jvmTarget = Constants.jvmVersion
+ }
+
+ buildFeatures {
+ buildConfig = true
+ viewBinding = true
+ dataBinding = true
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro",
+ )
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidLibraryPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidLibraryPlugin.kt
new file mode 100644
index 00000000..bec5c5d6
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/AndroidLibraryPlugin.kt
@@ -0,0 +1,47 @@
+package kr.genti.convention.plugin
+
+import com.android.build.gradle.LibraryExtension
+import kr.genti.convention.Constants
+import kr.genti.convention.config.configureAndroidCommonPlugin
+import kr.genti.convention.extension.kotlinOptions
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidLibraryPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.library")
+ }
+
+ extensions.configure {
+ configureAndroidCommonPlugin()
+
+ compileSdk = Constants.compileSdk
+
+ defaultConfig {
+ minSdk = Constants.minSdk
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ compileOptions {
+ sourceCompatibility = Constants.JAVA_VERSION
+ targetCompatibility = Constants.JAVA_VERSION
+ }
+
+ kotlinOptions {
+ jvmTarget = Constants.jvmVersion
+ }
+
+ buildFeatures {
+ buildConfig = true
+ dataBinding = true
+ viewBinding = true
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/HiltPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/HiltPlugin.kt
new file mode 100644
index 00000000..630cba21
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/HiltPlugin.kt
@@ -0,0 +1,23 @@
+package kr.genti.convention.plugin
+
+import kr.genti.convention.extension.getLibrary
+import kr.genti.convention.extension.implementation
+import kr.genti.convention.extension.kapt
+import kr.genti.convention.extension.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.dependencies
+
+class HiltPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+ with(pluginManager) {
+ apply("org.jetbrains.kotlin.kapt")
+ apply("dagger.hilt.android.plugin")
+ }
+
+ dependencies {
+ implementation(libs.getLibrary("hilt"))
+ kapt(libs.getLibrary("hilt-compiler"))
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/JavaLibraryPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/JavaLibraryPlugin.kt
new file mode 100644
index 00000000..4866aa5b
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/JavaLibraryPlugin.kt
@@ -0,0 +1,31 @@
+package kr.genti.convention.plugin
+
+import kr.genti.convention.Constants
+import kr.genti.convention.extension.getBundle
+import kr.genti.convention.extension.implementation
+import kr.genti.convention.extension.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+
+class JavaLibraryPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("org.jetbrains.kotlin.jvm")
+ apply("java-library")
+ }
+
+ extensions.configure {
+ sourceCompatibility = Constants.JAVA_VERSION
+ targetCompatibility = Constants.JAVA_VERSION
+ }
+
+ dependencies {
+ implementation(libs.getBundle("kotlin"))
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/KotlinPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/KotlinPlugin.kt
new file mode 100644
index 00000000..98042b25
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/KotlinPlugin.kt
@@ -0,0 +1,20 @@
+package kr.genti.convention.plugin
+
+import kr.genti.convention.extension.getBundle
+import kr.genti.convention.extension.implementation
+import kr.genti.convention.extension.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.dependencies
+
+class KotlinPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+ with(pluginManager) {
+ apply("kotlin-android")
+ }
+
+ dependencies {
+ implementation(libs.getBundle("kotlin"))
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/TestPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/TestPlugin.kt
new file mode 100644
index 00000000..07f27941
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/TestPlugin.kt
@@ -0,0 +1,20 @@
+package kr.genti.convention.plugin
+
+import kr.genti.convention.extension.androidTestImplementation
+import kr.genti.convention.extension.getLibrary
+import kr.genti.convention.extension.libs
+import kr.genti.convention.extension.testImplementation
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.dependencies
+
+class TestPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+
+ dependencies {
+ testImplementation(libs.getLibrary("j-unit"))
+ androidTestImplementation(libs.getLibrary("j-unit-androidx-test"))
+ androidTestImplementation(libs.getLibrary("espresso-core"))
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/java/kr/genti/convention/plugin/VersionPlugin.kt b/build-logic/convention/src/main/java/kr/genti/convention/plugin/VersionPlugin.kt
new file mode 100644
index 00000000..eea141d9
--- /dev/null
+++ b/build-logic/convention/src/main/java/kr/genti/convention/plugin/VersionPlugin.kt
@@ -0,0 +1,14 @@
+package kr.genti.convention.plugin
+
+import kr.genti.convention.Constants
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class VersionPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+ with(extensions) {
+ extraProperties["versionName"] = Constants.versionName
+ extraProperties["versionCode"] = Constants.versionCode
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/gradle.properties b/build-logic/gradle.properties
new file mode 100644
index 00000000..6977b719
--- /dev/null
+++ b/build-logic/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.parallel=true
+org.gradle.caching=true
+org.gradle.configureondemand=true
\ No newline at end of file
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
new file mode 100644
index 00000000..fd968aff
--- /dev/null
+++ b/build-logic/settings.gradle.kts
@@ -0,0 +1,16 @@
+enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
+
+dependencyResolutionManagement {
+ repositories {
+ google()
+ mavenCentral()
+ }
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
+
+rootProject.name = "build-logic"
+include(":convention")
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index ed5abd78..5e93e036 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,18 +3,13 @@ buildscript {
google()
mavenCentral()
}
-
- dependencies {
- ClassPathPlugins.run {
- classpath(gradle)
- classpath(kotlinGradlePlugin)
- classpath(hiltGradlePlugin)
- classpath(googleServices)
- classpath(crashlyticsGradle)
- }
- }
}
-tasks.register("clean", Delete::class) {
- delete(rootProject.buildDir)
-}
+plugins {
+ alias(libs.plugins.android.application) apply false
+ alias(libs.plugins.kotlin.android) apply false
+ alias(libs.plugins.kotlin.serialization) apply false
+ alias(libs.plugins.hilt) apply false
+ alias(libs.plugins.google.services) apply false
+ alias(libs.plugins.google.crashlytics) apply false
+}
\ No newline at end of file
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
deleted file mode 100644
index b22ed732..00000000
--- a/buildSrc/build.gradle.kts
+++ /dev/null
@@ -1,7 +0,0 @@
-plugins {
- `kotlin-dsl`
-}
-
-repositories {
- mavenCentral()
-}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/Constants.kt b/buildSrc/src/main/kotlin/Constants.kt
deleted file mode 100644
index 8a436472..00000000
--- a/buildSrc/src/main/kotlin/Constants.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-object Constants {
- const val packageName = "kr.genti.android"
- const val compileSdk = 34
- const val minSdk = 28
- const val targetSdk = 34
- const val versionCode = 15
- const val versionName = "1.1.6"
-}
diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt
deleted file mode 100644
index 496a1319..00000000
--- a/buildSrc/src/main/kotlin/Dependencies.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-object KotlinDependencies {
- const val kotlin = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlinVersion}"
- const val coroutines =
- "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesAndroidVersion}"
- const val jsonSerialization =
- "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinSerializationJsonVersion}"
- const val dateTime = "org.jetbrains.kotlinx:kotlinx-datetime:${Versions.kotlinDateTimeVersion}"
-}
-
-object AndroidXDependencies {
- const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtxVersion}"
- const val splashScreen = "androidx.core:core-splashscreen:${Versions.splashVersion}"
-
- const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompatVersion}"
- const val constraintLayout =
- "androidx.constraintlayout:constraintlayout:${Versions.constraintLayoutVersion}"
- const val startup = "androidx.startup:startup-runtime:${Versions.appStartUpVersion}"
- const val fragment = "androidx.fragment:fragment-ktx:${Versions.fragmentKtxVersion}"
- const val legacy = "androidx.legacy:legacy-support-v4:${Versions.legacySupportVersion}"
- const val security = "androidx.security:security-crypto:${Versions.securityVersion}"
-
- const val navigationFragment =
- "androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}"
- const val navigationUi = "androidx.navigation:navigation-ui-ktx:${Versions.navigationVersion}"
-
- const val lifeCycleKtx = "androidx.lifecycle:lifecycle-runtime-ktx:${Versions.lifecycleVersion}"
- const val lifecycleJava8 =
- "androidx.lifecycle:lifecycle-common-java8:${Versions.lifecycleVersion}"
-
- const val hilt = "com.google.dagger:hilt-android:${Versions.hiltVersion}"
- const val appUpdate = "com.google.android.play:app-update-ktx:${Versions.appUpdateVersion}"
-}
-
-object TestDependencies {
- const val jUnit = "junit:junit:${Versions.junitVersion}"
- const val androidTest = "androidx.test.ext:junit:${Versions.androidTestVersion}"
- const val espresso = "androidx.test.espresso:espresso-core:${Versions.espressoVersion}"
-}
-
-object MaterialDesignDependencies {
- const val materialDesign =
- "com.google.android.material:material:${Versions.materialDesignVersion}"
-}
-
-object KaptDependencies {
- const val hiltCompiler = "com.google.dagger:hilt-compiler:${Versions.hiltVersion}"
-}
-
-object RetrofitDependencies {
- const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofitVersion}"
- const val retrofitJsonConverter =
- "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:${Versions.jsonConverterVersion}"
-
- const val okHttpBom = "com.squareup.okhttp3:okhttp-bom:${Versions.okHttpVersion}"
- const val okHttp = "com.squareup.okhttp3:okhttp"
- const val okHttpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor"
-}
-
-object ThirdPartyDependencies {
- const val coil = "io.coil-kt:coil:${Versions.coilVersion}"
- const val amplitude = "com.amplitude:analytics-android:${Versions.amplitudeVersion}"
- const val timber = "com.jakewharton.timber:timber:${Versions.timberVersion}"
- const val progressView = "com.github.skydoves:progressview:${Versions.progressViewVersion}"
- const val balloon = "com.github.skydoves:balloon:${Versions.balloonVersion}"
- const val lottie = "com.airbnb.android:lottie:${Versions.lottieVersion}"
- const val circularProgressBar =
- "com.mikhaellopez:circularprogressbar:${Versions.circularProgressBar}"
- const val circleIndicator = "me.relex:circleindicator:${Versions.circleIndicatorVersion}"
- const val shimmer = "com.facebook.shimmer:shimmer:${Versions.shimmerVersion}"
-}
-
-object ClassPathPlugins {
- const val gradle = "com.android.tools.build:gradle:${Versions.gradleVersion}"
- const val kotlinGradlePlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}"
- const val hiltGradlePlugin = "com.google.dagger:hilt-android-gradle-plugin:${Versions.hiltVersion}"
-
- const val googleServices = "com.google.gms:google-services:${Versions.googleServicesVersion}"
- const val crashlyticsGradle =
- "com.google.firebase:firebase-crashlytics-gradle:${Versions.crashlyticsVersion}"
-}
-
-object FirebaseDependencies {
- const val firebaseBom = "com.google.firebase:firebase-bom:${Versions.firebaseBomVersion}"
- const val messaging = "com.google.firebase:firebase-messaging-ktx"
- const val crashlytics = "com.google.firebase:firebase-crashlytics-ktx"
- const val analytics = "com.google.firebase:firebase-analytics-ktx"
-}
-
-object KakaoDependencies {
- const val user = "com.kakao.sdk:v2-user:${Versions.kakaoVersion}"
-}
diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt
deleted file mode 100644
index 8ac3fc3f..00000000
--- a/buildSrc/src/main/kotlin/Versions.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-import org.gradle.api.JavaVersion
-
-object Versions {
- const val gradleVersion = "8.0.2"
- const val kotlinVersion = "1.8.20"
-
- val javaVersion = JavaVersion.VERSION_17
- const val jvmVersion = "17"
-
- const val coroutinesAndroidVersion = "1.7.1"
- const val kotlinSerializationJsonVersion = "1.5.1"
- const val kotlinDateTimeVersion = "0.4.0"
- const val coreKtxVersion = "1.10.1"
- const val appCompatVersion = "1.6.1"
- const val materialDesignVersion = "1.9.0"
- const val constraintLayoutVersion = "2.1.4"
- const val appStartUpVersion = "1.1.1"
- const val legacySupportVersion = "1.0.0"
- const val securityVersion = "1.1.0-alpha06"
- const val hiltVersion = "2.46.1"
- const val fragmentKtxVersion = "1.5.7"
- const val navigationVersion = "2.7.7"
- const val lifecycleVersion = "2.6.1"
- const val splashVersion = "1.0.1"
- const val coilVersion = "2.4.0"
- const val retrofitVersion = "2.9.0"
- const val jsonConverterVersion = "1.0.0"
- const val okHttpVersion = "4.11.0"
- const val amplitudeVersion = "1.17.3"
- const val timberVersion = "5.0.1"
- const val progressViewVersion = "1.1.3"
- const val balloonVersion = "1.4.5"
- const val lottieVersion = "6.0.0"
- const val circularProgressBar = "3.1.0"
- const val kakaoVersion = "2.20.3"
- const val circleIndicatorVersion = "2.1.6"
- const val shimmerVersion = "0.5.0"
- const val junitVersion = "4.13.2"
- const val espressoVersion = "3.3.0"
- const val androidTestVersion = "1.1.2"
- const val firebaseBomVersion = "33.1.2"
- const val googleServicesVersion = "4.4.2"
- const val crashlyticsVersion = "2.9.9"
- const val appUpdateVersion = "2.1.0"
-}
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 15e47907..041fe5a5 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -1,50 +1,7 @@
plugins {
- id("com.android.library")
- kotlin("android")
- kotlin("kapt")
- id("dagger.hilt.android.plugin")
+ id("kr.genti.androidLibrary")
}
android {
namespace = "kr.genti.core"
- compileSdk = Constants.compileSdk
-
- defaultConfig {
- minSdk = Constants.minSdk
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
- compileOptions {
- sourceCompatibility = Versions.javaVersion
- targetCompatibility = Versions.javaVersion
- }
- kotlinOptions {
- jvmTarget = Versions.jvmVersion
- }
-
- buildFeatures {
- dataBinding = true
- viewBinding = true
- }
-}
-
-dependencies {
- // Kotlin
- implementation(KotlinDependencies.kotlin)
-
- // Lifecycle Ktx
- implementation(AndroidXDependencies.lifeCycleKtx)
-
- // Material Design
- implementation(MaterialDesignDependencies.materialDesign)
-
- // Hilt
- implementation(AndroidXDependencies.hilt)
- kapt(KaptDependencies.hiltCompiler)
-
- // Test Dependency
- testImplementation(TestDependencies.jUnit)
- androidTestImplementation(TestDependencies.androidTest)
- androidTestImplementation(TestDependencies.espresso)
}
diff --git a/core/src/main/java/kr/genti/core/base/BaseBottomSheet.kt b/core/src/main/java/kr/genti/core/base/BaseBottomSheet.kt
index fbab6e6d..8bc93a0d 100644
--- a/core/src/main/java/kr/genti/core/base/BaseBottomSheet.kt
+++ b/core/src/main/java/kr/genti/core/base/BaseBottomSheet.kt
@@ -1,5 +1,6 @@
package kr.genti.core.base
+import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -26,6 +27,12 @@ abstract class BaseBottomSheet(
return binding.root
}
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return super.onCreateDialog(savedInstanceState).apply {
+ window?.setDimAmount(0.8f)
+ }
+ }
+
override fun onDestroyView() {
super.onDestroyView()
_binding = null
diff --git a/core/src/main/java/kr/genti/core/base/BaseDialog.kt b/core/src/main/java/kr/genti/core/base/BaseDialog.kt
index cad653b0..67e6d5a7 100644
--- a/core/src/main/java/kr/genti/core/base/BaseDialog.kt
+++ b/core/src/main/java/kr/genti/core/base/BaseDialog.kt
@@ -1,5 +1,6 @@
package kr.genti.core.base
+import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@@ -8,6 +9,7 @@ import androidx.annotation.LayoutRes
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.DialogFragment
+import kr.genti.core.R
abstract class BaseDialog(
@LayoutRes private val layoutRes: Int,
@@ -26,6 +28,13 @@ abstract class BaseDialog(
return binding.root
}
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ return super.onCreateDialog(savedInstanceState).apply {
+ window?.setWindowAnimations(R.style.DialogAnimation)
+ window?.setDimAmount(0.8f)
+ }
+ }
+
override fun onDestroyView() {
super.onDestroyView()
_binding = null
diff --git a/core/src/main/java/kr/genti/core/extension/StringExt.kt b/core/src/main/java/kr/genti/core/extension/StringExt.kt
index b0a1764a..d60841ea 100644
--- a/core/src/main/java/kr/genti/core/extension/StringExt.kt
+++ b/core/src/main/java/kr/genti/core/extension/StringExt.kt
@@ -18,3 +18,5 @@ fun String.getGraphemeLength(): Int {
return count
}
+
+fun String.breakLines(): String = this.replace(Regex("\\s+"), " ")
\ No newline at end of file
diff --git a/core/src/main/java/kr/genti/core/extension/ViewExt.kt b/core/src/main/java/kr/genti/core/extension/ViewExt.kt
index 3ef6859c..1ead55e2 100644
--- a/core/src/main/java/kr/genti/core/extension/ViewExt.kt
+++ b/core/src/main/java/kr/genti/core/extension/ViewExt.kt
@@ -1,9 +1,14 @@
package kr.genti.core.extension
+import android.graphics.LinearGradient
import android.graphics.RenderEffect
import android.graphics.Shader
import android.os.Build
+import android.text.Spannable
+import android.text.SpannableString
+import android.text.style.ImageSpan
import android.view.View
+import android.widget.TextView
inline fun View.setOnSingleClickListener(
delay: Long = 1000L,
@@ -30,3 +35,22 @@ fun View.setGusianBlur(radius: Float?) {
}
}
}
+
+fun TextView.setGradientText(startColor: Int, endColor: Int) {
+ paint.shader = LinearGradient(
+ 0f,
+ 0f,
+ paint.measureText(text.toString()),
+ textSize,
+ intArrayOf(startColor, endColor),
+ null,
+ Shader.TileMode.CLAMP
+ )
+}
+
+fun TextView.setTextWithImage(text: String, imageResId: Int) {
+ val spannableString = SpannableString(" $text")
+ val imageSpan = ImageSpan(context, imageResId, ImageSpan.ALIGN_BOTTOM)
+ spannableString.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
+ this.text = spannableString
+}
\ No newline at end of file
diff --git a/core/src/main/res/anim/fade_in.xml b/core/src/main/res/anim/fade_in.xml
new file mode 100644
index 00000000..712773e4
--- /dev/null
+++ b/core/src/main/res/anim/fade_in.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/core/src/main/res/anim/fade_out.xml b/core/src/main/res/anim/fade_out.xml
new file mode 100644
index 00000000..6f15c325
--- /dev/null
+++ b/core/src/main/res/anim/fade_out.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
new file mode 100644
index 00000000..a45c00f0
--- /dev/null
+++ b/core/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/data/build.gradle.kts b/data/build.gradle.kts
index 56c5dcb2..61889a67 100644
--- a/data/build.gradle.kts
+++ b/data/build.gradle.kts
@@ -1,66 +1,14 @@
plugins {
- id("com.android.library")
- kotlin("android")
- kotlin("kapt")
- kotlin("plugin.serialization") version Versions.kotlinVersion
+ id("kr.genti.androidLibrary")
}
android {
namespace = "kr.genti.data"
- compileSdk = Constants.compileSdk
-
- defaultConfig {
- minSdk = Constants.minSdk
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- compileOptions {
- sourceCompatibility = Versions.javaVersion
- targetCompatibility = Versions.javaVersion
- }
-
- kotlinOptions {
- jvmTarget = Versions.jvmVersion
- }
-
- buildFeatures {
- buildConfig = true
- }
}
dependencies {
- implementation(project(":domain"))
-
- AndroidXDependencies.run {
- implementation(hilt)
- implementation(security)
- implementation(coreKtx)
- }
-
- KotlinDependencies.run {
- implementation(kotlin)
- implementation(jsonSerialization)
- implementation(coroutines)
- implementation(dateTime)
- }
-
- RetrofitDependencies.run {
- implementation(platform(okHttpBom))
- implementation(okHttp)
- implementation(okHttpLoggingInterceptor)
- implementation(retrofit)
- implementation(retrofitJsonConverter)
- }
-
- ThirdPartyDependencies.run {
- implementation(timber)
- }
+ implementation(projects.domain)
- TestDependencies.run {
- testImplementation(jUnit)
- androidTestImplementation(androidTest)
- androidTestImplementation(espresso)
- }
+ implementation(platform(libs.okhttp.bom))
+ implementation(libs.bundles.networking)
}
diff --git a/data/src/main/java/kr/genti/data/dataSource/CreateDataSource.kt b/data/src/main/java/kr/genti/data/dataSource/CreateDataSource.kt
index a2797965..ec7e929d 100644
--- a/data/src/main/java/kr/genti/data/dataSource/CreateDataSource.kt
+++ b/data/src/main/java/kr/genti/data/dataSource/CreateDataSource.kt
@@ -2,8 +2,10 @@ package kr.genti.data.dataSource
import kr.genti.data.dto.BaseResponse
import kr.genti.data.dto.request.CreateRequestDto
+import kr.genti.data.dto.request.CreateTwoRequestDto
import kr.genti.data.dto.request.KeyRequestDto
import kr.genti.data.dto.request.S3RequestDto
+import kr.genti.data.dto.response.PromptExampleDto
import kr.genti.data.dto.response.S3PresignedUrlDto
interface CreateDataSource {
@@ -13,5 +15,11 @@ interface CreateDataSource {
suspend fun postToCreate(request: CreateRequestDto): BaseResponse
+ suspend fun postToCreateOne(request: CreateRequestDto): BaseResponse
+
+ suspend fun postToCreateTwo(request: CreateTwoRequestDto): BaseResponse
+
suspend fun postToVerify(request: KeyRequestDto): BaseResponse
+
+ suspend fun getPromptExample(): BaseResponse>
}
diff --git a/data/src/main/java/kr/genti/data/dataSource/GenerateDataSource.kt b/data/src/main/java/kr/genti/data/dataSource/GenerateDataSource.kt
index 1ae9ae3c..0a1fd96d 100644
--- a/data/src/main/java/kr/genti/data/dataSource/GenerateDataSource.kt
+++ b/data/src/main/java/kr/genti/data/dataSource/GenerateDataSource.kt
@@ -33,4 +33,6 @@ interface GenerateDataSource {
suspend fun getIsUserVerified(): BaseResponse
suspend fun getIsServerAvailable(): BaseResponse
+
+ suspend fun patchStatusInDevelop(): BaseResponse
}
diff --git a/data/src/main/java/kr/genti/data/dataSourceImpl/CreateDataSourceImpl.kt b/data/src/main/java/kr/genti/data/dataSourceImpl/CreateDataSourceImpl.kt
index 82b55e2f..cbb8815b 100644
--- a/data/src/main/java/kr/genti/data/dataSourceImpl/CreateDataSourceImpl.kt
+++ b/data/src/main/java/kr/genti/data/dataSourceImpl/CreateDataSourceImpl.kt
@@ -3,23 +3,37 @@ package kr.genti.data.dataSourceImpl
import kr.genti.data.dataSource.CreateDataSource
import kr.genti.data.dto.BaseResponse
import kr.genti.data.dto.request.CreateRequestDto
+import kr.genti.data.dto.request.CreateTwoRequestDto
import kr.genti.data.dto.request.KeyRequestDto
import kr.genti.data.dto.request.S3RequestDto
+import kr.genti.data.dto.response.PromptExampleDto
import kr.genti.data.dto.response.S3PresignedUrlDto
import kr.genti.data.service.CreateService
import javax.inject.Inject
data class CreateDataSourceImpl
- @Inject
- constructor(
- private val createService: CreateService,
- ) : CreateDataSource {
- override suspend fun getSingleS3Url(request: S3RequestDto): BaseResponse = createService.getSingleS3Url(request)
+@Inject
+constructor(
+ private val createService: CreateService,
+) : CreateDataSource {
+ override suspend fun getSingleS3Url(request: S3RequestDto): BaseResponse =
+ createService.getSingleS3Url(request)
- override suspend fun getMultiS3Url(request: List): BaseResponse> =
- createService.getMultiS3Url(request)
+ override suspend fun getMultiS3Url(request: List): BaseResponse> =
+ createService.getMultiS3Url(request)
- override suspend fun postToCreate(request: CreateRequestDto): BaseResponse = createService.postToCreate(request)
+ override suspend fun postToCreate(request: CreateRequestDto): BaseResponse =
+ createService.postToCreate(request)
- override suspend fun postToVerify(request: KeyRequestDto): BaseResponse = createService.postToVerify(request)
- }
+ override suspend fun postToCreateOne(request: CreateRequestDto): BaseResponse =
+ createService.postToCreateOne(request)
+
+ override suspend fun postToCreateTwo(request: CreateTwoRequestDto): BaseResponse =
+ createService.postToCreateTwo(request)
+
+ override suspend fun postToVerify(request: KeyRequestDto): BaseResponse =
+ createService.postToVerify(request)
+
+ override suspend fun getPromptExample(): BaseResponse> =
+ createService.getPromptExample()
+}
diff --git a/data/src/main/java/kr/genti/data/dataSourceImpl/GenerateDataSourceImpl.kt b/data/src/main/java/kr/genti/data/dataSourceImpl/GenerateDataSourceImpl.kt
index b4bed88e..afa881f4 100644
--- a/data/src/main/java/kr/genti/data/dataSourceImpl/GenerateDataSourceImpl.kt
+++ b/data/src/main/java/kr/genti/data/dataSourceImpl/GenerateDataSourceImpl.kt
@@ -11,35 +11,44 @@ import kr.genti.data.service.GenerateService
import javax.inject.Inject
data class GenerateDataSourceImpl
- @Inject
- constructor(
- private val generateService: GenerateService,
- ) : GenerateDataSource {
- override suspend fun getGenerateStatus(): BaseResponse = generateService.getGenerateStatus()
-
- override suspend fun getGeneratedPictureList(
- page: Int,
- size: Int,
- sortBy: String?,
- direction: String?,
- ): BaseResponse = generateService.getGeneratedPictureList(page, size, sortBy, direction)
-
- override suspend fun postGenerateReport(request: ReportRequestDto): BaseResponse =
- generateService.postGenerateReport(request)
-
- override suspend fun postGenerateRate(
- responseId: Int,
- star: Int,
- ): BaseResponse = generateService.postGenerateRate(responseId, star)
-
- override suspend fun postVerifyGenerateState(responseId: Int): BaseResponse =
- generateService.postVerifyGenerateState(responseId)
-
- override suspend fun getCanceledToReset(requestId: String): BaseResponse = generateService.getCanceledToReset(requestId)
-
- override suspend fun getOpenchatData(): BaseResponse = generateService.getOpenchatData()
-
- override suspend fun getIsUserVerified(): BaseResponse = generateService.getIsUserVerified()
-
- override suspend fun getIsServerAvailable(): BaseResponse = generateService.getIsServerAvailable()
- }
+@Inject
+constructor(
+ private val generateService: GenerateService,
+) : GenerateDataSource {
+ override suspend fun getGenerateStatus(): BaseResponse =
+ generateService.getGenerateStatus()
+
+ override suspend fun getGeneratedPictureList(
+ page: Int,
+ size: Int,
+ sortBy: String?,
+ direction: String?,
+ ): BaseResponse =
+ generateService.getGeneratedPictureList(page, size, sortBy, direction)
+
+ override suspend fun postGenerateReport(request: ReportRequestDto): BaseResponse =
+ generateService.postGenerateReport(request)
+
+ override suspend fun postGenerateRate(
+ responseId: Int,
+ star: Int,
+ ): BaseResponse = generateService.postGenerateRate(responseId, star)
+
+ override suspend fun postVerifyGenerateState(responseId: Int): BaseResponse =
+ generateService.postVerifyGenerateState(responseId)
+
+ override suspend fun getCanceledToReset(requestId: String): BaseResponse =
+ generateService.getCanceledToReset(requestId)
+
+ override suspend fun getOpenchatData(): BaseResponse =
+ generateService.getOpenchatData()
+
+ override suspend fun getIsUserVerified(): BaseResponse =
+ generateService.getIsUserVerified()
+
+ override suspend fun getIsServerAvailable(): BaseResponse =
+ generateService.getIsServerAvailable()
+
+ override suspend fun patchStatusInDevelop(): BaseResponse =
+ generateService.patchStatusInDevelop()
+}
diff --git a/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt b/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt
index f50f5795..3a95e1f2 100644
--- a/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt
+++ b/data/src/main/java/kr/genti/data/dto/request/CreateRequestDto.kt
@@ -4,22 +4,14 @@ import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kr.genti.data.dto.request.KeyRequestDto.Companion.toDto
import kr.genti.domain.entity.request.CreateRequestModel
-import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.PictureRatio
-import kr.genti.domain.enums.ShotCoverage
@Serializable
data class CreateRequestDto(
@SerialName("prompt")
val prompt: String,
- @SerialName("posePicture")
- val posePicture: KeyRequestDto?,
@SerialName("facePictureList")
val facePictureList: List,
- @SerialName("cameraAngle")
- val cameraAngle: CameraAngle,
- @SerialName("shotCoverage")
- val shotCoverage: ShotCoverage,
@SerialName("pictureRatio")
val pictureRatio: PictureRatio,
) {
@@ -27,10 +19,7 @@ data class CreateRequestDto(
fun CreateRequestModel.toDto() =
CreateRequestDto(
prompt,
- posePicture?.toDto(),
facePictureList.map { it.toDto() },
- cameraAngle,
- shotCoverage,
pictureRatio,
)
}
diff --git a/data/src/main/java/kr/genti/data/dto/request/CreateTwoRequestDto.kt b/data/src/main/java/kr/genti/data/dto/request/CreateTwoRequestDto.kt
new file mode 100644
index 00000000..4876c55e
--- /dev/null
+++ b/data/src/main/java/kr/genti/data/dto/request/CreateTwoRequestDto.kt
@@ -0,0 +1,29 @@
+package kr.genti.data.dto.request
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kr.genti.data.dto.request.KeyRequestDto.Companion.toDto
+import kr.genti.domain.entity.request.CreateTwoRequestModel
+import kr.genti.domain.enums.PictureRatio
+
+@Serializable
+data class CreateTwoRequestDto(
+ @SerialName("prompt")
+ val prompt: String,
+ @SerialName("facePictureList")
+ val facePictureList: List,
+ @SerialName("otherFacePictureList")
+ val otherFacePictureList: List,
+ @SerialName("pictureRatio")
+ val pictureRatio: PictureRatio,
+) {
+ companion object {
+ fun CreateTwoRequestModel.toDto() =
+ CreateTwoRequestDto(
+ prompt,
+ facePictureList.map { it.toDto() },
+ otherFacePictureList.map { it.toDto() },
+ pictureRatio,
+ )
+ }
+}
diff --git a/data/src/main/java/kr/genti/data/dto/response/GenerateStatusDto.kt b/data/src/main/java/kr/genti/data/dto/response/GenerateStatusDto.kt
index 04abf79c..a6995d07 100644
--- a/data/src/main/java/kr/genti/data/dto/response/GenerateStatusDto.kt
+++ b/data/src/main/java/kr/genti/data/dto/response/GenerateStatusDto.kt
@@ -13,6 +13,8 @@ data class GenerateStatusDto(
val status: GenerateStatus,
@SerialName("pictureGenerateResponse")
val pictureGenerateResponse: GenerateResponseDto?,
+ @SerialName("paid")
+ val paid: Boolean?,
) {
@Serializable
data class GenerateResponseDto(
@@ -33,5 +35,6 @@ data class GenerateStatusDto(
pictureGenerateRequestId,
status,
pictureGenerateResponse?.toModel(),
+ paid,
)
}
diff --git a/data/src/main/java/kr/genti/data/dto/response/PromptExampleDto.kt b/data/src/main/java/kr/genti/data/dto/response/PromptExampleDto.kt
new file mode 100644
index 00000000..2bf433ee
--- /dev/null
+++ b/data/src/main/java/kr/genti/data/dto/response/PromptExampleDto.kt
@@ -0,0 +1,15 @@
+package kr.genti.data.dto.response
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kr.genti.domain.entity.response.PromptExampleModel
+
+@Serializable
+data class PromptExampleDto(
+ @SerialName("url")
+ val url: String,
+ @SerialName("prompt")
+ val prompt: String,
+) {
+ fun toModel() = PromptExampleModel(url, prompt)
+}
\ No newline at end of file
diff --git a/data/src/main/java/kr/genti/data/local/UserSharedPref.kt b/data/src/main/java/kr/genti/data/local/UserSharedPref.kt
index 35f3fd8b..2214945b 100644
--- a/data/src/main/java/kr/genti/data/local/UserSharedPref.kt
+++ b/data/src/main/java/kr/genti/data/local/UserSharedPref.kt
@@ -4,8 +4,6 @@ interface UserSharedPref {
var accessToken: String
var refreshToken: String
var userRole: String
- var isGuideNeeded: Boolean
- var isChatAccessible: Boolean
fun clearInfo()
}
diff --git a/data/src/main/java/kr/genti/data/local/UserSharedPrefImpl.kt b/data/src/main/java/kr/genti/data/local/UserSharedPrefImpl.kt
index 50c6eaba..03bb6571 100644
--- a/data/src/main/java/kr/genti/data/local/UserSharedPrefImpl.kt
+++ b/data/src/main/java/kr/genti/data/local/UserSharedPrefImpl.kt
@@ -21,14 +21,6 @@ class UserSharedPrefImpl
get() = dataStore.getString(USER_ROLE, "").orEmpty()
set(value) = dataStore.edit { putString(USER_ROLE, value) }
- override var isGuideNeeded: Boolean
- get() = dataStore.getBoolean(IS_GUIDE_NEEDED, true)
- set(value) = dataStore.edit { putBoolean(IS_GUIDE_NEEDED, value) }
-
- override var isChatAccessible: Boolean
- get() = dataStore.getBoolean(IS_CHAT_ACCESSIBLE, true)
- set(value) = dataStore.edit { putBoolean(IS_CHAT_ACCESSIBLE, value) }
-
override fun clearInfo() {
dataStore.edit().clear().apply()
}
@@ -37,7 +29,6 @@ class UserSharedPrefImpl
private const val ACCESS_TOKEN = "ACCESS_TOKEN"
private const val REFRESH_TOKEN = "REFRESH_TOKEN"
private const val USER_ROLE = "USER_ROLE"
- private const val IS_GUIDE_NEEDED = "IS_GUIDE_NEEDED"
private const val IS_CHAT_ACCESSIBLE = "IS_CHAT_ACCESSIBLE"
}
}
diff --git a/data/src/main/java/kr/genti/data/repositoryImpl/CreateRepositoryImpl.kt b/data/src/main/java/kr/genti/data/repositoryImpl/CreateRepositoryImpl.kt
index dc3db02e..d3e4435f 100644
--- a/data/src/main/java/kr/genti/data/repositoryImpl/CreateRepositoryImpl.kt
+++ b/data/src/main/java/kr/genti/data/repositoryImpl/CreateRepositoryImpl.kt
@@ -2,37 +2,55 @@ package kr.genti.data.repositoryImpl
import kr.genti.data.dataSource.CreateDataSource
import kr.genti.data.dto.request.CreateRequestDto.Companion.toDto
+import kr.genti.data.dto.request.CreateTwoRequestDto.Companion.toDto
import kr.genti.data.dto.request.KeyRequestDto.Companion.toDto
import kr.genti.data.dto.request.S3RequestDto.Companion.toDto
import kr.genti.domain.entity.request.CreateRequestModel
+import kr.genti.domain.entity.request.CreateTwoRequestModel
import kr.genti.domain.entity.request.KeyRequestModel
import kr.genti.domain.entity.request.S3RequestModel
+import kr.genti.domain.entity.response.PromptExampleModel
import kr.genti.domain.entity.response.S3PresignedUrlModel
import kr.genti.domain.repository.CreateRepository
import javax.inject.Inject
class CreateRepositoryImpl
- @Inject
- constructor(
- private val createDataSource: CreateDataSource,
- ) : CreateRepository {
- override suspend fun getS3SingleUrl(request: S3RequestModel): Result =
- runCatching {
- createDataSource.getSingleS3Url(request.toDto()).response.toModel()
- }
-
- override suspend fun getS3MultiUrl(request: List): Result> =
- runCatching {
- createDataSource.getMultiS3Url(request.map { it.toDto() }).response.map { it.toModel() }
- }
-
- override suspend fun postToCreate(request: CreateRequestModel): Result =
- runCatching {
- createDataSource.postToCreate(request.toDto()).response
- }
-
- override suspend fun postToVerify(request: KeyRequestModel): Result =
- runCatching {
- createDataSource.postToVerify(request.toDto()).response
- }
- }
+@Inject
+constructor(
+ private val createDataSource: CreateDataSource,
+) : CreateRepository {
+ override suspend fun getS3SingleUrl(request: S3RequestModel): Result =
+ runCatching {
+ createDataSource.getSingleS3Url(request.toDto()).response.toModel()
+ }
+
+ override suspend fun getS3MultiUrl(request: List): Result> =
+ runCatching {
+ createDataSource.getMultiS3Url(request.map { it.toDto() }).response.map { it.toModel() }
+ }
+
+ override suspend fun postToCreate(request: CreateRequestModel): Result =
+ runCatching {
+ createDataSource.postToCreate(request.toDto()).response
+ }
+
+ override suspend fun postToCreateOne(request: CreateRequestModel): Result =
+ runCatching {
+ createDataSource.postToCreateOne(request.toDto()).response
+ }
+
+ override suspend fun postToCreateTwo(request: CreateTwoRequestModel): Result =
+ runCatching {
+ createDataSource.postToCreateTwo(request.toDto()).response
+ }
+
+ override suspend fun postToVerify(request: KeyRequestModel): Result =
+ runCatching {
+ createDataSource.postToVerify(request.toDto()).response
+ }
+
+ override suspend fun getPromptExample(): Result> =
+ runCatching {
+ createDataSource.getPromptExample().response.map { it.toModel() }
+ }
+}
diff --git a/data/src/main/java/kr/genti/data/repositoryImpl/GenerateRepositoryImpl.kt b/data/src/main/java/kr/genti/data/repositoryImpl/GenerateRepositoryImpl.kt
index 50a31f7c..5220b5c8 100644
--- a/data/src/main/java/kr/genti/data/repositoryImpl/GenerateRepositoryImpl.kt
+++ b/data/src/main/java/kr/genti/data/repositoryImpl/GenerateRepositoryImpl.kt
@@ -11,67 +11,72 @@ import kr.genti.domain.repository.GenerateRepository
import javax.inject.Inject
class GenerateRepositoryImpl
- @Inject
- constructor(
- private val generateDataSource: GenerateDataSource,
- ) : GenerateRepository {
- override suspend fun getGenerateStatus(): Result =
- runCatching {
- generateDataSource.getGenerateStatus().response.toModel()
- }
+@Inject
+constructor(
+ private val generateDataSource: GenerateDataSource,
+) : GenerateRepository {
+ override suspend fun getGenerateStatus(): Result =
+ runCatching {
+ generateDataSource.getGenerateStatus().response.toModel()
+ }
- override suspend fun getGeneratedPictureList(
- page: Int,
- size: Int,
- sortBy: String?,
- direction: String?,
- ): Result =
- runCatching {
- generateDataSource
- .getGeneratedPictureList(
- page,
- size,
- sortBy,
- direction,
- ).response
- .toModel()
- }
+ override suspend fun getGeneratedPictureList(
+ page: Int,
+ size: Int,
+ sortBy: String?,
+ direction: String?,
+ ): Result =
+ runCatching {
+ generateDataSource
+ .getGeneratedPictureList(
+ page,
+ size,
+ sortBy,
+ direction,
+ ).response
+ .toModel()
+ }
- override suspend fun postGenerateReport(request: ReportRequestModel): Result =
- runCatching {
- generateDataSource.postGenerateReport(request.toDto()).response
- }
+ override suspend fun postGenerateReport(request: ReportRequestModel): Result =
+ runCatching {
+ generateDataSource.postGenerateReport(request.toDto()).response
+ }
- override suspend fun postGenerateRate(
- responseId: Int,
- star: Int,
- ): Result =
- runCatching {
- generateDataSource.postGenerateRate(responseId, star).response
- }
+ override suspend fun postGenerateRate(
+ responseId: Int,
+ star: Int,
+ ): Result =
+ runCatching {
+ generateDataSource.postGenerateRate(responseId, star).response
+ }
- override suspend fun postVerifyGenerateState(responseId: Int): Result =
- runCatching {
- generateDataSource.postVerifyGenerateState(responseId).response
- }
+ override suspend fun postVerifyGenerateState(responseId: Int): Result =
+ runCatching {
+ generateDataSource.postVerifyGenerateState(responseId).response
+ }
- override suspend fun getCanceledToReset(requestId: String): Result =
- runCatching {
- generateDataSource.getCanceledToReset(requestId).response
- }
+ override suspend fun getCanceledToReset(requestId: String): Result =
+ runCatching {
+ generateDataSource.getCanceledToReset(requestId).response
+ }
- override suspend fun getOpenchatData(): Result =
- runCatching {
- generateDataSource.getOpenchatData().response.toModel()
- }
+ override suspend fun getOpenchatData(): Result =
+ runCatching {
+ generateDataSource.getOpenchatData().response.toModel()
+ }
- override suspend fun getIsUserVerified(): Result =
- runCatching {
- generateDataSource.getIsUserVerified().response
- }
+ override suspend fun getIsUserVerified(): Result =
+ runCatching {
+ generateDataSource.getIsUserVerified().response
+ }
- override suspend fun getIsServerAvailable(): Result =
- runCatching {
- generateDataSource.getIsServerAvailable().response.toModel()
- }
- }
+ override suspend fun getIsServerAvailable(): Result =
+ runCatching {
+ generateDataSource.getIsServerAvailable().response.toModel()
+ }
+
+ override suspend fun patchStatusInDevelop(): Result =
+ runCatching {
+ generateDataSource.patchStatusInDevelop().response
+ }
+}
diff --git a/data/src/main/java/kr/genti/data/repositoryImpl/UserRepositoryImpl.kt b/data/src/main/java/kr/genti/data/repositoryImpl/UserRepositoryImpl.kt
index 4200e4ab..876214a7 100644
--- a/data/src/main/java/kr/genti/data/repositoryImpl/UserRepositoryImpl.kt
+++ b/data/src/main/java/kr/genti/data/repositoryImpl/UserRepositoryImpl.kt
@@ -15,10 +15,6 @@ class UserRepositoryImpl
override fun getUserRole(): String = userSharedPref.userRole
- override fun getIsGuideNeeded(): Boolean = userSharedPref.isGuideNeeded
-
- override fun getIsChatAccessible(): Boolean = userSharedPref.isChatAccessible
-
override fun setTokens(
accessToken: String,
refreshToken: String,
@@ -31,14 +27,6 @@ class UserRepositoryImpl
userSharedPref.userRole = userRole
}
- override fun setIsGuideNeeded(isGuideNeeded: Boolean) {
- userSharedPref.isGuideNeeded = isGuideNeeded
- }
-
- override fun setIsChatAccessible(isChatAccessible: Boolean) {
- userSharedPref.isChatAccessible = isChatAccessible
- }
-
override fun clearInfo() {
userSharedPref.clearInfo()
}
diff --git a/data/src/main/java/kr/genti/data/service/CreateService.kt b/data/src/main/java/kr/genti/data/service/CreateService.kt
index df5c76b0..b84cf4be 100644
--- a/data/src/main/java/kr/genti/data/service/CreateService.kt
+++ b/data/src/main/java/kr/genti/data/service/CreateService.kt
@@ -2,10 +2,13 @@ package kr.genti.data.service
import kr.genti.data.dto.BaseResponse
import kr.genti.data.dto.request.CreateRequestDto
+import kr.genti.data.dto.request.CreateTwoRequestDto
import kr.genti.data.dto.request.KeyRequestDto
import kr.genti.data.dto.request.S3RequestDto
+import kr.genti.data.dto.response.PromptExampleDto
import kr.genti.data.dto.response.S3PresignedUrlDto
import retrofit2.http.Body
+import retrofit2.http.GET
import retrofit2.http.POST
interface CreateService {
@@ -24,8 +27,21 @@ interface CreateService {
@Body request: CreateRequestDto,
): BaseResponse
+ @POST("api/v1/users/picture-generate-requests/paid/one")
+ suspend fun postToCreateOne(
+ @Body request: CreateRequestDto,
+ ): BaseResponse
+
+ @POST("api/v1/users/picture-generate-requests/paid/two")
+ suspend fun postToCreateTwo(
+ @Body request: CreateTwoRequestDto,
+ ): BaseResponse
+
@POST("api/v1/user-verification")
suspend fun postToVerify(
@Body request: KeyRequestDto,
): BaseResponse
+
+ @GET("api/v1/users/examples/with-picture-square")
+ suspend fun getPromptExample(): BaseResponse>
}
diff --git a/data/src/main/java/kr/genti/data/service/GenerateService.kt b/data/src/main/java/kr/genti/data/service/GenerateService.kt
index 1b4e77f5..c90c0a13 100644
--- a/data/src/main/java/kr/genti/data/service/GenerateService.kt
+++ b/data/src/main/java/kr/genti/data/service/GenerateService.kt
@@ -53,4 +53,7 @@ interface GenerateService {
@GET("api/v1/maintenance")
suspend fun getIsServerAvailable(): BaseResponse
+
+ @POST("api/v1/frontend/picture-generate-responses")
+ suspend fun patchStatusInDevelop(): BaseResponse
}
diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts
index 649449cf..5b9bf4c5 100644
--- a/domain/build.gradle.kts
+++ b/domain/build.gradle.kts
@@ -1,18 +1,3 @@
plugins {
- id("java-library")
- kotlin("jvm")
- kotlin("kapt")
-}
-
-java {
- sourceCompatibility = Versions.javaVersion
- targetCompatibility = Versions.javaVersion
-}
-
-dependencies {
- KotlinDependencies.run {
- implementation(kotlin)
- implementation(coroutines)
- implementation(dateTime)
- }
+ id("kr.genti.javaLibrary")
}
\ No newline at end of file
diff --git a/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateRequestModel.kt b/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateRequestModel.kt
index 742e7ae3..75e522ea 100644
--- a/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateRequestModel.kt
+++ b/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateRequestModel.kt
@@ -1,14 +1,9 @@
package kr.genti.domain.entity.request
-import kr.genti.domain.enums.CameraAngle
import kr.genti.domain.enums.PictureRatio
-import kr.genti.domain.enums.ShotCoverage
data class CreateRequestModel(
val prompt: String,
- val posePicture: KeyRequestModel?,
val facePictureList: List,
- val cameraAngle: CameraAngle,
- val shotCoverage: ShotCoverage,
val pictureRatio: PictureRatio,
)
diff --git a/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateTwoRequestModel.kt b/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateTwoRequestModel.kt
new file mode 100644
index 00000000..e96793ed
--- /dev/null
+++ b/domain/src/main/kotlin/kr/genti/domain/entity/request/CreateTwoRequestModel.kt
@@ -0,0 +1,10 @@
+package kr.genti.domain.entity.request
+
+import kr.genti.domain.enums.PictureRatio
+
+data class CreateTwoRequestModel(
+ val prompt: String,
+ val facePictureList: List,
+ val otherFacePictureList: List,
+ val pictureRatio: PictureRatio,
+)
diff --git a/domain/src/main/kotlin/kr/genti/domain/entity/response/GenerateStatusModel.kt b/domain/src/main/kotlin/kr/genti/domain/entity/response/GenerateStatusModel.kt
index cd946bd2..0ed62e7c 100644
--- a/domain/src/main/kotlin/kr/genti/domain/entity/response/GenerateStatusModel.kt
+++ b/domain/src/main/kotlin/kr/genti/domain/entity/response/GenerateStatusModel.kt
@@ -3,12 +3,13 @@ package kr.genti.domain.entity.response
import kr.genti.domain.enums.GenerateStatus
data class GenerateStatusModel(
- val pictureGenerateRequestId: Long?,
+ val requestId: Long?,
val status: GenerateStatus,
- val pictureGenerateResponse: GenerateResponseModel?,
+ val response: GenerateResponseModel?,
+ val paid: Boolean?,
) {
data class GenerateResponseModel(
- val pictureGenerateResponseId: Long,
- val pictureCompleted: ImageModel?,
+ val responseId: Long,
+ val picture: ImageModel?,
)
}
diff --git a/domain/src/main/kotlin/kr/genti/domain/entity/response/PromptExampleModel.kt b/domain/src/main/kotlin/kr/genti/domain/entity/response/PromptExampleModel.kt
new file mode 100644
index 00000000..8c9a8e20
--- /dev/null
+++ b/domain/src/main/kotlin/kr/genti/domain/entity/response/PromptExampleModel.kt
@@ -0,0 +1,6 @@
+package kr.genti.domain.entity.response
+
+data class PromptExampleModel(
+ val url: String,
+ val prompt: String,
+)
\ No newline at end of file
diff --git a/domain/src/main/kotlin/kr/genti/domain/enums/CameraAngle.kt b/domain/src/main/kotlin/kr/genti/domain/enums/CameraAngle.kt
deleted file mode 100644
index 0fb02510..00000000
--- a/domain/src/main/kotlin/kr/genti/domain/enums/CameraAngle.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package kr.genti.domain.enums
-
-enum class CameraAngle(private val description: String) {
- ANY("앵글은 자유롭게 맡길래요"),
- HIGH("위에서 촬영"),
- MIDDLE("눈높이에서 촬영"),
- LOW("아래에서 촬영"),
- ;
-
- override fun toString(): String {
- return description
- }
-}
diff --git a/domain/src/main/kotlin/kr/genti/domain/enums/PictureNumber.kt b/domain/src/main/kotlin/kr/genti/domain/enums/PictureNumber.kt
new file mode 100644
index 00000000..b16d57eb
--- /dev/null
+++ b/domain/src/main/kotlin/kr/genti/domain/enums/PictureNumber.kt
@@ -0,0 +1,17 @@
+package kr.genti.domain.enums
+
+enum class PictureNumber {
+ ONE,
+ TWO,
+ ;
+
+ companion object {
+ fun String.toPictureNumber(): PictureNumber {
+ return if (this == "ONE") {
+ ONE
+ } else {
+ TWO
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/domain/src/main/kotlin/kr/genti/domain/enums/ShotCoverage.kt b/domain/src/main/kotlin/kr/genti/domain/enums/ShotCoverage.kt
deleted file mode 100644
index 14128e66..00000000
--- a/domain/src/main/kotlin/kr/genti/domain/enums/ShotCoverage.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package kr.genti.domain.enums
-
-enum class ShotCoverage(private val description: String) {
- ANY("프레임은 자유롭게 맡길래요"),
- UPPER_BODY("바스트샷\n(상반신)"),
- KNEE_SHOT("니샷\n(무릎 위)"),
- FULL_BODY("풀샷\n(전신)"),
- ;
-
- override fun toString(): String {
- return description
- }
-}
diff --git a/domain/src/main/kotlin/kr/genti/domain/repository/CreateRepository.kt b/domain/src/main/kotlin/kr/genti/domain/repository/CreateRepository.kt
index 9535244f..bab39b95 100644
--- a/domain/src/main/kotlin/kr/genti/domain/repository/CreateRepository.kt
+++ b/domain/src/main/kotlin/kr/genti/domain/repository/CreateRepository.kt
@@ -1,8 +1,10 @@
package kr.genti.domain.repository
import kr.genti.domain.entity.request.CreateRequestModel
+import kr.genti.domain.entity.request.CreateTwoRequestModel
import kr.genti.domain.entity.request.KeyRequestModel
import kr.genti.domain.entity.request.S3RequestModel
+import kr.genti.domain.entity.response.PromptExampleModel
import kr.genti.domain.entity.response.S3PresignedUrlModel
interface CreateRepository {
@@ -12,5 +14,11 @@ interface CreateRepository {
suspend fun postToCreate(request: CreateRequestModel): Result
+ suspend fun postToCreateOne(request: CreateRequestModel): Result
+
+ suspend fun postToCreateTwo(request: CreateTwoRequestModel): Result
+
suspend fun postToVerify(request: KeyRequestModel): Result
+
+ suspend fun getPromptExample(): Result>
}
diff --git a/domain/src/main/kotlin/kr/genti/domain/repository/GenerateRepository.kt b/domain/src/main/kotlin/kr/genti/domain/repository/GenerateRepository.kt
index 7a34143a..3ea3b1bf 100644
--- a/domain/src/main/kotlin/kr/genti/domain/repository/GenerateRepository.kt
+++ b/domain/src/main/kotlin/kr/genti/domain/repository/GenerateRepository.kt
@@ -32,4 +32,6 @@ interface GenerateRepository {
suspend fun getIsUserVerified(): Result
suspend fun getIsServerAvailable(): Result
+
+ suspend fun patchStatusInDevelop(): Result
}
diff --git a/domain/src/main/kotlin/kr/genti/domain/repository/UserRepository.kt b/domain/src/main/kotlin/kr/genti/domain/repository/UserRepository.kt
index e103fbaa..2868d969 100644
--- a/domain/src/main/kotlin/kr/genti/domain/repository/UserRepository.kt
+++ b/domain/src/main/kotlin/kr/genti/domain/repository/UserRepository.kt
@@ -7,10 +7,6 @@ interface UserRepository {
fun getUserRole(): String
- fun getIsGuideNeeded(): Boolean
-
- fun getIsChatAccessible(): Boolean
-
fun setTokens(
accessToken: String,
refreshToken: String,
@@ -18,9 +14,5 @@ interface UserRepository {
fun setUserRole(userRole: String)
- fun setIsGuideNeeded(isGuideNeeded: Boolean)
-
- fun setIsChatAccessible(isChatAccessible: Boolean)
-
fun clearInfo()
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 54596282..d09d4de3 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,24 +1,189 @@
[versions]
-agp = "8.3.0"
-kotlin = "1.9.0"
-coreKtx = "1.13.0"
+# Build Tools
+agp = "8.1.2"
+
+# Kotlin
+kotlin = "1.8.20"
+
+# AndroidX
+androidx-core-ktx = "1.13.1"
+androidx-core-splashscreen = "1.0.1"
+androidx-appcompat = "1.7.0"
+androidx-activity-ktx = "1.9.0"
+androidx-lifecycle-runtime-ktx = "2.8.7"
+androidx-navigation-ktx = "2.7.7"
+androidx-fragment-ktx = "1.5.7"
+androidx-legacy-support = "1.0.0"
+androidx-constraint-layout = "2.1.4"
+
+# Google
+material-design = "1.9.0"
+app-update = "2.1.0"
+google-services = "4.4.2"
+
+# Hilt
+hilt = "2.46.1"
+
+# Networking
+retrofit = "2.9.0"
+okhttp = "4.11.0"
+retrofit-serialization-converter = "1.0.0"
+
+# Kotlin Extensions
+kotlin-serialization = "1.5.1"
+kotlin-datetime = "0.4.0"
+kotlin-coroutines = "1.7.1"
+
+# UI Libraries
+coil = "2.4.0"
+glide = "4.12.0"
+glide-transformations = "4.3.0"
+lottie = "6.0.0"
+shimmer = "0.5.0"
+circular-progress-bar = "3.1.0"
+progress-view = "1.1.3"
+balloon = "1.4.5"
+circle-indicator = "2.1.6"
+
+# Amplitude
+amplitude = "1.17.3"
+
+# Firebase
+firebase-bom = "33.1.2"
+crashlytics = "2.9.9"
+
+# Kakao
+kakao = "2.20.3"
+
+# Testing
junit = "4.13.2"
-junitVersion = "1.1.5"
-espressoCore = "3.5.1"
-appcompat = "1.6.1"
-material = "1.11.0"
-navigationFragmentKtx = "2.7.7"
-navigationUiKtx = "2.7.7"
+espresso = "3.5.1"
+androidx-test = "1.1.5"
+
+# Timber
+timber = "5.0.1"
[libraries]
-androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
-junit = { group = "junit", name = "junit", version.ref = "junit" }
-androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
-androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
-androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
-material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+# Gradle Plugin
+android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" }
+kotlin-gradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
-[plugins]
-androidApplication = { id = "com.android.application", version.ref = "agp" }
-jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+# Kotlin
+kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
+kotlin-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlin-serialization" }
+kotlin-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlin-datetime" }
+kotlin-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlin-coroutines" }
+
+# AndroidX
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
+androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidx-core-splashscreen" }
+androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" }
+androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidx-activity-ktx" }
+androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "androidx-lifecycle-runtime-ktx" }
+androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "androidx-navigation-ktx" }
+androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "androidx-navigation-ktx" }
+androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidx-fragment-ktx" }
+androidx-legacy-support = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "androidx-legacy-support" }
+androidx-constraint-layout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraint-layout" }
+
+# MaterialDesign
+material-design = { group = "com.google.android.material", name = "material", version.ref = "material-design" }
+# Hilt
+hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
+hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
+
+# Networking
+retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
+retrofit-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofit-serialization-converter" }
+okhttp-bom = { group = "com.squareup.okhttp3", name = "okhttp-bom", version.ref = "okhttp" }
+okhttp = { group = "com.squareup.okhttp3", name = "okhttp" }
+okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor" }
+
+# UI Libraries
+coil = { group = "io.coil-kt", name = "coil", version.ref = "coil" }
+glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "glide" }
+glide-transformations = { group = "jp.wasabeef", name = "glide-transformations", version.ref = "glide-transformations" }
+lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "lottie" }
+shimmer = { group = "com.facebook.shimmer", name = "shimmer", version.ref = "shimmer" }
+circular-progress-bar = { group = "com.mikhaellopez", name = "circularprogressbar", version.ref = "circular-progress-bar" }
+progress-view = { group = "com.github.skydoves", name = "progressview", version.ref = "progress-view" }
+balloon = { group = "com.github.skydoves", name = "balloon", version.ref = "balloon" }
+circle-indicator = { group = "me.relex", name = "circleindicator", version.ref = "circle-indicator" }
+
+# Analytics
+amplitude = { group = "com.amplitude", name = "analytics-android", version.ref = "amplitude" }
+
+# Firebase
+firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebase-bom" }
+firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashlytics-ktx" }
+firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" }
+firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging-ktx" }
+
+# Kakao
+kakao = { group = "com.kakao.sdk", name = "v2-user", version.ref = "kakao" }
+
+# Testing
+j-unit = { group = "junit", name = "junit", version.ref = "junit" }
+j-unit-androidx-test = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
+
+# App Update
+app-update = { group = "com.google.android.play", name = "app-update-ktx", version.ref = "app-update" }
+
+# Timber
+timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" }
+
+[bundles]
+kotlin = [
+ "kotlin-stdlib",
+ "kotlin-serialization",
+ "kotlin-datetime",
+ "kotlin-coroutines",
+]
+
+androidx = [
+ "androidx-core-ktx",
+ "androidx-core-splashscreen",
+ "androidx-appcompat",
+ "androidx-activity-ktx",
+ "androidx-lifecycle-runtime-ktx",
+ "androidx-navigation-fragment-ktx",
+ "androidx-navigation-ui-ktx",
+ "androidx-fragment-ktx",
+ "androidx-legacy-support",
+ "androidx-constraint-layout"
+]
+
+networking = [
+ "retrofit",
+ "retrofit-serialization-converter",
+ "okhttp",
+ "okhttp-logging-interceptor"
+]
+
+ui = [
+ "coil",
+ "glide",
+ "glide-transformations",
+ "lottie",
+ "shimmer",
+ "circular-progress-bar",
+ "progress-view",
+ "balloon",
+ "circle-indicator"
+]
+
+firebase = [
+ "firebase-crashlytics",
+ "firebase-analytics",
+ "firebase-messaging"
+]
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
+hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
+google-services = { id = "com.google.gms.google-services", version.ref = "google-services" }
+google-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "crashlytics" }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index d7c014f1..43368ec1 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed May 01 02:58:14 KST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/presentation/build.gradle.kts b/presentation/build.gradle.kts
index 25ab42f3..29284339 100644
--- a/presentation/build.gradle.kts
+++ b/presentation/build.gradle.kts
@@ -1,102 +1,30 @@
plugins {
- id("com.android.library")
- kotlin("android")
- kotlin("kapt")
- id("kotlin-parcelize")
- id("dagger.hilt.android.plugin")
+ id("kr.genti.androidLibrary")
+ id("kr.genti.version")
}
android {
namespace = "kr.genti.presentation"
- compileSdk = Constants.compileSdk
defaultConfig {
- minSdk = Constants.minSdk
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
-
- buildConfigField("String", "VERSION_NAME", "\"${Constants.versionName}\"")
- buildConfigField("String", "VERSION_CODE", "\"${Constants.versionCode}\"")
- }
-
- compileOptions {
- sourceCompatibility = Versions.javaVersion
- targetCompatibility = Versions.javaVersion
- }
-
- kotlinOptions {
- jvmTarget = Versions.jvmVersion
- }
-
- buildFeatures {
- buildConfig = true
- dataBinding = true
- viewBinding = true
+ buildConfigField("String", "VERSION_NAME", "\"${extra["versionName"]}\"")
+ buildConfigField("String", "VERSION_CODE", "\"${extra["versionCode"]}\"")
}
}
dependencies {
- implementation(project(":core"))
- implementation(project(":domain"))
+ implementation(projects.core)
+ implementation(projects.domain)
- KotlinDependencies.run {
- implementation(kotlin)
- implementation(coroutines)
- implementation(jsonSerialization)
- implementation(dateTime)
- }
+ implementation(platform(libs.okhttp.bom))
+ implementation(libs.bundles.networking)
- AndroidXDependencies.run {
- implementation(coreKtx)
- implementation(appCompat)
- implementation(constraintLayout)
- implementation(fragment)
- implementation(navigationFragment)
- implementation(navigationUi)
- implementation(startup)
- implementation(legacy)
- implementation(security)
- implementation(lifeCycleKtx)
- implementation(lifecycleJava8)
- implementation(splashScreen)
- implementation(hilt)
- implementation(appUpdate)
- }
+ implementation(platform(libs.firebase.bom))
+ implementation(libs.bundles.firebase)
- KaptDependencies.run {
- kapt(hiltCompiler)
- }
-
- MaterialDesignDependencies.run {
- implementation(materialDesign)
- }
-
- TestDependencies.run {
- testImplementation(jUnit)
- androidTestImplementation(androidTest)
- androidTestImplementation(espresso)
- }
-
- ThirdPartyDependencies.run {
- implementation(coil)
- implementation(timber)
- implementation(amplitude)
- implementation(progressView)
- implementation(balloon)
- implementation(lottie)
- implementation(circularProgressBar)
- implementation(circleIndicator)
- }
-
- FirebaseDependencies.run {
- implementation(platform(firebaseBom))
- implementation(messaging)
- implementation(crashlytics)
- implementation(analytics)
- }
-
- KakaoDependencies.run {
- implementation(user)
- }
+ implementation(libs.bundles.androidx)
+ implementation(libs.bundles.ui)
+ implementation(libs.kakao)
+ implementation(libs.app.update)
+ implementation(libs.amplitude)
}
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/login/LoginActivity.kt b/presentation/src/main/java/kr/genti/presentation/auth/login/LoginActivity.kt
index 0d79d5cd..08494f9e 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/login/LoginActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/login/LoginActivity.kt
@@ -1,14 +1,12 @@
package kr.genti.presentation.auth.login
+import android.animation.ObjectAnimator
import android.app.Activity
import android.app.ActivityOptions
import android.content.Intent
+import android.graphics.Matrix
import android.os.Bundle
import androidx.activity.viewModels
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.updatePadding
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
@@ -16,7 +14,6 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseActivity
-import kr.genti.core.extension.colorOf
import kr.genti.core.extension.initOnBackPressedListener
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.stringOf
@@ -37,8 +34,7 @@ class LoginActivity : BaseActivity(R.layout.activity_login
initLoginBtnListener()
initOnBackPressedListener(binding.root)
- setStatusBarTransparent()
- setNavigationBarGreen()
+ setBackgroundAnimation()
observeAppLoginAvailable()
observeGetDeviceTokenResult()
observeChangeTokenState()
@@ -50,16 +46,29 @@ class LoginActivity : BaseActivity(R.layout.activity_login
}
}
- private fun setStatusBarTransparent() {
- WindowCompat.setDecorFitsSystemWindows(window, false)
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
- v.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom)
- insets
- }
- }
+ private fun setBackgroundAnimation() {
+ val imageView = binding.ivLoginBackground
+ imageView.post {
+ val matrix = Matrix()
+
+ val scale = imageView.height.toFloat() / imageView.drawable.intrinsicHeight.toFloat()
+ matrix.setScale(scale, scale)
+ val scaledWidth = imageView.drawable.intrinsicWidth.toFloat() * scale
- private fun setNavigationBarGreen() {
- this.window.navigationBarColor = colorOf(R.color.genti_green)
+ matrix.postTranslate(0f, 0f)
+ imageView.imageMatrix = matrix
+
+ val animator = ObjectAnimator.ofFloat(0f, imageView.width - scaledWidth).apply {
+ duration = 8000
+ addUpdateListener { animation ->
+ val translateX = animation.animatedValue as Float
+ matrix.setScale(scale, scale)
+ matrix.postTranslate(translateX, 0f)
+ imageView.imageMatrix = matrix
+ }
+ }
+ animator.start()
+ }
}
private fun observeAppLoginAvailable() {
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingActivity.kt b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingActivity.kt
index f1cebf9b..90d9ee93 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingActivity.kt
@@ -1,13 +1,12 @@
package kr.genti.presentation.auth.onboarding
-import android.animation.ValueAnimator
+import android.animation.ObjectAnimator
import android.content.Intent
import android.os.Bundle
import androidx.core.view.isVisible
-import androidx.core.view.updateLayoutParams
import dagger.hilt.android.AndroidEntryPoint
import kr.genti.core.base.BaseActivity
-import kr.genti.core.extension.dpToPx
+import kr.genti.core.extension.initOnBackPressedListener
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.presentation.R
import kr.genti.presentation.databinding.ActivityOnboardingBinding
@@ -20,12 +19,13 @@ import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
@AndroidEntryPoint
class OnboardingActivity : BaseActivity(R.layout.activity_onboarding) {
private var _onboardingAdapter: OnboardingAdapter? = null
- val onboardingAdapter
+ private val onboardingAdapter
get() = requireNotNull(_onboardingAdapter) { getString(R.string.adapter_not_initialized_error_msg) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ initOnBackPressedListener(binding.root)
initViewPager()
initNextBtnListener()
initFinishBtnListener()
@@ -47,26 +47,17 @@ class OnboardingActivity : BaseActivity(R.layout.acti
mapOf(PROPERTY_BTN to "next"),
)
with(binding) {
- btnNext.setOnSingleClickListener {
- vpOnboarding.currentItem = 1
- btnNext.isVisible = false
- btnFinish.isVisible = true
- tvOnboardingTitle.isVisible = false
- btnExit.isVisible = false
- startLogoAnimation()
- }
- }
- }
-
- private fun startLogoAnimation() {
- ValueAnimator.ofInt(60.dpToPx(this), 150.dpToPx(this)).apply {
- duration = 300
- addUpdateListener { animator ->
- binding.ivOnboardingLogo.updateLayoutParams {
- width = animator.animatedValue as Int
+ btnNext.setOnClickListener {
+ vpOnboarding.currentItem += 1
+ if (vpOnboarding.currentItem == 2) {
+ btnNext.isVisible = false
+ btnFinish.isVisible = true
+ ObjectAnimator.ofFloat(ivOnboardingThird, "alpha", 0f, 1f).apply {
+ duration = 1000
+ start()
+ }
}
}
- start()
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingAdapter.kt b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingAdapter.kt
index 99d4a12b..ed8dbf8a 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingAdapter.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingAdapter.kt
@@ -25,6 +25,6 @@ class OnboardingAdapter : RecyclerView.Adapter() {
override fun getItemCount(): Int = TOTAL_VIEW_COUNT
companion object {
- const val TOTAL_VIEW_COUNT = 2
+ const val TOTAL_VIEW_COUNT = 3
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingViewHolder.kt b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingViewHolder.kt
index fd66f379..8893b807 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingViewHolder.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/onboarding/OnboardingViewHolder.kt
@@ -1,7 +1,9 @@
package kr.genti.presentation.auth.onboarding
+import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
+import kr.genti.presentation.R
import kr.genti.presentation.databinding.ItemOnboardingBinding
class OnboardingViewHolder(
@@ -9,8 +11,17 @@ class OnboardingViewHolder(
) : RecyclerView.ViewHolder(binding.root) {
fun onBind(position: Int) {
with(binding) {
- layoutOnboardingFirst.isVisible = position == 0
- layoutOnboardingSecond.isVisible = position != 0
+ ivOnboardingFirst.isVisible = position == 0
+ ivOnboardingSecond.isVisible = position == 1
+ if (position == 1) {
+ tvOnboardingSubtitle.text = "얼굴 사진 3장만 골라요."
+ tvOnboardingBody.text = "사진 생성에 이용할 본인 사진 3장을 골라주세요."
+ }
+ if (position == 2) {
+ tvOnboardingSubtitle.text = "나만의 특별한 사진 완성!"
+ tvOnboardingBody.text = "지금 젠티하러 가볼까요?"
+ root.background = AppCompatResources.getDrawable(root.context, R.color.transparent)
+ }
}
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupActivity.kt b/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupActivity.kt
index 7406fa78..d2615b08 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupActivity.kt
@@ -3,10 +3,6 @@ package kr.genti.presentation.auth.signup
import android.content.Intent
import android.os.Bundle
import androidx.activity.viewModels
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.updatePadding
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint
@@ -14,7 +10,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseActivity
-import kr.genti.core.extension.colorOf
+import kr.genti.core.extension.hideKeyboard
import kr.genti.core.extension.initOnBackPressedListener
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.stringOf
@@ -25,7 +21,6 @@ import kr.genti.presentation.R
import kr.genti.presentation.auth.onboarding.OnboardingActivity
import kr.genti.presentation.databinding.ActivitySignupBinding
import kr.genti.presentation.util.AmplitudeManager
-import java.util.Calendar
@AndroidEntryPoint
class SignupActivity : BaseActivity(R.layout.activity_signup) {
@@ -36,10 +31,8 @@ class SignupActivity : BaseActivity(R.layout.activity_sig
initView()
initSubmitBtnListener()
- setYearPicker()
- setStatusBarTransparent()
- setNavigationBarGreen()
observePostSignupState()
+ observeYearInputState()
}
private fun initView() {
@@ -54,31 +47,6 @@ class SignupActivity : BaseActivity(R.layout.activity_sig
}
}
- private fun setYearPicker() {
- binding.npSignupBirth.apply {
- val currentYear = Calendar.getInstance()[Calendar.YEAR]
- maxValue = currentYear
- minValue = 1900
- value = currentYear
- viewModel.selectBirthYear(currentYear)
- setOnValueChangedListener { _, _, newVal ->
- viewModel.selectBirthYear(newVal)
- }
- }
- }
-
- private fun setStatusBarTransparent() {
- WindowCompat.setDecorFitsSystemWindows(window, false)
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
- v.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom)
- insets
- }
- }
-
- private fun setNavigationBarGreen() {
- this.window.navigationBarColor = colorOf(R.color.green_5)
- }
-
private fun observePostSignupState() {
viewModel.postSignupState
.flowWithLifecycle(lifecycle)
@@ -99,6 +67,15 @@ class SignupActivity : BaseActivity(R.layout.activity_sig
}.launchIn(lifecycleScope)
}
+ private fun observeYearInputState() {
+ viewModel.isYearAllSelected.flowWithLifecycle(lifecycle).distinctUntilChanged()
+ .onEach { isAllSelected ->
+ if (isAllSelected) {
+ hideKeyboard(binding.root)
+ }
+ }.launchIn(lifecycleScope)
+ }
+
private fun setAmplitudeUserProperty(state: UiState.Success) {
AmplitudeManager.apply {
trackEvent("complete_infoget")
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupViewModel.kt b/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupViewModel.kt
index 1083c479..364c0087 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupViewModel.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/signup/SignupViewModel.kt
@@ -17,62 +17,60 @@ import javax.inject.Inject
@HiltViewModel
class SignupViewModel
- @Inject
- constructor(
- private val infoRepository: InfoRepository,
- private val userRepository: UserRepository,
- ) : ViewModel() {
- val selectedGender = MutableLiveData(Gender.NONE)
- val isGenderSelected = MutableLiveData(false)
+@Inject
+constructor(
+ private val infoRepository: InfoRepository,
+ private val userRepository: UserRepository,
+) : ViewModel() {
+ val selectedGender = MutableLiveData(Gender.NONE)
+ private val isGenderSelected = MutableLiveData(false)
- val selectedYear = MutableLiveData()
- val selectedYearText = MutableLiveData()
- val isYearSelected = MutableLiveData(false)
+ val selectedYear = MutableLiveData()
+ val isYearSelected = MutableLiveData(false)
- val isAllSelected = MutableLiveData(false)
+ private val _isYearAllSelected = MutableStateFlow(false)
+ val isYearAllSelected: StateFlow = _isYearAllSelected
- private val _postSignupState = MutableStateFlow>(UiState.Empty)
- val postSignupState: StateFlow> = _postSignupState
+ val isAllSelected = MutableLiveData(false)
- fun selectGender(gender: Gender) {
- selectedGender.value = gender
- isGenderSelected.value = true
- checkAllSelected()
- }
+ private val _postSignupState = MutableStateFlow>(UiState.Empty)
+ val postSignupState: StateFlow> = _postSignupState
- fun selectBirthYear(year: Int) {
- selectedYear.value = year
- if (isYearSelected.value == true) selectedYearText.value = year.toString() + "년"
- }
+ fun selectGender(gender: Gender) {
+ selectedGender.value = gender
+ isGenderSelected.value = true
+ checkAllSelected()
+ }
- fun showYearPicker() {
- isYearSelected.value = true
- selectedYearText.value = selectedYear.value.toString() + "년"
- checkAllSelected()
- }
+ fun checkYear() {
+ isYearSelected.value = selectedYear.value?.isNotEmpty()
+ _isYearAllSelected.value = selectedYear.value?.length == 4 &&
+ selectedYear.value?.toIntOrNull()?.let { it in 1950..2025 } == true
+ checkAllSelected()
+ }
- private fun checkAllSelected() {
- isAllSelected.value = isGenderSelected.value == true && isYearSelected.value == true
- }
+ private fun checkAllSelected() {
+ isAllSelected.value = isGenderSelected.value == true && isYearAllSelected.value == true
+ }
- fun postSignupDataToServer() {
- _postSignupState.value = UiState.Loading
- viewModelScope.launch {
- infoRepository.postSignupData(
- SignupRequestModel(
- selectedYear.value.toString(),
- selectedGender.value.toString(),
- ),
- ).onSuccess {
- userRepository.setUserRole(ROLE_USER)
- _postSignupState.value = UiState.Success(it)
- }.onFailure {
- _postSignupState.value = UiState.Failure(it.message.orEmpty())
- }
+ fun postSignupDataToServer() {
+ _postSignupState.value = UiState.Loading
+ viewModelScope.launch {
+ infoRepository.postSignupData(
+ SignupRequestModel(
+ selectedYear.value.toString(),
+ selectedGender.value.toString(),
+ ),
+ ).onSuccess {
+ userRepository.setUserRole(ROLE_USER)
+ _postSignupState.value = UiState.Success(it)
+ }.onFailure {
+ _postSignupState.value = UiState.Failure(it.message.orEmpty())
}
}
+ }
- companion object {
- private const val ROLE_USER = "USER"
- }
+ companion object {
+ private const val ROLE_USER = "USER"
}
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/auth/splash/SplashActivity.kt b/presentation/src/main/java/kr/genti/presentation/auth/splash/SplashActivity.kt
index ebb23508..d47529e2 100644
--- a/presentation/src/main/java/kr/genti/presentation/auth/splash/SplashActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/auth/splash/SplashActivity.kt
@@ -20,7 +20,6 @@ import com.google.android.play.core.appupdate.AppUpdateOptions
import com.google.android.play.core.install.model.AppUpdateType.IMMEDIATE
import com.google.android.play.core.install.model.UpdateAvailability.UPDATE_AVAILABLE
import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseActivity
@@ -47,11 +46,16 @@ class SplashActivity : BaseActivity(R.layout.activity_spl
super.onCreate(savedInstanceState)
setSystemWindowsTransparent()
- checkAppUpdateAvailable()
observeAutoLoginState()
observeReissueTokenResult()
}
+ override fun onResume() {
+ super.onResume()
+
+ checkAppUpdateAvailable()
+ }
+
private fun setSystemWindowsTransparent() {
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).apply {
@@ -79,7 +83,7 @@ class SplashActivity : BaseActivity(R.layout.activity_spl
private fun isAppUpdateNeeded(appUpdateInfo: AppUpdateInfo) =
appUpdateInfo.updateAvailability() == UPDATE_AVAILABLE &&
- appUpdateInfo.isUpdateTypeAllowed(IMMEDIATE)
+ appUpdateInfo.isUpdateTypeAllowed(IMMEDIATE)
private fun requestUpdate(appUpdateInfo: AppUpdateInfo) {
runCatching {
@@ -92,25 +96,23 @@ class SplashActivity : BaseActivity(R.layout.activity_spl
}
private fun observeAutoLoginState() {
- viewModel.isAutoLogined.flowWithLifecycle(lifecycle).distinctUntilChanged()
- .onEach { isAutoLogined ->
- if (isAutoLogined) {
- viewModel.postToReissueToken()
- } else {
- navigateTo()
- }
- }.launchIn(lifecycleScope)
+ viewModel.isAutoLogined.flowWithLifecycle(lifecycle).onEach { isAutoLogined ->
+ if (isAutoLogined) {
+ viewModel.postToReissueToken()
+ } else {
+ navigateTo()
+ }
+ }.launchIn(lifecycleScope)
}
private fun observeReissueTokenResult() {
- viewModel.reissueTokenResult.flowWithLifecycle(lifecycle).distinctUntilChanged()
- .onEach { isSuccess ->
- if (isSuccess) {
- navigateTo()
- } else {
- navigateTo()
- }
- }.launchIn(lifecycleScope)
+ viewModel.reissueTokenResult.flowWithLifecycle(lifecycle).onEach { isSuccess ->
+ if (isSuccess) {
+ navigateTo()
+ } else {
+ navigateTo()
+ }
+ }.launchIn(lifecycleScope)
}
private inline fun navigateTo() {
diff --git a/presentation/src/main/java/kr/genti/presentation/create/CreateActivity.kt b/presentation/src/main/java/kr/genti/presentation/create/CreateActivity.kt
new file mode 100644
index 00000000..8d53b305
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/CreateActivity.kt
@@ -0,0 +1,120 @@
+package kr.genti.presentation.create
+
+import android.animation.ObjectAnimator
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.animation.LinearInterpolator
+import androidx.activity.OnBackPressedCallback
+import androidx.activity.viewModels
+import androidx.core.view.isVisible
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.NavController
+import androidx.navigation.fragment.NavHostFragment
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kr.genti.core.base.BaseActivity
+import kr.genti.core.state.UiState
+import kr.genti.presentation.R
+import kr.genti.presentation.databinding.ActivityCreateBinding
+import kr.genti.presentation.util.AmplitudeManager
+import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
+
+@AndroidEntryPoint
+class CreateActivity() : BaseActivity(R.layout.activity_create) {
+ private val viewModel by viewModels()
+ private lateinit var navController: NavController
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ initView()
+ initBackBtnListener()
+ setParentPicWithIntent()
+ observeProgressBar()
+ observeGeneratingState()
+ }
+
+ private fun initView() {
+ navController = binding.fcvCreate.getFragment().navController
+ }
+
+ private fun initBackBtnListener() {
+ binding.btnBack.setOnClickListener {
+ when (navController.currentDestination?.id) {
+ R.id.numberFragment -> finish()
+ R.id.defineFragment -> {
+ if (viewModel.isCreatingParentPic) {
+ navigateBackFragment("create1", -33)
+ } else {
+ finish()
+ }
+ }
+
+ R.id.poseFragment -> navigateBackFragment("create2", -33)
+ R.id.selfieFragment -> navigateBackFragment("create3", -34)
+ }
+ }
+ }
+
+ private fun navigateBackFragment(tag: String, amount: Int) {
+ AmplitudeManager.trackEvent(
+ EVENT_CLICK_BTN,
+ mapOf(PROPERTY_PAGE to tag),
+ mapOf(PROPERTY_BTN to "back"),
+ )
+ navController.popBackStack()
+ viewModel.modCurrentPercent(amount)
+ }
+
+ private fun setParentPicWithIntent() {
+ viewModel.isCreatingParentPic = intent.getBooleanExtra(EXTRA_IS_CREATING_PARENT_PIC, false)
+ if (viewModel.isCreatingParentPic) {
+ binding.tvCreateTitle.text = getString(R.string.create_parent_tv_title)
+ } else {
+ navController.navigate(R.id.action_number_to_define_without_anim)
+ viewModel.modCurrentPercent(33)
+ }
+ }
+
+ private fun observeProgressBar() {
+ viewModel.currentPercent.flowWithLifecycle(lifecycle).onEach { percent ->
+ ObjectAnimator.ofInt(
+ binding.progressbarCreate,
+ PROPERTY_PROGRESS,
+ binding.progressbarCreate.progress,
+ percent,
+ ).apply {
+ duration = 300
+ interpolator = LinearInterpolator()
+ start()
+ }
+ binding.tvCreatePhase.text = getString(R.string.create_phase_text, percent / 33)
+ }.launchIn(lifecycleScope)
+ }
+
+ private fun observeGeneratingState() {
+ viewModel.totalGeneratingState.flowWithLifecycle(lifecycle).onEach { state ->
+ binding.layoutLoading.isVisible = state == UiState.Loading
+ }.launchIn(lifecycleScope)
+ }
+
+ companion object {
+ const val PROPERTY_PROGRESS = "progress"
+
+ private const val EXTRA_IS_CREATING_PARENT_PIC = "EXTRA_IS_CREATING_PARENT_PIC"
+
+ @JvmStatic
+ fun createIntent(
+ context: Context,
+ isCreatingParentPic: Boolean,
+ ): Intent =
+ Intent(context, CreateActivity::class.java).apply {
+ putExtra(EXTRA_IS_CREATING_PARENT_PIC, isCreatingParentPic)
+ }
+ }
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/create/CreateViewModel.kt b/presentation/src/main/java/kr/genti/presentation/create/CreateViewModel.kt
new file mode 100644
index 00000000..d0bb1674
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/CreateViewModel.kt
@@ -0,0 +1,237 @@
+package kr.genti.presentation.create
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitAll
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import kr.genti.core.state.UiState
+import kr.genti.domain.entity.request.CreateRequestModel
+import kr.genti.domain.entity.request.CreateTwoRequestModel
+import kr.genti.domain.entity.request.KeyRequestModel
+import kr.genti.domain.entity.request.S3RequestModel
+import kr.genti.domain.entity.response.ImageFileModel
+import kr.genti.domain.entity.response.PromptExampleModel
+import kr.genti.domain.entity.response.S3PresignedUrlModel
+import kr.genti.domain.enums.FileType
+import kr.genti.domain.enums.PictureNumber
+import kr.genti.domain.enums.PictureRatio
+import kr.genti.domain.repository.CreateRepository
+import kr.genti.domain.repository.UploadRepository
+import javax.inject.Inject
+
+@HiltViewModel
+class CreateViewModel
+@Inject
+constructor(
+ private val createRepository: CreateRepository,
+ private val uploadRepository: UploadRepository,
+) : ViewModel() {
+ var isCreatingParentPic = false
+
+ val prompt = MutableLiveData()
+ val isWritten = MutableLiveData(false)
+
+ val selectedNumber = MutableLiveData()
+ val isNumberSelected = MutableLiveData(false)
+
+ val selectedRatio = MutableLiveData()
+ val isRatioSelected = MutableLiveData(false)
+
+ var currentAddingList = 0
+ var imageList = listOf()
+ var firstImageList = listOf()
+ var secondImageList = listOf()
+
+ var isFirstListCompleted = MutableLiveData(false)
+ var isSecondListCompleted = MutableLiveData(false)
+ var isCompleted = MutableLiveData(false)
+
+ private val _currentPercent = MutableStateFlow(0)
+ val currentPercent: StateFlow = _currentPercent
+
+ private val _getExampleState =
+ MutableStateFlow>>(UiState.Empty)
+ val getExampleState: StateFlow>> = _getExampleState
+
+ private val _totalGeneratingState = MutableStateFlow>(UiState.Empty)
+ val totalGeneratingState: StateFlow> = _totalGeneratingState
+
+ private var imageS3KeyList = listOf()
+ private var firstImageS3KeyList = listOf()
+ private var secondImageS3KeyList = listOf()
+
+ init {
+ getExamplePrompt()
+ }
+
+ fun modCurrentPercent(amount: Int) {
+ _currentPercent.value += amount
+ }
+
+ fun checkWritten() {
+ isWritten.value = prompt.value?.isNotEmpty()
+ }
+
+ fun selectNumber(item: PictureNumber) {
+ selectedNumber.value = item
+ isNumberSelected.value = selectedNumber.value != null
+ }
+
+ fun selectRatio(item: PictureRatio) {
+ selectedRatio.value = item
+ isRatioSelected.value = selectedRatio.value != null
+ }
+
+ fun updateCompletionState(uriSize: Int) {
+ when (currentAddingList) {
+ 0 -> isCompleted.value = uriSize == 3
+ 1 -> {
+ isFirstListCompleted.value = uriSize == 3
+ isCompleted.value =
+ isFirstListCompleted.value == true && isSecondListCompleted.value == true
+ }
+
+ 2 -> {
+ isSecondListCompleted.value = uriSize == 3
+ isCompleted.value =
+ isFirstListCompleted.value == true && isSecondListCompleted.value == true
+ }
+ }
+ }
+
+ fun resetTotalGeneratingState() {
+ _totalGeneratingState.value = UiState.Empty
+ }
+
+ private fun getExamplePrompt() {
+ _getExampleState.value = UiState.Loading
+ viewModelScope.launch {
+ runCatching {
+ createRepository.getPromptExample()
+ }.onSuccess {
+ _getExampleState.value = UiState.Success(it.getOrThrow())
+ }.onFailure {
+ _getExampleState.value = UiState.Failure(it.message.toString())
+ }
+ }
+ }
+
+ fun startSendingImages() {
+ _totalGeneratingState.value = UiState.Loading
+ if (selectedNumber.value != PictureNumber.TWO) {
+ saveThreeImages()
+ } else {
+ saveSixImages()
+ }
+ }
+
+ private fun saveThreeImages() {
+ viewModelScope.launch {
+ runCatching {
+ coroutineScope {
+ val urlModelList = getThreeS3Urls(imageList)
+ postThreeImage(urlModelList, imageList)
+ urlModelList.map { KeyRequestModel(it.s3Key) }
+ }
+ }.onSuccess { keyList ->
+ imageS3KeyList = keyList
+ postThreeToGenerateImage()
+ }.onFailure {
+ _totalGeneratingState.value = UiState.Failure(it.message.toString())
+ }
+ }
+ }
+
+ private fun saveSixImages() {
+ viewModelScope.launch {
+ runCatching {
+ coroutineScope {
+ val firstResult = async {
+ val urlModelList = getThreeS3Urls(firstImageList)
+ postThreeImage(urlModelList, firstImageList)
+ urlModelList.map { KeyRequestModel(it.s3Key) }
+ }
+ val secondResult = async {
+ val urlModelList = getThreeS3Urls(secondImageList)
+ postThreeImage(urlModelList, secondImageList)
+ urlModelList.map { KeyRequestModel(it.s3Key) }
+ }
+ firstImageS3KeyList = firstResult.await()
+ secondImageS3KeyList = secondResult.await()
+ }
+ }.onSuccess {
+ postSixToGenerateImage()
+ }.onFailure {
+ _totalGeneratingState.value = UiState.Failure(it.message.toString())
+ }
+ }
+ }
+
+ private suspend fun getThreeS3Urls(imageList: List): List {
+ return createRepository.getS3MultiUrl(
+ imageList.map { image ->
+ S3RequestModel(FileType.USER_UPLOADED_IMAGE, image.name)
+ }
+ ).getOrThrow()
+ }
+
+ private suspend fun postThreeImage(
+ urlModelList: List,
+ imageList: List
+ ) {
+ coroutineScope {
+ urlModelList.mapIndexed { i, urlModel ->
+ async {
+ runCatching {
+ uploadRepository.uploadImage(urlModel.url, imageList[i].url)
+ }.onFailure {
+ throw Exception(it.message)
+ }
+ }
+ }.awaitAll()
+ }
+ }
+
+ private fun postThreeToGenerateImage() {
+ viewModelScope.launch {
+ val request = CreateRequestModel(
+ prompt.value ?: return@launch,
+ imageS3KeyList,
+ selectedRatio.value ?: return@launch,
+ )
+ val result = if (isCreatingParentPic) {
+ createRepository.postToCreateOne(request)
+ } else {
+ createRepository.postToCreate(request)
+ }
+ result.onSuccess {
+ _totalGeneratingState.value = UiState.Success(it)
+ }.onFailure {
+ _totalGeneratingState.value = UiState.Failure(it.message.toString())
+ }
+ }
+ }
+
+ private fun postSixToGenerateImage() {
+ viewModelScope.launch {
+ createRepository.postToCreateTwo(
+ CreateTwoRequestModel(
+ prompt.value ?: return@launch,
+ firstImageS3KeyList,
+ secondImageS3KeyList,
+ selectedRatio.value ?: return@launch,
+ )
+ ).onSuccess {
+ _totalGeneratingState.value = UiState.Success(isCreatingParentPic)
+ }.onFailure {
+ _totalGeneratingState.value = UiState.Failure(it.message.toString())
+ }
+ }
+ }
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/create/DefineAdapter.kt b/presentation/src/main/java/kr/genti/presentation/create/DefineAdapter.kt
new file mode 100644
index 00000000..7e0edd78
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/DefineAdapter.kt
@@ -0,0 +1,37 @@
+package kr.genti.presentation.create
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import androidx.recyclerview.widget.ListAdapter
+import kr.genti.core.util.ItemDiffCallback
+import kr.genti.domain.entity.response.PromptExampleModel
+import kr.genti.presentation.databinding.ItemDefineExampleBinding
+
+class DefineAdapter : ListAdapter(diffUtil) {
+
+ override fun onCreateViewHolder(
+ parent: ViewGroup,
+ viewType: Int,
+ ): DefineViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ val binding = ItemDefineExampleBinding.inflate(inflater, parent, false)
+ return DefineViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(
+ holder: DefineViewHolder,
+ position: Int,
+ ) {
+ val item = getItem(position) ?: return
+ holder.onBind(item)
+ }
+
+ companion object {
+
+ private val diffUtil =
+ ItemDiffCallback(
+ onItemsTheSame = { old, new -> old.prompt == new.prompt },
+ onContentsTheSame = { old, new -> old == new },
+ )
+ }
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/kr/genti/presentation/create/DefineFragment.kt b/presentation/src/main/java/kr/genti/presentation/create/DefineFragment.kt
new file mode 100644
index 00000000..511c5bd1
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/DefineFragment.kt
@@ -0,0 +1,135 @@
+package kr.genti.presentation.create
+
+import android.os.Bundle
+import android.view.View
+import androidx.activity.OnBackPressedCallback
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.flowWithLifecycle
+import androidx.lifecycle.lifecycleScope
+import androidx.navigation.fragment.findNavController
+import androidx.viewpager2.widget.ViewPager2
+import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kr.genti.core.base.BaseFragment
+import kr.genti.core.extension.setOnSingleClickListener
+import kr.genti.core.extension.setTextWithImage
+import kr.genti.core.extension.stringOf
+import kr.genti.core.extension.toast
+import kr.genti.core.state.UiState
+import kr.genti.presentation.R
+import kr.genti.presentation.databinding.FragmentDefineBinding
+import kr.genti.presentation.util.AmplitudeManager
+import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
+
+@AndroidEntryPoint
+class DefineFragment() : BaseFragment(R.layout.fragment_define) {
+ private val viewModel by activityViewModels()
+
+ private var _adapter: DefineAdapter? = null
+ private val adapter
+ get() = requireNotNull(_adapter) { getString(R.string.adapter_not_initialized_error_msg) }
+
+ override fun onViewCreated(
+ view: View,
+ savedInstanceState: Bundle?,
+ ) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initView()
+ initCreateBtnListener()
+ initBackPressedListener()
+ initViewPager()
+ setTextByParent()
+ observeGetExampleState()
+ }
+
+ private fun initView() {
+ binding.vm = viewModel
+ }
+
+ private fun initCreateBtnListener() {
+ binding.btnCreateNext.setOnSingleClickListener {
+ AmplitudeManager.trackEvent(
+ EVENT_CLICK_BTN,
+ mapOf(PROPERTY_PAGE to "create1"),
+ mapOf(PROPERTY_BTN to "next"),
+ )
+ findNavController().navigate(R.id.action_define_to_pose)
+ viewModel.modCurrentPercent(33)
+ }
+ }
+
+ private fun initBackPressedListener() {
+ requireActivity().onBackPressedDispatcher.addCallback(
+ viewLifecycleOwner,
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ if (viewModel.isCreatingParentPic) {
+ viewModel.modCurrentPercent(-33)
+ findNavController().popBackStack()
+ } else {
+ requireActivity().finish()
+ }
+ }
+ })
+ }
+
+ private fun initViewPager() {
+ _adapter = DefineAdapter()
+ with(binding) {
+ vpCreateRandom.adapter = adapter
+ vpCreateRandom.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ AmplitudeManager.apply {
+ trackEvent(
+ EVENT_CLICK_BTN,
+ mapOf(PROPERTY_PAGE to "create1"),
+ mapOf(PROPERTY_BTN to "promptsuggest_refresh"),
+ )
+ plusIntProperties("user_promptsuggest_refresh")
+ }
+ }
+ })
+ }
+ }
+
+ private fun setTextByParent() {
+ with(binding) {
+ val (titleRes, subtitle2Res) = if (viewModel.isCreatingParentPic) {
+ R.string.create_tv_script_title_parent to R.string.create_tv_script_subtitle_2_parent
+ } else {
+ R.string.create_tv_script_title to R.string.create_tv_script_subtitle_2
+ }
+ tvCreateScriptTitle.text = stringOf(titleRes)
+ tvCreateScriptSubtitle1.setTextWithImage(
+ stringOf(R.string.create_tv_script_subtitle_1),
+ R.drawable.ic_check,
+ )
+ tvCreateScriptSubtitle2.setTextWithImage(
+ stringOf(subtitle2Res),
+ R.drawable.ic_check,
+ )
+ }
+ }
+
+ private fun observeGetExampleState() {
+ viewModel.getExampleState
+ .flowWithLifecycle(lifecycle)
+ .onEach { state ->
+ when (state) {
+ is UiState.Success -> {
+ adapter.submitList(state.data)
+ binding.dotIndicator.setViewPager(binding.vpCreateRandom)
+ }
+
+ is UiState.Failure -> toast(stringOf(R.string.error_msg))
+ else -> return@onEach
+ }
+ }.launchIn(lifecycleScope)
+ }
+
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/create/DefineViewHolder.kt b/presentation/src/main/java/kr/genti/presentation/create/DefineViewHolder.kt
new file mode 100644
index 00000000..bcbb726d
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/DefineViewHolder.kt
@@ -0,0 +1,18 @@
+package kr.genti.presentation.create
+
+import androidx.recyclerview.widget.RecyclerView
+import coil.load
+import kr.genti.core.extension.breakLines
+import kr.genti.domain.entity.response.PromptExampleModel
+import kr.genti.presentation.databinding.ItemDefineExampleBinding
+
+class DefineViewHolder(
+ val binding: ItemDefineExampleBinding,
+) : RecyclerView.ViewHolder(binding.root) {
+ fun onBind(item: PromptExampleModel) {
+ with(binding) {
+ ivDefineExample.load(item.url)
+ tvDefineExample.text = item.prompt.breakLines()
+ }
+ }
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/create/NumberFragment.kt b/presentation/src/main/java/kr/genti/presentation/create/NumberFragment.kt
new file mode 100644
index 00000000..a91c6c56
--- /dev/null
+++ b/presentation/src/main/java/kr/genti/presentation/create/NumberFragment.kt
@@ -0,0 +1,45 @@
+package kr.genti.presentation.create
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.activityViewModels
+import androidx.navigation.fragment.findNavController
+import kr.genti.core.base.BaseFragment
+import kr.genti.core.extension.setOnSingleClickListener
+import kr.genti.presentation.R
+import kr.genti.presentation.databinding.FragmentNumberBinding
+import kr.genti.presentation.util.AmplitudeManager
+import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
+import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
+
+class NumberFragment() : BaseFragment(R.layout.fragment_number) {
+ private val viewModel by activityViewModels()
+
+
+ override fun onViewCreated(
+ view: View,
+ savedInstanceState: Bundle?,
+ ) {
+ super.onViewCreated(view, savedInstanceState)
+
+ initView()
+ initNextBtnListener()
+ }
+
+ private fun initView() {
+ binding.vm = viewModel
+ }
+
+ private fun initNextBtnListener() {
+ binding.btnNumberNext.setOnSingleClickListener {
+ AmplitudeManager.trackEvent(
+ EVENT_CLICK_BTN,
+ mapOf(PROPERTY_PAGE to "create0"),
+ mapOf(PROPERTY_BTN to "next"),
+ )
+ findNavController().navigate(R.id.action_number_to_define)
+ viewModel.modCurrentPercent(33)
+ }
+ }
+}
\ No newline at end of file
diff --git a/presentation/src/main/java/kr/genti/presentation/main/create/PoseFragment.kt b/presentation/src/main/java/kr/genti/presentation/create/PoseFragment.kt
similarity index 62%
rename from presentation/src/main/java/kr/genti/presentation/main/create/PoseFragment.kt
rename to presentation/src/main/java/kr/genti/presentation/create/PoseFragment.kt
index db44b9f7..26edd36e 100644
--- a/presentation/src/main/java/kr/genti/presentation/main/create/PoseFragment.kt
+++ b/presentation/src/main/java/kr/genti/presentation/create/PoseFragment.kt
@@ -1,4 +1,4 @@
-package kr.genti.presentation.main.create
+package kr.genti.presentation.create
import android.os.Bundle
import android.view.View
@@ -19,8 +19,6 @@ import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
class PoseFragment() : BaseFragment(R.layout.fragment_pose) {
private val viewModel by activityViewModels()
- private var createGuideDialog: CreateGuideDialog? = null
-
override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
@@ -30,7 +28,6 @@ class PoseFragment() : BaseFragment(R.layout.fragment_pose)
initView()
initNextBtnListener()
initBackPressedListener()
- initGuideIfNeeded()
}
private fun initView() {
@@ -50,38 +47,13 @@ class PoseFragment() : BaseFragment(R.layout.fragment_pose)
}
private fun initBackPressedListener() {
- val onBackPressedCallback =
+ requireActivity().onBackPressedDispatcher.addCallback(
+ viewLifecycleOwner,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
- if (isAdded) {
- findNavController().popBackStack()
- viewModel.modCurrentPercent(-33)
- } else {
- requireActivity().onBackPressedDispatcher.onBackPressed()
- }
+ viewModel.modCurrentPercent(-33)
+ findNavController().popBackStack()
}
- }
- activity?.onBackPressedDispatcher?.addCallback(
- requireActivity(),
- onBackPressedCallback,
- )
- }
-
- private fun initGuideIfNeeded() {
- if (viewModel.getIsGuideNeeded()) {
- createGuideDialog = CreateGuideDialog()
- createGuideDialog?.show(childFragmentManager, DIALOG_GUIDE)
- viewModel.setIsGuideNeeded(false)
- }
- }
-
- override fun onDestroyView() {
- super.onDestroyView()
-
- createGuideDialog = null
- }
-
- companion object {
- const val DIALOG_GUIDE = "DIALOG_GUIDE"
+ })
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/main/create/SelfieFragment.kt b/presentation/src/main/java/kr/genti/presentation/create/SelfieFragment.kt
similarity index 51%
rename from presentation/src/main/java/kr/genti/presentation/main/create/SelfieFragment.kt
rename to presentation/src/main/java/kr/genti/presentation/create/SelfieFragment.kt
index 362ed08b..66905dcf 100644
--- a/presentation/src/main/java/kr/genti/presentation/main/create/SelfieFragment.kt
+++ b/presentation/src/main/java/kr/genti/presentation/create/SelfieFragment.kt
@@ -1,15 +1,13 @@
-package kr.genti.presentation.main.create
+package kr.genti.presentation.create
import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.net.Uri
+import android.os.Build
import android.os.Bundle
-import android.text.SpannableString
-import android.text.SpannableStringBuilder
-import android.text.Spanned
-import android.text.style.BulletSpan
import android.view.View
+import android.widget.ImageView
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.PickVisualMediaRequest
@@ -27,27 +25,26 @@ import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseFragment
import kr.genti.core.extension.getFileName
import kr.genti.core.extension.setOnSingleClickListener
+import kr.genti.core.extension.setTextWithImage
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.core.state.UiState
import kr.genti.domain.entity.response.ImageFileModel
+import kr.genti.domain.enums.PictureNumber
import kr.genti.presentation.R
import kr.genti.presentation.databinding.FragmentSelfieBinding
import kr.genti.presentation.generate.waiting.WaitingActivity
-import kr.genti.presentation.main.MainActivity
-import kr.genti.presentation.main.feed.FeedFragment
import kr.genti.presentation.util.AmplitudeManager
import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
-import kotlin.math.max
@AndroidEntryPoint
class SelfieFragment : BaseFragment(R.layout.fragment_selfie) {
private val viewModel by activityViewModels()
+
private lateinit var photoPickerResult: ActivityResultLauncher
private lateinit var galleryPickerResult: ActivityResultLauncher
- private lateinit var waitingResult: ActivityResultLauncher
override fun onViewCreated(
view: View,
@@ -59,11 +56,10 @@ class SelfieFragment : BaseFragment(R.layout.fragment_sel
initBackPressedListener()
initAddImageBtnListener()
initRequestCreateBtnListener()
+ setGuideTextByParent()
+ setLayoutByParent()
setGalleryImageWithPhotoPicker()
setGalleryImageWithGalleryPicker()
- setBulletPointList()
- setGuideListBlur()
- initWaitingResult()
observeGeneratingState()
}
@@ -78,19 +74,14 @@ class SelfieFragment : BaseFragment(R.layout.fragment_sel
}
private fun initBackPressedListener() {
- val onBackPressedCallback =
+ requireActivity().onBackPressedDispatcher.addCallback(
+ viewLifecycleOwner,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
- if (isAdded) {
- findNavController().popBackStack()
- viewModel.modCurrentPercent(-34)
- }
+ viewModel.modCurrentPercent(-34)
+ findNavController().popBackStack()
}
- }
- activity?.onBackPressedDispatcher?.addCallback(
- requireActivity(),
- onBackPressedCallback,
- )
+ })
}
private fun initAddImageBtnListener() {
@@ -101,21 +92,15 @@ class SelfieFragment : BaseFragment(R.layout.fragment_sel
mapOf(PROPERTY_PAGE to "create3"),
mapOf(PROPERTY_BTN to "selectpic"),
)
- checkAndGetImages()
- }
- layoutAddedImage.setOnSingleClickListener {
- AmplitudeManager.trackEvent(
- EVENT_CLICK_BTN,
- mapOf(PROPERTY_PAGE to "create3"),
- mapOf(PROPERTY_BTN to "reselectpic"),
- )
- checkAndGetImages()
+ checkAndGetImages(0)
}
+ btnSelfieAddFirst.setOnSingleClickListener { checkAndGetImages(1) }
+ btnSelfieAddSecond.setOnSingleClickListener { checkAndGetImages(2) }
}
}
private fun initRequestCreateBtnListener() {
- binding.btnSelfieNext.setOnSingleClickListener {
+ binding.btnCreate.setOnSingleClickListener {
AmplitudeManager.trackEvent(
EVENT_CLICK_BTN,
mapOf(PROPERTY_PAGE to "create3"),
@@ -128,8 +113,52 @@ class SelfieFragment : BaseFragment(R.layout.fragment_sel
}
}
- private fun checkAndGetImages() {
- if (isPhotoPickerAvailable(requireContext())) {
+ private fun setGuideTextByParent() {
+ with(binding) {
+ tvSelfieGuide1.setTextWithImage(
+ stringOf(R.string.selfie_tv_guide_1),
+ R.drawable.ic_check,
+ )
+ if (viewModel.isCreatingParentPic) {
+ tvSelfieGuide2.setTextWithImage(
+ stringOf(R.string.selfie_tv_guide_parent),
+ R.drawable.ic_check,
+ )
+ tvSelfieGuide3.isVisible = false
+ tvSelfieWarning.isVisible = false
+ } else {
+ tvSelfieGuide2.setTextWithImage(
+ stringOf(R.string.selfie_tv_guide_2),
+ R.drawable.ic_check,
+ )
+ tvSelfieGuide3.isVisible = true
+ tvSelfieWarning.isVisible = true
+ tvSelfieGuide3.setTextWithImage(
+ stringOf(R.string.selfie_tv_guide_3),
+ R.drawable.ic_check,
+ )
+ }
+ }
+ }
+
+ private fun setLayoutByParent() {
+ with(binding) {
+ if (viewModel.isCreatingParentPic) {
+ if (viewModel.selectedNumber.value == PictureNumber.ONE) {
+ tvSelfieTitle.text = stringOf(R.string.selfie_tv_title_parent_one)
+ } else {
+ tvSelfieTitle.text = stringOf(R.string.selfie_tv_title_parent_two)
+ layoutExampleImage.isVisible = false
+ layoutTwoParent.isVisible = true
+ btnSelfieAdd.visibility = View.INVISIBLE
+ }
+ }
+ }
+ }
+
+ private fun checkAndGetImages(currentAddingList: Int) {
+ viewModel.currentAddingList = currentAddingList
+ if (isPhotoPickerAvailable(requireContext()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
photoPickerResult.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
} else {
galleryPickerResult.launch(
@@ -172,110 +201,69 @@ class SelfieFragment : BaseFragment(R.layout.fragment_sel
private fun setImageListWithUri(uris: List) {
with(viewModel) {
- imageList =
- uris.mapIndexed { _, uri ->
- ImageFileModel(
- uri.hashCode().toLong(),
- uri.getFileName(requireActivity().contentResolver).toString(),
- uri.toString(),
- )
- }
- isCompleted.value = uris.size == 3
- }
- with(binding) {
- listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3).apply {
- forEach { it.setImageDrawable(null) }
- uris.take(size).forEachIndexed { index, uri ->
- this[index].load(uri)
- }
- }
- }
- binding.layoutAddedImage.isVisible = uris.isNotEmpty()
- }
-
- private fun setSavedImages() {
- if (viewModel.imageList.isNotEmpty()) {
- val imageViews =
- with(binding) { listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3) }
- imageViews.forEach { it.setImageDrawable(null) }
- viewModel.imageList
- .take(3)
- .forEachIndexed { index, imageFile -> imageViews[index].load(imageFile.url) }
- binding.layoutAddedImage.isVisible = true
+ val listMap = mapOf(
+ 0 to ::imageList,
+ 1 to ::firstImageList,
+ 2 to ::secondImageList
+ )
+ listMap[currentAddingList]?.set(uris.map { uri ->
+ uri.toImageFileModel()
+ })
+ updateCompletionState(uris.size)
}
+ setSavedImages()
}
- private fun setBulletPointList() {
- val points =
- listOf(
- stringOf(R.string.selfie_tv_guide_one),
- stringOf(R.string.selfie_tv_guide_two),
- stringOf(R.string.selfie_tv_guide_three),
- stringOf(R.string.selfie_tv_guide_four),
- )
- val spannableStringBuilder = SpannableStringBuilder()
- points.forEach { point ->
- val spannableString =
- SpannableString(point).apply {
- setSpan(
- BulletSpan(15),
- 0,
- point.length,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
- )
- }
- with(spannableStringBuilder) {
- append(spannableString)
- append("\n")
- }
- }
- binding.tvSelfieGuideBody.text = spannableStringBuilder
+ private fun Uri.toImageFileModel(): ImageFileModel {
+ return ImageFileModel(
+ hashCode().toLong(),
+ getFileName(requireActivity().contentResolver).toString(),
+ toString()
+ )
}
- private fun setGuideListBlur() {
+ private fun setSavedImages() {
with(binding) {
- svSelfieGuide.setOnScrollChangeListener { _, _, scrollY, _, _ ->
- ivSelfieBlurBottom.alpha = max(0.0, (1 - scrollY / 500f).toDouble()).toFloat()
- ivSelfieBlurTop.alpha = 1 - max(0.0, (1 - scrollY / 100f).toDouble()).toFloat()
+ if (viewModel.selectedNumber.value != PictureNumber.TWO) {
+ layoutAddedImage.isVisible = viewModel.imageList.isNotEmpty()
+ layoutExampleImage.isVisible = viewModel.imageList.isEmpty()
+ btnSelfieAdd.text =
+ if (viewModel.imageList.isEmpty()) stringOf(R.string.selfie_tv_btn_select)
+ else stringOf(R.string.selfie_tv_btn_reselect)
+ listOf(ivAddedImage1, ivAddedImage2, ivAddedImage3)
+ .resetAndLoadImages(viewModel.imageList)
+ } else {
+ listOf(ivAddedFirstImage1, ivAddedFirstImage2, ivAddedFirstImage3)
+ .resetAndLoadImages(viewModel.firstImageList)
+ listOf(ivAddedSecondImage1, ivAddedSecondImage2, ivAddedSecondImage3)
+ .resetAndLoadImages(viewModel.secondImageList)
}
}
}
- private fun initWaitingResult() {
- if (!::waitingResult.isInitialized) {
- waitingResult =
- registerForActivityResult(
- ActivityResultContracts.StartActivityForResult(),
- ) { result ->
- if (result.resultCode == RESULT_OK) {
- requireActivity()
- .supportFragmentManager
- .beginTransaction()
- .replace(R.id.fcv_main, FeedFragment())
- .commit()
- (requireActivity() as? MainActivity)?.initBnvItemIconTintList()
- }
- }
+ private fun List.resetAndLoadImages(imageList: List) {
+ this.forEach { it.load(R.drawable.img_empty_image) }
+ imageList.take(size).forEachIndexed { index, file ->
+ this[index].load(file.url)
}
}
private fun observeGeneratingState() {
- viewModel.totalGeneratingState
- .flowWithLifecycle(lifecycle)
- .onEach { state ->
- when (state) {
- is UiState.Success -> {
- AmplitudeManager.plusIntProperties("user_piccreate")
- waitingResult.launch(Intent(requireContext(), WaitingActivity::class.java))
- with(viewModel) {
- modCurrentPercent(-67)
- resetGeneratingState()
- }
- }
+ viewModel.totalGeneratingState.flowWithLifecycle(lifecycle).onEach { state ->
+ when (state) {
+ is UiState.Success -> {
+ AmplitudeManager.plusIntProperties("user_piccreate")
+ startActivity(WaitingActivity.createIntent(requireContext(), state.data))
+ requireActivity().finish()
+ }
- is UiState.Failure -> toast(stringOf(R.string.error_msg))
- else -> return@onEach
+ is UiState.Failure -> {
+ toast(stringOf(R.string.error_msg))
+ viewModel.resetTotalGeneratingState()
}
- }.launchIn(lifecycleScope)
+
+ else -> return@onEach
+ }
+ }.launchIn(lifecycleScope)
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedActivity.kt b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedActivity.kt
index 5f6ac5bf..7172f7c3 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedActivity.kt
@@ -3,37 +3,26 @@ package kr.genti.presentation.generate.finished
import android.content.Context
import android.content.Intent
import android.os.Bundle
-import android.text.SpannableStringBuilder
-import android.text.Spanned
-import android.text.style.AbsoluteSizeSpan
-import android.text.style.ForegroundColorSpan
-import android.text.style.TypefaceSpan
-import android.widget.ImageView
-import android.widget.TextView
+import android.view.ViewGroup
+import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.core.content.FileProvider
-import androidx.core.content.res.ResourcesCompat
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
-import androidx.core.view.updatePadding
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import coil.load
-import coil.transform.RoundedCornersTransformation
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
import dagger.hilt.android.AndroidEntryPoint
+import jp.wasabeef.glide.transformations.BlurTransformation
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.core.base.BaseActivity
-import kr.genti.core.extension.colorOf
import kr.genti.core.extension.dpToPx
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
-import kr.genti.domain.entity.response.ImageModel
-import kr.genti.domain.enums.PictureRatio.Companion.toPictureRatio
-import kr.genti.domain.enums.PictureType
+import kr.genti.domain.enums.PictureRatio
import kr.genti.presentation.R
import kr.genti.presentation.databinding.ActivityFinishedBinding
import kr.genti.presentation.main.profile.ProfileImageDialog.Companion.FILE_PROVIDER_AUTORITY
@@ -43,6 +32,7 @@ import kr.genti.presentation.util.AmplitudeManager
import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_PAGE
+import kr.genti.presentation.util.GlideResultListener
import kr.genti.presentation.util.downloadImage
import java.io.File
@@ -63,10 +53,11 @@ class FinishedActivity : BaseActivity(R.layout.activity
initImageBtnListener()
initSaveBtnListener()
initShareBtnListener()
- initReturnBtnListener()
initUnwantedBtnListener()
+ initCloseBtnListener()
+ initBackPressedListener()
+ setUiWIthIsPaidIntent()
getIntentInfo()
- setStatusBarTransparent()
observeDownloadCacheImage()
}
@@ -75,26 +66,21 @@ class FinishedActivity : BaseActivity(R.layout.activity
}
private fun initImageBtnListener() {
- with(binding) {
- ivFinishedImage32.setOnSingleClickListener { showImageDialog() }
- ivFinishedImage23.setOnSingleClickListener { showImageDialog() }
+ binding.ivFinishedImage.setOnSingleClickListener {
+ AmplitudeManager.trackEvent("enlarge_picdone_picture")
+ finishedImageDialog = FinishedImageDialog()
+ finishedImageDialog?.show(supportFragmentManager, DIALOG_IMAGE)
}
}
- private fun showImageDialog() {
- AmplitudeManager.trackEvent("enlarge_picdone_picture")
- finishedImageDialog = FinishedImageDialog()
- finishedImageDialog?.show(supportFragmentManager, DIALOG_IMAGE)
- }
-
private fun initSaveBtnListener() {
with(binding) {
- btnDownload23.setOnSingleClickListener { saveImage() }
- btnDownload32.setOnSingleClickListener { saveImage() }
+ btnDownload.setOnSingleClickListener { downloadImage() }
+ btnSavePaid.setOnSingleClickListener { downloadImage() }
}
}
- private fun saveImage() {
+ private fun downloadImage() {
AmplitudeManager.apply {
trackEvent(
EVENT_CLICK_BTN,
@@ -103,7 +89,7 @@ class FinishedActivity : BaseActivity(R.layout.activity
)
plusIntProperties("user_picturedownload")
}
- downloadImage(viewModel.finishedImage.id, viewModel.finishedImage.url)
+ downloadImage(viewModel.finishedImageId, viewModel.finishedImageUrl)
}
private fun initShareBtnListener() {
@@ -121,18 +107,6 @@ class FinishedActivity : BaseActivity(R.layout.activity
}
}
- private fun initReturnBtnListener() {
- binding.btnReturnMain.setOnSingleClickListener {
- AmplitudeManager.trackEvent(
- EVENT_CLICK_BTN,
- mapOf(PROPERTY_PAGE to "picdone"),
- mapOf(PROPERTY_BTN to "gomain"),
- )
- finishedRatingDialog = FinishedRatingDialog()
- finishedRatingDialog?.show(supportFragmentManager, DIALOG_RATING)
- }
- }
-
private fun initUnwantedBtnListener() {
binding.btnUnwanted.setOnSingleClickListener {
finishedReportDialog = FinishedReportDialog()
@@ -140,30 +114,87 @@ class FinishedActivity : BaseActivity(R.layout.activity
}
}
+ private fun initCloseBtnListener() {
+ binding.btnClose.setOnSingleClickListener {
+ showFinishedRatingDialog()
+ }
+ }
+
+ private fun initBackPressedListener() {
+ val onBackPressedCallback =
+ object : OnBackPressedCallback(true) {
+ override fun handleOnBackPressed() {
+ showFinishedRatingDialog()
+ }
+ }
+
+ this.onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
+ }
+
+ private fun setUiWIthIsPaidIntent() {
+ if (intent.getBooleanExtra(EXTRA_IS_PAID, false)) {
+ with(binding) {
+ tvFinishedTitle.text = stringOf(R.string.finished_tv_title_paid)
+ btnDownload.isVisible = false
+ ivFinishedTooltip.isVisible = false
+ btnShare.isVisible = false
+ btnSavePaid.isVisible = true
+ }
+ }
+ }
+
+ private fun showFinishedRatingDialog() {
+ AmplitudeManager.trackEvent(
+ EVENT_CLICK_BTN,
+ mapOf(PROPERTY_PAGE to "picdone"),
+ mapOf(PROPERTY_BTN to "gomain"),
+ )
+ finishedRatingDialog = FinishedRatingDialog()
+ finishedRatingDialog?.show(supportFragmentManager, DIALOG_RATING)
+ }
+
private fun getIntentInfo() {
- viewModel.finishedImage =
- ImageModel(
- intent.getLongExtra(EXTRA_RESPONSE_ID, -1),
- intent.getStringExtra(EXTRA_URL).orEmpty(),
- "",
- intent.getStringExtra(EXTRA_RATIO)?.toPictureRatio(),
- PictureType.PictureCompleted,
- )
- viewModel.setPictureRatio()
- setUiWithRatio()
+ with(viewModel) {
+ finishedImageId = intent.getLongExtra(EXTRA_RESPONSE_ID, -1)
+ finishedImageUrl = intent.getStringExtra(EXTRA_URL).orEmpty()
+ finishedImageRatio = intent.getStringExtra(EXTRA_RATIO).orEmpty()
+ }
+ setImageLayout()
}
- private fun setUiWithRatio() {
+ private fun setImageLayout() {
with(binding) {
- layout32.isVisible = viewModel.isRatioGaro
- layout23.isVisible = !viewModel.isRatioGaro
- if (viewModel.isRatioGaro) {
- ivFinishedImage32.loadImageToView()
- tvFinishedTitle32.setEmphasizedText()
- } else {
- ivFinishedImage23.loadImageToView()
- tvFinishedTitle23.setEmphasizedText()
+ if (viewModel.finishedImageRatio == PictureRatio.RATIO_GARO.name) {
+ setGaroImageMargin()
}
+ ivFinishedImage.load(viewModel.finishedImageUrl)
+ ivFinishedBackground.apply {
+ Glide.with(this.context)
+ .load(viewModel.finishedImageUrl)
+ .apply(RequestOptions.bitmapTransform(BlurTransformation(50)))
+ .listener(GlideResultListener {
+ binding.layoutLoading.isVisible = false
+ })
+ .into(this)
+ }
+ }
+ }
+
+ private fun setGaroImageMargin() {
+ with(binding) {
+ cvFinishedImage.layoutParams =
+ (cvFinishedImage.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ marginStart = 16.dpToPx(this@FinishedActivity)
+ marginEnd = 16.dpToPx(this@FinishedActivity)
+ }
+ btnDownload.layoutParams =
+ (btnDownload.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ marginEnd = 16.dpToPx(this@FinishedActivity)
+ }
+ tvFinishedSubtitle.layoutParams =
+ (tvFinishedSubtitle.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ bottomMargin = 64.dpToPx(this@FinishedActivity)
+ }
}
}
@@ -191,52 +222,6 @@ class FinishedActivity : BaseActivity(R.layout.activity
}.launchIn(lifecycleScope)
}
- private fun ImageView.loadImageToView() {
- this.load(viewModel.finishedImage.url) {
- transformations(
- RoundedCornersTransformation(
- 15.dpToPx(this@FinishedActivity).toFloat(),
- ),
- )
- }
- }
-
- private fun TextView.setEmphasizedText() {
- this.apply {
- text =
- SpannableStringBuilder(text).apply {
- setSpan(
- AbsoluteSizeSpan(22, true),
- 0,
- 11,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
- )
- setSpan(
- ForegroundColorSpan(colorOf(R.color.green_1)),
- 0,
- 11,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
- )
- setSpan(
- ResourcesCompat
- .getFont(context, R.font.font_pretendard_bold)
- ?.let { TypefaceSpan(it) },
- 0,
- 11,
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
- )
- }
- }
- }
-
- private fun setStatusBarTransparent() {
- WindowCompat.setDecorFitsSystemWindows(window, false)
- ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
- v.updatePadding(bottom = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom)
- insets
- }
- }
-
override fun onDestroy() {
super.onDestroy()
finishedImageDialog = null
@@ -253,6 +238,7 @@ class FinishedActivity : BaseActivity(R.layout.activity
private const val EXTRA_RESPONSE_ID = "EXTRA_RESPONSE_ID"
private const val EXTRA_URL = "EXTRA_URL"
private const val EXTRA_RATIO = "EXTRA_RATIO"
+ private const val EXTRA_IS_PAID = "EXTRA_IS_PAID"
@JvmStatic
fun createIntent(
@@ -260,11 +246,13 @@ class FinishedActivity : BaseActivity(R.layout.activity
id: Long,
url: String,
ratio: String,
+ isPaid: Boolean? = null,
): Intent =
Intent(context, FinishedActivity::class.java).apply {
putExtra(EXTRA_RESPONSE_ID, id)
putExtra(EXTRA_URL, url)
putExtra(EXTRA_RATIO, ratio)
+ putExtra(EXTRA_IS_PAID, isPaid)
}
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedImageDialog.kt b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedImageDialog.kt
index c5133c63..6029d02e 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedImageDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedImageDialog.kt
@@ -4,13 +4,11 @@ import android.content.DialogInterface
import android.os.Bundle
import android.view.View
import android.view.WindowManager
-import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.activityViewModels
import coil.load
import kr.genti.core.base.BaseDialog
import kr.genti.core.extension.setGusianBlur
import kr.genti.core.extension.setOnSingleClickListener
-import kr.genti.domain.enums.PictureRatio
import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogFinishedImageBinding
import kr.genti.presentation.util.AmplitudeManager
@@ -28,9 +26,6 @@ class FinishedImageDialog : BaseDialog(R.layout.dial
)
setBackgroundDrawableResource(R.color.transparent)
}
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(50f)
}
override fun onViewCreated(
@@ -46,7 +41,7 @@ class FinishedImageDialog : BaseDialog(R.layout.dial
private fun initExitBtnListener() {
binding.btnExit.setOnSingleClickListener { dismiss() }
- binding.ivProfileBackground.setOnSingleClickListener { dismiss() }
+ binding.root.setOnSingleClickListener { dismiss() }
}
private fun initDownloadBtnListener() {
@@ -55,25 +50,11 @@ class FinishedImageDialog : BaseDialog(R.layout.dial
trackEvent("download_picdone_enlargedpicture")
plusIntProperties("user_picturedownload")
}
- requireActivity().downloadImage(viewModel.finishedImage.id, viewModel.finishedImage.url)
+ requireActivity().downloadImage(viewModel.finishedImageId, viewModel.finishedImageUrl)
}
}
private fun setImage() {
- with(binding.ivProfile) {
- load(viewModel.finishedImage.url)
- if (viewModel.finishedImage.pictureRatio == PictureRatio.RATIO_GARO) {
- (layoutParams as ConstraintLayout.LayoutParams).dimensionRatio = "3:2"
- } else {
- (layoutParams as ConstraintLayout.LayoutParams).dimensionRatio = "2:3"
- }
- }
- }
-
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(null)
+ binding.ivFinished.load(viewModel.finishedImageUrl)
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedRatingDialog.kt b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedRatingDialog.kt
index 0c385102..8e8d152a 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedRatingDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedRatingDialog.kt
@@ -17,25 +17,22 @@ import kr.genti.core.extension.stringOf
import kr.genti.core.extension.toast
import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogFinishedRatingBinding
-import kr.genti.presentation.generate.openchat.OpenchatActivity
import kr.genti.presentation.main.MainActivity
import kr.genti.presentation.util.AmplitudeManager
-class FinishedRatingDialog : BaseDialog(R.layout.dialog_finished_rating) {
+class FinishedRatingDialog :
+ BaseDialog(R.layout.dialog_finished_rating) {
private val viewModel by activityViewModels()
override fun onStart() {
super.onStart()
dialog?.window?.apply {
setLayout(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
)
setBackgroundDrawableResource(R.color.transparent)
}
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(50f)
}
override fun onViewCreated(
@@ -72,13 +69,9 @@ class FinishedRatingDialog : BaseDialog(R.layout.di
}
private fun navigateToMain() {
- if (viewModel.getIsOpenchatAccessible()) {
- startActivity(Intent(requireActivity(), OpenchatActivity::class.java))
- } else {
- Intent(requireActivity(), MainActivity::class.java).apply {
- flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
- startActivity(this)
- }
+ Intent(requireActivity(), MainActivity::class.java).apply {
+ flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
+ startActivity(this)
}
dismiss()
}
@@ -106,11 +99,4 @@ class FinishedRatingDialog : BaseDialog(R.layout.di
}
}.launchIn(lifecycleScope)
}
-
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(null)
- }
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedReportDialog.kt b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedReportDialog.kt
index 6dfc06a2..a76fd316 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedReportDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedReportDialog.kt
@@ -21,7 +21,8 @@ import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogFinishedReportBinding
import kr.genti.presentation.util.AmplitudeManager
-class FinishedReportDialog : BaseDialog(R.layout.dialog_finished_report) {
+class FinishedReportDialog :
+ BaseDialog(R.layout.dialog_finished_report) {
private val viewModel by activityViewModels()
override fun onStart() {
@@ -33,9 +34,6 @@ class FinishedReportDialog : BaseDialog(R.layout.di
)
setBackgroundDrawableResource(R.color.transparent)
}
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(50f)
}
override fun onViewCreated(
@@ -58,10 +56,6 @@ class FinishedReportDialog : BaseDialog(R.layout.di
dismiss()
requireActivity().finish()
}
- btnOkay.setOnSingleClickListener {
- dismiss()
- requireActivity().finish()
- }
}
}
@@ -91,21 +85,10 @@ class FinishedReportDialog : BaseDialog(R.layout.di
with(binding) {
layoutErrorInput.isVisible = false
layoutErrorOutput.isVisible = true
- viewOutside.setOnSingleClickListener {
- dismiss()
- requireActivity().finish()
- }
}
} else {
toast(stringOf(R.string.error_msg))
}
}.launchIn(lifecycleScope)
}
-
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
- requireActivity()
- .window.decorView.rootView
- .setGusianBlur(null)
- }
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedViewModel.kt b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedViewModel.kt
index c659e4ac..bdf6b05a 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedViewModel.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/finished/FinishedViewModel.kt
@@ -13,7 +13,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kr.genti.domain.entity.request.ReportRequestModel
import kr.genti.domain.entity.response.ImageModel
-import kr.genti.domain.enums.PictureRatio
import kr.genti.domain.repository.GenerateRepository
import kr.genti.domain.repository.UserRepository
import java.io.File
@@ -23,107 +22,93 @@ import javax.inject.Inject
@HiltViewModel
class FinishedViewModel
- @Inject
- constructor(
- private val generateRepository: GenerateRepository,
- private val userRepository: UserRepository,
- ) : ViewModel() {
- val errorReport = MutableLiveData()
- val isWritten = MutableLiveData(false)
+@Inject
+constructor(
+ private val generateRepository: GenerateRepository
+) : ViewModel() {
+ val errorReport = MutableLiveData()
+ val isWritten = MutableLiveData(false)
- var finishedImage =
- ImageModel(
- -1,
- "",
- "",
- null,
- null,
- )
+ var finishedImageId: Long = -1
+ var finishedImageUrl: String = ""
+ var finishedImageRatio: String = ""
- var isRatioGaro = true
+ private val _isImageDownloaded = MutableSharedFlow()
+ val isImageDownloaded: SharedFlow = _isImageDownloaded
- private val _isImageDownloaded = MutableSharedFlow()
- val isImageDownloaded: SharedFlow = _isImageDownloaded
+ private val _postReportResult = MutableSharedFlow()
+ val postReportResult: SharedFlow = _postReportResult
- private val _postReportResult = MutableSharedFlow()
- val postReportResult: SharedFlow = _postReportResult
+ private val _postRateResult = MutableSharedFlow()
+ val postRateResult: SharedFlow = _postRateResult
- private val _postRateResult = MutableSharedFlow()
- val postRateResult: SharedFlow = _postRateResult
+ private val _postVerifyResult = MutableSharedFlow()
+ val postVerifyResult: SharedFlow = _postVerifyResult
- private val _postVerifyResult = MutableSharedFlow()
- val postVerifyResult: SharedFlow = _postVerifyResult
-
- fun checkWritten() {
- isWritten.value = errorReport.value?.isNotEmpty()
- }
-
- fun setPictureRatio() {
- isRatioGaro = finishedImage.pictureRatio == PictureRatio.RATIO_GARO
- }
+ fun checkWritten() {
+ isWritten.value = errorReport.value?.isNotEmpty()
+ }
- fun downloadImageToCache(outputFile: File) {
- viewModelScope.launch {
- runCatching {
- withContext(Dispatchers.IO) {
- val connection = URL(finishedImage.url).openConnection()
- connection.connect()
- connection.getInputStream()?.use { inputStream ->
- FileOutputStream(outputFile).use { out ->
- val bitmap = BitmapFactory.decodeStream(inputStream)
- bitmap?.compress(Bitmap.CompressFormat.PNG, 100, out)
- }
+ fun downloadImageToCache(outputFile: File) {
+ viewModelScope.launch {
+ runCatching {
+ withContext(Dispatchers.IO) {
+ val connection = URL(finishedImageUrl).openConnection()
+ connection.connect()
+ connection.getInputStream()?.use { inputStream ->
+ FileOutputStream(outputFile).use { out ->
+ val bitmap = BitmapFactory.decodeStream(inputStream)
+ bitmap?.compress(Bitmap.CompressFormat.PNG, 100, out)
}
}
- }.onSuccess {
- _isImageDownloaded.emit(true)
- }.onFailure {
- _isImageDownloaded.emit(false)
}
+ }.onSuccess {
+ _isImageDownloaded.emit(true)
+ }.onFailure {
+ _isImageDownloaded.emit(false)
}
}
+ }
- fun postGenerateRateToServer(star: Int) {
- viewModelScope.launch {
- generateRepository
- .postGenerateRate(
- finishedImage.id.toInt(),
- star,
- ).onSuccess {
- _postRateResult.emit(true)
- }.onFailure {
- _postRateResult.emit(false)
- }
- }
+ fun postGenerateRateToServer(star: Int) {
+ viewModelScope.launch {
+ generateRepository
+ .postGenerateRate(
+ finishedImageId.toInt(),
+ star,
+ ).onSuccess {
+ _postRateResult.emit(true)
+ }.onFailure {
+ _postRateResult.emit(false)
+ }
}
+ }
- fun postGenerateReportToServer() {
- viewModelScope.launch {
- generateRepository
- .postGenerateReport(
- ReportRequestModel(
- finishedImage.id,
- errorReport.value.orEmpty(),
- ),
- ).onSuccess {
- _postReportResult.emit(true)
- }.onFailure {
- _postReportResult.emit(false)
- }
- }
+ fun postGenerateReportToServer() {
+ viewModelScope.launch {
+ generateRepository
+ .postGenerateReport(
+ ReportRequestModel(
+ finishedImageId,
+ errorReport.value.orEmpty(),
+ ),
+ ).onSuccess {
+ _postReportResult.emit(true)
+ }.onFailure {
+ _postReportResult.emit(false)
+ }
}
+ }
- fun postVerifyGenerateStateToServer() {
- viewModelScope.launch {
- generateRepository
- .postVerifyGenerateState(finishedImage.id.toInt())
- .onSuccess {
- _postVerifyResult.emit(true)
- }.onFailure {
- _postVerifyResult.emit(false)
- }
- }
+ fun postVerifyGenerateStateToServer() {
+ viewModelScope.launch {
+ generateRepository
+ .postVerifyGenerateState(finishedImageId.toInt())
+ .onSuccess {
+ _postVerifyResult.emit(true)
+ }.onFailure {
+ _postVerifyResult.emit(false)
+ }
}
-
- fun getIsOpenchatAccessible() = userRepository.getIsChatAccessible()
}
+}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatActivity.kt b/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatActivity.kt
deleted file mode 100644
index d22bebd4..00000000
--- a/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatActivity.kt
+++ /dev/null
@@ -1,144 +0,0 @@
-package kr.genti.presentation.generate.openchat
-
-import android.content.Intent
-import android.graphics.Color
-import android.graphics.LinearGradient
-import android.graphics.Shader
-import android.net.Uri
-import android.os.Bundle
-import android.text.Spannable
-import android.text.SpannableString
-import android.text.style.ForegroundColorSpan
-import androidx.activity.addCallback
-import androidx.activity.viewModels
-import androidx.lifecycle.flowWithLifecycle
-import androidx.lifecycle.lifecycleScope
-import coil.load
-import dagger.hilt.android.AndroidEntryPoint
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kr.genti.core.base.BaseActivity
-import kr.genti.core.extension.setOnSingleClickListener
-import kr.genti.core.extension.stringOf
-import kr.genti.core.extension.toast
-import kr.genti.core.state.UiState
-import kr.genti.presentation.R
-import kr.genti.presentation.databinding.ActivityOpenchatBinding
-import kr.genti.presentation.main.MainActivity
-
-@AndroidEntryPoint
-class OpenchatActivity : BaseActivity(R.layout.activity_openchat) {
- private val viewModel by viewModels()
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- initExitBtnListener()
- initAccessAgainBtnListener()
- setTitleTextGradation()
- setBackPressed()
- observeGetOpenchatState()
- }
-
- override fun onResume() {
- super.onResume()
-
- if (viewModel.isKakaoLaunched) navigateToMain()
- }
-
- private fun initExitBtnListener() {
- binding.btnExit.setOnSingleClickListener {
- viewModel.setIsChatAccessible()
- navigateToMain()
- }
- }
-
- private fun navigateToMain() {
- Intent(this, MainActivity::class.java).apply {
- flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
- startActivity(this)
- }
- }
-
- private fun initAccessAgainBtnListener() {
- binding.btnAccessAgain.setOnClickListener {
- if (viewModel.isAccessible) {
- viewModel.isAccessible = false
- binding.ivAccessAgain.load(R.drawable.ic_check_checked)
- binding.tvAccessAgain.setTextColor(Color.parseColor("#0D2D2B"))
- } else {
- viewModel.isAccessible = true
- binding.ivAccessAgain.load(R.drawable.ic_check_unchecked)
- binding.tvAccessAgain.setTextColor(Color.parseColor("#990D2D2B"))
- }
- }
- }
-
- private fun setTitleTextGradation() {
- binding.tvOpenchatTitleUp.apply {
- paint.shader =
- LinearGradient(
- 0f,
- 0f,
- paint.measureText(text.toString()),
- textSize,
- intArrayOf(
- Color.parseColor("#6CEE2A"),
- Color.parseColor("#1CF48B"),
- ),
- null,
- Shader.TileMode.CLAMP,
- )
- }
- }
-
- private fun setBackPressed() {
- onBackPressedDispatcher.addCallback(this) {
- viewModel.setIsChatAccessible()
- navigateToMain()
- }
- }
-
- private fun observeGetOpenchatState() {
- viewModel.getOpenchatState
- .flowWithLifecycle(lifecycle)
- .distinctUntilChanged()
- .onEach { state ->
- when (state) {
- is UiState.Success -> {
- with(state.data) {
- if (!accessible) navigateToMain()
- url?.let { initEnterBtnListener(it) }
- count?.let { setGuideTextInfo(it) }
- }
- }
-
- is UiState.Failure -> toast(stringOf(R.string.error_msg))
- else -> return@onEach
- }
- }.launchIn(lifecycleScope)
- }
-
- private fun initEnterBtnListener(url: String) {
- binding.btnEnterOpenchat.setOnSingleClickListener {
- with(viewModel) {
- setIsChatAccessible()
- isKakaoLaunched = true
- }
- startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
- }
- }
-
- private fun setGuideTextInfo(count: Int) {
- binding.tvOpenchatGuide.text =
- SpannableString(getString(R.string.openchat_tv_guide, count)).apply {
- setSpan(
- ForegroundColorSpan(Color.parseColor("#49F155")),
- 3,
- 7 + count.toString().length,
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE,
- )
- }
- }
-}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatViewModel.kt b/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatViewModel.kt
deleted file mode 100644
index 6f5efcc5..00000000
--- a/presentation/src/main/java/kr/genti/presentation/generate/openchat/OpenchatViewModel.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package kr.genti.presentation.generate.openchat
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.launch
-import kr.genti.core.state.UiState
-import kr.genti.domain.entity.response.OpenchatModel
-import kr.genti.domain.repository.GenerateRepository
-import kr.genti.domain.repository.UserRepository
-import javax.inject.Inject
-
-@HiltViewModel
-class OpenchatViewModel
- @Inject
- constructor(
- private val generateRepository: GenerateRepository,
- private val userRepository: UserRepository,
- ) : ViewModel() {
- private val _getOpenchatState = MutableStateFlow>(UiState.Empty)
- val getOpenchatState: StateFlow> = _getOpenchatState
-
- var isAccessible = true
- var isKakaoLaunched = false
-
- init {
- getOpenchatData()
- }
-
- private fun getOpenchatData() {
- _getOpenchatState.value = UiState.Loading
- viewModelScope.launch {
- generateRepository
- .getOpenchatData()
- .onSuccess {
- userRepository.setIsChatAccessible(it.accessible)
- _getOpenchatState.value = UiState.Success(it)
- }.onFailure {
- _getOpenchatState.value = UiState.Failure(it.message.toString())
- }
- }
- }
-
- fun setIsChatAccessible() {
- userRepository.setIsChatAccessible(isAccessible)
- }
- }
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyActivity.kt b/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyActivity.kt
index 5fd04c10..79b6826a 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyActivity.kt
@@ -66,8 +66,8 @@ class VerifyActivity : BaseActivity(R.layout.activity_ver
private fun initView() {
AmplitudeManager.trackEvent("view_verifyme1")
- setStatusBarColorFromResource(R.color.verify_bg)
- setNavigationBarColorFromResource(R.color.verify_bg)
+ setStatusBarColorFromResource(R.color.black)
+ setNavigationBarColorFromResource(R.color.black)
}
private fun initExitBtnListener() {
@@ -215,7 +215,7 @@ class VerifyActivity : BaseActivity(R.layout.activity_ver
)
}
}.onSuccess {
- cameraLauncher.launch(photoUri)
+ photoUri?.let { cameraLauncher.launch(it) }
}
} else {
toast(stringOf(R.string.error_msg))
@@ -229,7 +229,8 @@ class VerifyActivity : BaseActivity(R.layout.activity_ver
cacheDir,
)
- private fun getFileDateFormat() = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
+ private fun getFileDateFormat() =
+ SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
private fun observeGeneratingState() {
viewModel.totalGeneratingState
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyExitDialog.kt b/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyExitDialog.kt
index 357b4fbc..6b359848 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyExitDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/verify/VerifyExitDialog.kt
@@ -17,7 +17,7 @@ class VerifyExitDialog : BaseDialog(R.layout.dialog_ver
super.onStart()
dialog?.window?.apply {
setLayout(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
)
setBackgroundDrawableResource(R.color.transparent)
@@ -35,7 +35,7 @@ class VerifyExitDialog : BaseDialog(R.layout.dialog_ver
}
private fun initCloseBtnListener() {
- binding.btnClose.setOnSingleClickListener { dismiss() }
+ binding.btnReturn.setOnSingleClickListener { dismiss() }
}
private fun initExitBtnListener() {
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/waiting/PushDialog.kt b/presentation/src/main/java/kr/genti/presentation/generate/waiting/PushDialog.kt
index bfa4cb2f..3ba78fbd 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/waiting/PushDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/waiting/PushDialog.kt
@@ -26,7 +26,7 @@ class PushDialog : BaseDialog(R.layout.dialog_push) {
super.onStart()
dialog?.window?.apply {
setLayout(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
)
setBackgroundDrawableResource(R.color.transparent)
@@ -50,7 +50,12 @@ class PushDialog : BaseDialog(R.layout.dialog_push) {
}
private fun initCloseBtnListener() {
- binding.btnClose.setOnSingleClickListener { dismiss() }
+ binding.btnClose.setOnSingleClickListener {
+ with(requireActivity()) {
+ setResult(Activity.RESULT_OK)
+ finish()
+ }
+ }
}
private fun initGetAlarmBtnListener() {
@@ -92,13 +97,4 @@ class PushDialog : BaseDialog(R.layout.dialog_push) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
-
- override fun onDismiss(dialog: DialogInterface) {
- super.onDismiss(dialog)
-
- with(requireActivity()) {
- setResult(Activity.RESULT_OK)
- finish()
- }
- }
}
diff --git a/presentation/src/main/java/kr/genti/presentation/generate/waiting/WaitingActivity.kt b/presentation/src/main/java/kr/genti/presentation/generate/waiting/WaitingActivity.kt
index 094d35ce..096fac26 100644
--- a/presentation/src/main/java/kr/genti/presentation/generate/waiting/WaitingActivity.kt
+++ b/presentation/src/main/java/kr/genti/presentation/generate/waiting/WaitingActivity.kt
@@ -2,6 +2,8 @@ package kr.genti.presentation.generate.waiting
import android.Manifest
import android.app.Activity
+import android.content.Context
+import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
@@ -16,6 +18,7 @@ import kr.genti.core.base.BaseActivity
import kr.genti.core.extension.setOnSingleClickListener
import kr.genti.presentation.R
import kr.genti.presentation.databinding.ActivityWaitBinding
+import kr.genti.presentation.generate.finished.FinishedActivity
import kr.genti.presentation.util.AmplitudeManager
import kr.genti.presentation.util.AmplitudeManager.EVENT_CLICK_BTN
import kr.genti.presentation.util.AmplitudeManager.PROPERTY_BTN
@@ -30,6 +33,7 @@ class WaitingActivity : BaseActivity(R.layout.activity_wait
initReturnBtnListener()
setOnBackPressed()
+ setUiBuIsPaidIntent()
setStatusBarTransparent()
}
@@ -75,6 +79,12 @@ class WaitingActivity : BaseActivity(R.layout.activity_wait
false
}
+ private fun setUiBuIsPaidIntent() {
+ if (intent.getBooleanExtra(EXTRA_IS_PAID, false)) {
+ binding.tvWaitTitle.text = getString(R.string.wait_tv_title_paid)
+ }
+ }
+
private fun setStatusBarTransparent() {
WindowCompat.setDecorFitsSystemWindows(window, false)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets ->
@@ -91,5 +101,16 @@ class WaitingActivity : BaseActivity(R.layout.activity_wait
companion object {
private const val DIALOG_PUSH = "DIALOG_PUSH"
+
+ private const val EXTRA_IS_PAID = "EXTRA_IS_PAID"
+
+ @JvmStatic
+ fun createIntent(
+ context: Context,
+ isPaid: Boolean? = null,
+ ): Intent =
+ Intent(context, WaitingActivity::class.java).apply {
+ putExtra(EXTRA_IS_PAID, isPaid)
+ }
}
}
diff --git a/presentation/src/main/java/kr/genti/presentation/main/CreateErrorDialog.kt b/presentation/src/main/java/kr/genti/presentation/main/CreateErrorDialog.kt
index 6280f848..92bcb063 100644
--- a/presentation/src/main/java/kr/genti/presentation/main/CreateErrorDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/main/CreateErrorDialog.kt
@@ -22,7 +22,7 @@ class CreateErrorDialog : BaseDialog(R.layout.dialog_c
super.onStart()
dialog?.window?.apply {
setLayout(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
)
setBackgroundDrawableResource(R.color.transparent)
diff --git a/presentation/src/main/java/kr/genti/presentation/main/CreateFinishedDialog.kt b/presentation/src/main/java/kr/genti/presentation/main/CreateFinishedDialog.kt
index 191a3bf3..d79ffb60 100644
--- a/presentation/src/main/java/kr/genti/presentation/main/CreateFinishedDialog.kt
+++ b/presentation/src/main/java/kr/genti/presentation/main/CreateFinishedDialog.kt
@@ -12,14 +12,15 @@ import kr.genti.presentation.R
import kr.genti.presentation.databinding.DialogCreateFinishedBinding
import kr.genti.presentation.generate.finished.FinishedActivity
-class CreateFinishedDialog : BaseDialog(R.layout.dialog_create_finished) {
+class CreateFinishedDialog :
+ BaseDialog(R.layout.dialog_create_finished) {
private val viewModel by activityViewModels()
override fun onStart() {
super.onStart()
dialog?.window?.apply {
setLayout(
- WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT,
)
setBackgroundDrawableResource(R.color.transparent)
@@ -45,18 +46,17 @@ class CreateFinishedDialog : BaseDialog