diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 8568fa9e..2f97c865 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -26,13 +26,17 @@ android {
buildTypes {
release {
- isMinifyEnabled = false
+ getByName("debug")
+ isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
+ buildFeatures {
+ buildConfig = true
+ }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
@@ -57,4 +61,5 @@ dependencies {
implementation(project(":feature:main"))
implementation(project(":feature:login"))
implementation(project(":core:designsystem"))
-}
\ No newline at end of file
+ implementation(project(":core:data"))
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 33341792..1c00b2cc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,8 @@
+
+
-
+ android:networkSecurityConfig="@xml/network_security_config"
+ tools:targetApi="31"/>
\ No newline at end of file
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..872512f7
--- /dev/null
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+
+
+
+ 223.130.130.31
+
+
\ No newline at end of file
diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts
index c6fba51a..e9cdff2a 100644
--- a/core/data/build.gradle.kts
+++ b/core/data/build.gradle.kts
@@ -45,4 +45,8 @@ dependencies {
ksp(libs.hilt.compiler)
implementation(libs.hilt.android)
+
+ implementation(project(":core:domain"))
+ implementation(project(":core:model"))
+ implementation(project(":core:network"))
}
\ No newline at end of file
diff --git a/core/data/src/androidTest/java/com/goalpanzi/mission_mate/core/data/ExampleInstrumentedTest.kt b/core/data/src/androidTest/java/com/goalpanzi/mission_mate/core/data/ExampleInstrumentedTest.kt
deleted file mode 100644
index 893f4c99..00000000
--- a/core/data/src/androidTest/java/com/goalpanzi/mission_mate/core/data/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.goalpanzi.mission_mate.core.data
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.goalpanzi.mission_mate.core.data.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/Data.kt b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/Data.kt
deleted file mode 100644
index 4b970b65..00000000
--- a/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/Data.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.goalpanzi.mission_mate.core.data
-
-class Data {
-}
\ No newline at end of file
diff --git a/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DataModule.kt b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DataModule.kt
new file mode 100644
index 00000000..21696f28
--- /dev/null
+++ b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DataModule.kt
@@ -0,0 +1,16 @@
+package com.goalpanzi.mission_mate.core.data.di
+
+import com.goalpanzi.mission_mate.core.data.repository.LoginRepositoryImpl
+import com.goalpanzi.mission_mate.core.domain.repository.LoginRepository
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal abstract class DataModule {
+
+ @Binds
+ abstract fun bindLoginRepository(impl: LoginRepositoryImpl): LoginRepository
+}
\ No newline at end of file
diff --git a/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DispatchersModule.kt b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DispatchersModule.kt
new file mode 100644
index 00000000..2b129a1b
--- /dev/null
+++ b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/di/DispatchersModule.kt
@@ -0,0 +1,27 @@
+package com.goalpanzi.mission_mate.core.data.di
+
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import javax.inject.Qualifier
+
+@Qualifier
+@Retention(AnnotationRetention.RUNTIME)
+annotation class Dispatcher(val dispatchers: MissionMateDispatcher)
+
+enum class MissionMateDispatcher {
+ IO
+}
+
+@Module
+@InstallIn(SingletonComponent::class)
+interface DispatchersModule {
+
+ @Provides
+ @Dispatcher(MissionMateDispatcher.IO)
+ fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
+
+}
\ No newline at end of file
diff --git a/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/repository/LoginRepositoryImpl.kt b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/repository/LoginRepositoryImpl.kt
new file mode 100644
index 00000000..5b257823
--- /dev/null
+++ b/core/data/src/main/java/com/goalpanzi/mission_mate/core/data/repository/LoginRepositoryImpl.kt
@@ -0,0 +1,18 @@
+package com.goalpanzi.mission_mate.core.data.repository
+
+import com.goalpanzi.mission_mate.core.domain.repository.LoginRepository
+import com.goalpanzi.mission_mate.core.network.service.LoginService
+import com.luckyoct.model.GoogleLogin
+import com.luckyoct.model.request.GoogleLoginRequest
+import javax.inject.Inject
+
+class LoginRepositoryImpl @Inject constructor(
+ private val loginService: LoginService
+): LoginRepository {
+
+ override suspend fun requestGoogleLogin(token: String, email: String): GoogleLogin {
+ val request = GoogleLoginRequest(identityToken = token, email = email)
+ val response = loginService.requestGoogleLogin(request)
+ return response
+ }
+}
\ No newline at end of file
diff --git a/core/datastore/src/androidTest/java/com/goalpanzi/mission_mate/core/datastore/ExampleInstrumentedTest.kt b/core/datastore/src/androidTest/java/com/goalpanzi/mission_mate/core/datastore/ExampleInstrumentedTest.kt
deleted file mode 100644
index b6e103ad..00000000
--- a/core/datastore/src/androidTest/java/com/goalpanzi/mission_mate/core/datastore/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.goalpanzi.mission_mate.core.datastore
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.goalpanzi.mission_mate.core.datastore.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/theme/Color.kt b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/theme/Color.kt
index 10bade95..5068d8ef 100644
--- a/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/theme/Color.kt
+++ b/core/designsystem/src/main/java/com/goalpanzi/mission_mate/core/designsystem/theme/Color.kt
@@ -8,4 +8,6 @@ val Pink80 = Color(0xFFEFB8C8)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
+val Pink40 = Color(0xFF7D5260)
+
+val Orange01 = Color(0xFFF5EDEA)
\ No newline at end of file
diff --git a/core/domain/build.gradle.kts b/core/domain/build.gradle.kts
index d3dd2cc9..e5538f89 100644
--- a/core/domain/build.gradle.kts
+++ b/core/domain/build.gradle.kts
@@ -45,4 +45,6 @@ dependencies {
ksp(libs.hilt.compiler)
implementation(libs.hilt.android)
+
+ implementation(project(":core:model"))
}
\ No newline at end of file
diff --git a/core/domain/src/androidTest/java/com/goalpanzi/mission_mate/core/domain/ExampleInstrumentedTest.kt b/core/domain/src/androidTest/java/com/goalpanzi/mission_mate/core/domain/ExampleInstrumentedTest.kt
deleted file mode 100644
index ff04cf42..00000000
--- a/core/domain/src/androidTest/java/com/goalpanzi/mission_mate/core/domain/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.goalpanzi.mission_mate.core.domain
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.goalpanzi.mission_mate.core.domain.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/Domain.kt b/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/Domain.kt
deleted file mode 100644
index 17c80efa..00000000
--- a/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/Domain.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.goalpanzi.mission_mate.core.domain
-
-class Domain {
-}
\ No newline at end of file
diff --git a/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/repository/LoginRepository.kt b/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/repository/LoginRepository.kt
new file mode 100644
index 00000000..dfe6f1fc
--- /dev/null
+++ b/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/repository/LoginRepository.kt
@@ -0,0 +1,7 @@
+package com.goalpanzi.mission_mate.core.domain.repository
+
+import com.luckyoct.model.GoogleLogin
+
+interface LoginRepository {
+ suspend fun requestGoogleLogin(token: String, email: String): GoogleLogin
+}
\ No newline at end of file
diff --git a/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/usecase/LoginUseCase.kt b/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/usecase/LoginUseCase.kt
new file mode 100644
index 00000000..5ff15bce
--- /dev/null
+++ b/core/domain/src/main/java/com/goalpanzi/mission_mate/core/domain/usecase/LoginUseCase.kt
@@ -0,0 +1,13 @@
+package com.goalpanzi.mission_mate.core.domain.usecase
+
+import com.goalpanzi.mission_mate.core.domain.repository.LoginRepository
+import com.luckyoct.model.GoogleLogin
+import javax.inject.Inject
+
+class LoginUseCase @Inject constructor(
+ private val loginRepository: LoginRepository
+) {
+
+ suspend fun requestGoogleLogin(token: String, email: String): GoogleLogin = loginRepository.requestGoogleLogin(token, email)
+
+}
\ No newline at end of file
diff --git a/core/model/.gitignore b/core/model/.gitignore
new file mode 100644
index 00000000..42afabfd
--- /dev/null
+++ b/core/model/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts
new file mode 100644
index 00000000..0c2067bb
--- /dev/null
+++ b/core/model/build.gradle.kts
@@ -0,0 +1,42 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.jetbrains.kotlin.android)
+ alias(libs.plugins.kotlin.plugin.serialization)
+}
+
+android {
+ namespace = "com.luckyoct.model"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+}
+
+dependencies {
+
+ implementation(libs.kotlin.serialization.json)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ androidTestImplementation(libs.androidx.espresso.core)
+}
\ No newline at end of file
diff --git a/core/model/consumer-rules.pro b/core/model/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/core/model/proguard-rules.pro b/core/model/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/core/model/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/core/model/src/main/AndroidManifest.xml b/core/model/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..a5918e68
--- /dev/null
+++ b/core/model/src/main/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/core/model/src/main/java/com/luckyoct/model/GoogleLogin.kt b/core/model/src/main/java/com/luckyoct/model/GoogleLogin.kt
new file mode 100644
index 00000000..406c5eca
--- /dev/null
+++ b/core/model/src/main/java/com/luckyoct/model/GoogleLogin.kt
@@ -0,0 +1,10 @@
+package com.luckyoct.model
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class GoogleLogin(
+ val accessToken: String,
+ val refreshToken: String,
+ val isProfileSet: Boolean
+)
diff --git a/core/model/src/main/java/com/luckyoct/model/request/GoogleLoginRequest.kt b/core/model/src/main/java/com/luckyoct/model/request/GoogleLoginRequest.kt
new file mode 100644
index 00000000..c844ac49
--- /dev/null
+++ b/core/model/src/main/java/com/luckyoct/model/request/GoogleLoginRequest.kt
@@ -0,0 +1,9 @@
+package com.luckyoct.model.request
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class GoogleLoginRequest(
+ val identityToken: String,
+ val email: String
+)
diff --git a/core/model/src/test/java/com/luckyoct/model/ExampleUnitTest.kt b/core/model/src/test/java/com/luckyoct/model/ExampleUnitTest.kt
new file mode 100644
index 00000000..dfdf2fb7
--- /dev/null
+++ b/core/model/src/test/java/com/luckyoct/model/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.luckyoct.model
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/core/navigation/src/androidTest/java/com/goalpanzi/mission_mate/core/navigation/ExampleInstrumentedTest.kt b/core/navigation/src/androidTest/java/com/goalpanzi/mission_mate/core/navigation/ExampleInstrumentedTest.kt
deleted file mode 100644
index 3939f16d..00000000
--- a/core/navigation/src/androidTest/java/com/goalpanzi/mission_mate/core/navigation/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package com.goalpanzi.mission_mate.core.navigation
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleInstrumentedTest {
-
-}
\ No newline at end of file
diff --git a/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/Navigation.kt b/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/Navigation.kt
deleted file mode 100644
index f95186bb..00000000
--- a/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/Navigation.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.goalpanzi.mission_mate.core.navigation
-
-class Navigation {
-}
\ No newline at end of file
diff --git a/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt b/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt
new file mode 100644
index 00000000..d0ad89be
--- /dev/null
+++ b/core/navigation/src/main/java/com/goalpanzi/mission_mate/core/navigation/RouteModel.kt
@@ -0,0 +1,8 @@
+package com.goalpanzi.mission_mate.core.navigation
+
+import kotlinx.serialization.Serializable
+
+sealed interface RouteModel {
+ @Serializable
+ data object Login : RouteModel
+}
\ No newline at end of file
diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts
index 99e10005..9b0226f3 100644
--- a/core/network/build.gradle.kts
+++ b/core/network/build.gradle.kts
@@ -20,6 +20,9 @@ android {
}
buildTypes {
+ debug {
+ buildConfigField("String", "BASE_URL", "\"http://223.130.130.31:8080\"")
+ }
release {
isMinifyEnabled = false
proguardFiles(
@@ -28,6 +31,9 @@ android {
)
}
}
+ buildFeatures {
+ buildConfig = true
+ }
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
@@ -48,4 +54,6 @@ dependencies {
ksp(libs.hilt.compiler)
implementation(libs.hilt.android)
+
+ implementation(project(":core:model"))
}
\ No newline at end of file
diff --git a/core/network/src/androidTest/java/com/goalpanzi/mission_mate/core/network/ExampleInstrumentedTest.kt b/core/network/src/androidTest/java/com/goalpanzi/mission_mate/core/network/ExampleInstrumentedTest.kt
deleted file mode 100644
index 089f385d..00000000
--- a/core/network/src/androidTest/java/com/goalpanzi/mission_mate/core/network/ExampleInstrumentedTest.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.goalpanzi.mission_mate.core.network
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.ext.junit.runners.AndroidJUnit4
-
-import org.junit.Test
-import org.junit.runner.RunWith
-
-import org.junit.Assert.*
-
-/**
- * Instrumented test, which will execute on an Android device.
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-@RunWith(AndroidJUnit4::class)
-class ExampleInstrumentedTest {
- @Test
- fun useAppContext() {
- // Context of the app under test.
- val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.goalpanzi.mission_mate.core.network.test", appContext.packageName)
- }
-}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/Network.kt b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/Network.kt
deleted file mode 100644
index 4112733d..00000000
--- a/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/Network.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package com.goalpanzi.mission_mate.core.network
-
-class Network {
-}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/NetworkModule.kt b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/NetworkModule.kt
new file mode 100644
index 00000000..fa3284ae
--- /dev/null
+++ b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/NetworkModule.kt
@@ -0,0 +1,75 @@
+package com.goalpanzi.mission_mate.core.network.di
+
+import com.goalpanzi.mission_mate.core.network.BuildConfig
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import kotlinx.serialization.json.Json
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Converter
+import retrofit2.Retrofit
+import retrofit2.converter.kotlinx.serialization.asConverterFactory
+import java.security.KeyStore
+import javax.inject.Singleton
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+
+@Module
+@InstallIn(SingletonComponent::class)
+internal object NetworkModule {
+
+ @Provides
+ @Singleton
+ fun provideRequestHttpLoggingInterceptor(): HttpLoggingInterceptor {
+ return HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
+ }
+
+ @Provides
+ @Singleton
+ fun provideOkhttpClient(
+ httpLoggingInterceptor: HttpLoggingInterceptor
+ ): OkHttpClient {
+ // TLS 대응
+ val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ trustManagerFactory.init(null as KeyStore?)
+ val trustManager = trustManagerFactory.trustManagers[0] as X509TrustManager
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(null, arrayOf(trustManager), java.security.SecureRandom())
+
+ return OkHttpClient.Builder()
+ .sslSocketFactory(sslContext.socketFactory, trustManager)
+ .addInterceptor(httpLoggingInterceptor)
+ .build()
+ }
+
+ @Provides
+ @Singleton
+ fun provideJson(): Json = Json {
+ ignoreUnknownKeys = true
+ }
+
+ @Provides
+ @Singleton
+ fun provideConverterFactory(
+ json: Json,
+ ): Converter.Factory {
+ return json.asConverterFactory("application/json".toMediaType())
+ }
+
+ @Provides
+ @Singleton
+ fun provideRetrofit(
+ okHttpClient: OkHttpClient,
+ converterFactory: Converter.Factory
+ ) : Retrofit {
+ return Retrofit.Builder()
+ .client(okHttpClient)
+ .baseUrl(BuildConfig.BASE_URL)
+ .addConverterFactory(converterFactory)
+ .build()
+ }
+}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/ServiceModule.kt b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/ServiceModule.kt
new file mode 100644
index 00000000..0d248b31
--- /dev/null
+++ b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/di/ServiceModule.kt
@@ -0,0 +1,20 @@
+package com.goalpanzi.mission_mate.core.network.di
+
+import com.goalpanzi.mission_mate.core.network.service.LoginService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import retrofit2.Retrofit
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object ServiceModule {
+
+ @Provides
+ @Singleton
+ fun provideLoginService(retrofit: Retrofit): LoginService {
+ return retrofit.create(LoginService::class.java)
+ }
+}
\ No newline at end of file
diff --git a/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/service/LoginService.kt b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/service/LoginService.kt
new file mode 100644
index 00000000..79c07b5c
--- /dev/null
+++ b/core/network/src/main/java/com/goalpanzi/mission_mate/core/network/service/LoginService.kt
@@ -0,0 +1,14 @@
+package com.goalpanzi.mission_mate.core.network.service
+
+import com.luckyoct.model.GoogleLogin
+import com.luckyoct.model.request.GoogleLoginRequest
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface LoginService {
+
+ @POST("/api/auth/login/google")
+ suspend fun requestGoogleLogin(
+ @Body request: GoogleLoginRequest
+ ): GoogleLogin
+}
\ No newline at end of file
diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts
index e0a9e624..fb862b5f 100644
--- a/feature/login/build.gradle.kts
+++ b/feature/login/build.gradle.kts
@@ -1,3 +1,4 @@
+import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
@@ -23,8 +24,12 @@ android {
}
buildTypes {
+ debug {
+ buildConfigField("String", "CREDENTIAL_WEB_CLIENT_ID", getCredentialClientId())
+ }
release {
- isMinifyEnabled = false
+ getByName("debug")
+ isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
@@ -42,6 +47,7 @@ android {
}
buildFeatures {
compose = true
+ buildConfig = true
}
composeCompiler {
enableStrongSkippingMode = true
@@ -72,4 +78,15 @@ dependencies {
ksp(libs.hilt.compiler)
implementation(project(":core:designsystem"))
-}
\ No newline at end of file
+ implementation(project(":core:navigation"))
+ implementation(project(":core:domain"))
+ implementation(project(":core:model"))
+
+ implementation(libs.credentials)
+ implementation(libs.credentials.auth)
+ implementation(libs.google.id)
+}
+
+fun getCredentialClientId(): String {
+ return gradleLocalProperties(rootDir, providers).getProperty("CREDENTIAL_WEB_CLIENT_ID") ?: ""
+}
diff --git a/feature/login/proguard-rules.pro b/feature/login/proguard-rules.pro
index 481bb434..71dd361f 100644
--- a/feature/login/proguard-rules.pro
+++ b/feature/login/proguard-rules.pro
@@ -18,4 +18,8 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
+-if class androidx.credentials.CredentialManager
+-keep class androidx.credentials.playservices.** {
+ *;
+}
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginActivity.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginActivity.kt
deleted file mode 100644
index 6ee3bbcf..00000000
--- a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginActivity.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-package com.goalpanzi.mission_mate.feature.login
-
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
-import com.goalpanzi.mission_mate.core.designsystem.theme.MissionmateTheme
-import dagger.hilt.android.AndroidEntryPoint
-
-@AndroidEntryPoint
-class LoginActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- MissionmateTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "Android",
- modifier = Modifier.padding(innerPadding)
- )
- }
- }
- }
- }
-}
-
-@Composable
-fun Greeting(name: String, modifier: Modifier = Modifier) {
- Text(
- text = "Hello $name!",
- modifier = modifier
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- MissionmateTheme {
- Greeting("Android")
- }
-}
\ No newline at end of file
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginNavigation.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginNavigation.kt
new file mode 100644
index 00000000..dd559be8
--- /dev/null
+++ b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginNavigation.kt
@@ -0,0 +1,20 @@
+package com.goalpanzi.mission_mate.feature.login
+
+import androidx.navigation.NavController
+import androidx.navigation.NavGraphBuilder
+import androidx.navigation.compose.composable
+import com.goalpanzi.mission_mate.core.navigation.RouteModel
+
+fun NavController.navigateToLogin() {
+ this.navigate(RouteModel.Login)
+}
+
+fun NavGraphBuilder.loginNavGraph(
+ onBackClick: () -> Unit
+) {
+ composable {
+ LoginRoute(
+ onBackClick = onBackClick
+ )
+ }
+}
\ No newline at end of file
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginScreen.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginScreen.kt
new file mode 100644
index 00000000..a487f0e8
--- /dev/null
+++ b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginScreen.kt
@@ -0,0 +1,99 @@
+package com.goalpanzi.mission_mate.feature.login
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
+import com.goalpanzi.mission_mate.core.designsystem.theme.Orange01
+
+@Composable
+fun LoginRoute(
+ onBackClick: () -> Unit,
+ modifier: Modifier = Modifier,
+ viewModel: LoginViewModel = hiltViewModel()
+) {
+ val context = LocalContext.current
+
+ LoginScreen(
+ modifier = modifier,
+ onGoogleLoginClick = { viewModel.request(context) }
+ )
+}
+
+@Composable
+fun LoginScreen(
+ modifier: Modifier = Modifier,
+ onGoogleLoginClick: () -> Unit,
+) {
+ Box(
+ modifier = modifier
+ ) {
+ Column(
+ modifier = modifier
+ .fillMaxSize()
+ .background(color = Orange01)
+ .padding(horizontal = 24.dp),
+ verticalArrangement = Arrangement.Center
+ ) {
+ Box(
+ modifier = modifier
+ .size(342.dp)
+ )
+
+ Box(
+ modifier = modifier
+ .fillMaxWidth()
+ .padding(top = 91.dp)
+ .height(60.dp)
+ .background(color = Color.White, shape = RoundedCornerShape(30.dp))
+ .clip(RoundedCornerShape(30.dp))
+ .clickable(onClick = onGoogleLoginClick),
+ contentAlignment = Alignment.CenterStart
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.btn_google),
+ contentScale = ContentScale.FillBounds,
+ contentDescription = null
+ )
+ Text(
+ text = stringResource(id = R.string.google_login),
+ modifier = modifier.fillMaxWidth(),
+ style = MissionMateTypography.body_lg_bold,
+ color = Color.Black,
+ textAlign = TextAlign.Center
+ )
+ }
+ }
+ }
+}
+
+@Preview
+@Composable
+fun LoginScreenPreview() {
+ LoginScreen(
+ onGoogleLoginClick = {}
+ )
+}
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginUiState.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginUiState.kt
new file mode 100644
index 00000000..dac6ead8
--- /dev/null
+++ b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginUiState.kt
@@ -0,0 +1,6 @@
+package com.goalpanzi.mission_mate.feature.login
+
+sealed interface LoginUiState {
+ data object Loading : LoginUiState
+ data class Success(val isAlreadyMember: Boolean) : LoginUiState
+}
\ No newline at end of file
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginViewModel.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginViewModel.kt
new file mode 100644
index 00000000..83074eea
--- /dev/null
+++ b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/LoginViewModel.kt
@@ -0,0 +1,69 @@
+package com.goalpanzi.mission_mate.feature.login
+
+import android.content.Context
+import androidx.credentials.CredentialManager
+import androidx.credentials.CustomCredential
+import androidx.credentials.GetCredentialRequest
+import androidx.credentials.GetCredentialResponse
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.goalpanzi.mission_mate.core.domain.usecase.LoginUseCase
+import com.goalpanzi.mission_mate.feature.login.util.TokenUtil
+import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
+import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
+import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class LoginViewModel @Inject constructor(
+ private val loginUseCase: LoginUseCase
+) : ViewModel() {
+
+ fun request(context: Context) {
+ viewModelScope.launch {
+
+ val credentialManager = CredentialManager.create(context)
+ val signInWithGoogleOption: GetSignInWithGoogleOption =
+ GetSignInWithGoogleOption.Builder(BuildConfig.CREDENTIAL_WEB_CLIENT_ID)
+ .build()
+
+ val request: GetCredentialRequest = GetCredentialRequest.Builder()
+ .addCredentialOption(signInWithGoogleOption)
+ .build()
+
+ try {
+ val result = credentialManager.getCredential(context, request)
+ handleSignIn(result)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ private suspend fun handleSignIn(response: GetCredentialResponse) {
+ when (val credential = response.credential) {
+ is CustomCredential -> {
+ if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
+ try {
+ val googleIdTokenCredential =
+ GoogleIdTokenCredential.createFrom(credential.data)
+ val compressedToken = TokenUtil.compressToken(googleIdTokenCredential.idToken)
+ val result = loginUseCase.requestGoogleLogin(
+ token = compressedToken,
+ email = googleIdTokenCredential.id
+ )
+ // TODO : success event
+ } catch (e: GoogleIdTokenParsingException) {
+ e.printStackTrace()
+ }
+ }
+ }
+
+ else -> {
+ // TODO : error event
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/util/TokenUtil.kt b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/util/TokenUtil.kt
new file mode 100644
index 00000000..6b87dc6f
--- /dev/null
+++ b/feature/login/src/main/java/com/goalpanzi/mission_mate/feature/login/util/TokenUtil.kt
@@ -0,0 +1,10 @@
+package com.goalpanzi.mission_mate.feature.login.util
+
+import java.security.MessageDigest
+
+object TokenUtil {
+ fun compressToken(data: String): String {
+ val bytes = MessageDigest.getInstance("SHA-256").digest(data.toByteArray())
+ return bytes.joinToString("") { "%02x".format(it) }
+ }
+}
\ No newline at end of file
diff --git a/feature/login/src/main/res/drawable/btn_google.xml b/feature/login/src/main/res/drawable/btn_google.xml
new file mode 100644
index 00000000..e099295a
--- /dev/null
+++ b/feature/login/src/main/res/drawable/btn_google.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/login/src/main/res/values/strings.xml b/feature/login/src/main/res/values/strings.xml
new file mode 100644
index 00000000..342e82a8
--- /dev/null
+++ b/feature/login/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Google로 로그인
+
\ No newline at end of file
diff --git a/feature/main/build.gradle.kts b/feature/main/build.gradle.kts
index 37589087..185bd8e8 100644
--- a/feature/main/build.gradle.kts
+++ b/feature/main/build.gradle.kts
@@ -69,4 +69,7 @@ dependencies {
ksp(libs.hilt.compiler)
implementation(project(":core:designsystem"))
+ implementation(project(":core:navigation"))
+ implementation(project(":core:domain"))
+ implementation(project(":feature:login"))
}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainActivity.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainActivity.kt
index db1bbfbb..57f70455 100644
--- a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainActivity.kt
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainActivity.kt
@@ -4,45 +4,27 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.tooling.preview.Preview
+import androidx.activity.viewModels
+import com.goalpanzi.mission_mate.core.designsystem.theme.MissionmateTheme
+import com.goalpanzi.mission_mate.core.main.component.MainNavigator
+import com.goalpanzi.mission_mate.core.main.component.rememberMainNavigator
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
+
+ private val viewModel: MainViewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
- com.goalpanzi.mission_mate.core.designsystem.theme.MissionmateTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "Android",
- modifier = Modifier.padding(innerPadding)
- )
- }
+ val navigator: MainNavigator = rememberMainNavigator()
+ MissionmateTheme {
+ MainScreen(
+ navigator = navigator,
+ )
}
}
}
}
-
-@Composable
-fun Greeting(name: String, modifier: Modifier = Modifier) {
- Text(
- text = "Hello $name!",
- modifier = modifier
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- com.goalpanzi.mission_mate.core.designsystem.theme.MissionmateTheme {
- Greeting("Android")
- }
-}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainScreen.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainScreen.kt
new file mode 100644
index 00000000..3a5366ab
--- /dev/null
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainScreen.kt
@@ -0,0 +1,33 @@
+package com.goalpanzi.mission_mate.core.main
+
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.goalpanzi.mission_mate.core.main.component.MainNavHost
+import com.goalpanzi.mission_mate.core.main.component.MainNavigator
+import com.goalpanzi.mission_mate.core.main.component.rememberMainNavigator
+
+@Composable
+internal fun MainScreen(
+ navigator: MainNavigator = rememberMainNavigator(),
+) {
+ MainScreenContent(
+ navigator = navigator
+ )
+}
+
+@Composable
+private fun MainScreenContent(
+ navigator: MainNavigator,
+ modifier: Modifier = Modifier
+) {
+ Scaffold(
+ modifier = modifier,
+ content = { padding ->
+ MainNavHost(
+ navigator = navigator,
+ padding = padding
+ )
+ }
+ )
+}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainViewModel.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainViewModel.kt
new file mode 100644
index 00000000..dd508655
--- /dev/null
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/MainViewModel.kt
@@ -0,0 +1,14 @@
+package com.goalpanzi.mission_mate.core.main
+
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+
+@HiltViewModel
+class MainViewModel @Inject constructor(
+
+): ViewModel() {
+
+ // TODO : flow to get isAuthorized
+ val isAuthorized = false
+}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt
new file mode 100644
index 00000000..d76c4a9c
--- /dev/null
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavHost.kt
@@ -0,0 +1,33 @@
+package com.goalpanzi.mission_mate.core.main.component
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.navigation.compose.NavHost
+import com.goalpanzi.mission_mate.feature.login.loginNavGraph
+
+@Composable
+internal fun MainNavHost(
+ modifier: Modifier = Modifier,
+ navigator: MainNavigator,
+ padding: PaddingValues
+) {
+ Box(
+ modifier = modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colorScheme.surfaceDim)
+ ) {
+ NavHost(
+ navController = navigator.navController,
+ startDestination = navigator.startDestination
+ ) {
+ loginNavGraph(
+ onBackClick = { navigator.popBackStack() }
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt
new file mode 100644
index 00000000..20f8eaaf
--- /dev/null
+++ b/feature/main/src/main/java/com/goalpanzi/mission_mate/core/main/component/MainNavigator.kt
@@ -0,0 +1,31 @@
+package com.goalpanzi.mission_mate.core.main.component
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.rememberNavController
+import com.goalpanzi.mission_mate.core.navigation.RouteModel
+import com.goalpanzi.mission_mate.feature.login.navigateToLogin
+
+class MainNavigator(
+ val navController: NavHostController
+) {
+
+ //TODO : change to Main
+ val startDestination = RouteModel.Login
+
+ fun popBackStack() {
+ navController.popBackStack()
+ }
+
+ fun navigateToLogin() {
+ navController.navigateToLogin()
+ }
+}
+
+@Composable
+internal fun rememberMainNavigator(
+ navController: NavHostController = rememberNavController()
+) : MainNavigator = remember(navController) {
+ MainNavigator(navController)
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2b2125b5..4246f804 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -17,7 +17,7 @@ androidxActivity = "1.9.0"
## Compose
composeBom = "2024.06.00"
-navigation-compose = "2.7.7"
+navigation-compose = "2.8.0-beta02"
## Kotlin Symbol Processing (KSP)
ksp = "2.0.0-1.0.23"
@@ -43,6 +43,11 @@ dataStore-preferences = "1.1.1"
## Image Loader
coil-compose = "2.5.0"
+## Google OAuth
+credential = "1.2.2"
+identity = "1.1.1"
+material = "1.12.0"
+
[libraries]
## Koitln
kotlin-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
@@ -69,7 +74,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
-androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigation-compose" }
+androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose" }
## Test
junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -97,6 +102,12 @@ dataStore = { module = "androidx.datastore:datastore-preferences", version.ref =
## Image Loader
coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil-compose" }
+## Google OAuth
+credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credential" }
+credentials-auth = { group = "androidx.credentials", name = "credentials-play-services-auth", version.ref = "credential" }
+google-id = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version = "identity" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+
[plugins]
## Android gradle plugin
android-application = { id = "com.android.application", version.ref = "agp" }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 1789af6b..60df1575 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,4 +1,4 @@
-#Sat Jul 13 15:21:07 KST 2024
+#Sat Jul 20 15:16:45 KST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1808e810..c5bf1a21 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -30,3 +30,4 @@ include(":core:navigation")
include(":feature:login")
include(":feature:main")
include(":feature:board")
+include(":core:model")