From b8c9663154798c9b4886485cf4a5661c38c0411e Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:03:56 +0900 Subject: [PATCH 01/91] :sparkles: :: add auth data --- .../data/di/RepositoryModule.kt | 17 ++++++++ .../data/repository/auth/AuthRepository.kt | 20 +++++++++ .../repository/auth/AuthRepositoryImpl.kt | 43 +++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt create mode 100644 core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt create mode 100644 core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt diff --git a/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt b/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt new file mode 100644 index 00000000..67555ec5 --- /dev/null +++ b/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt @@ -0,0 +1,17 @@ +package com.stackknowledge.data.di + +import com.stackknowledge.data.repository.auth.AuthRepository +import com.stackknowledge.data.repository.auth.AuthRepositoryImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +abstract class RepositoryModule { + @Binds + abstract fun bindAuthRepository( + authRepositoryImpl: AuthRepositoryImpl + ): AuthRepository +} \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt new file mode 100644 index 00000000..14ac0b21 --- /dev/null +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt @@ -0,0 +1,20 @@ +package com.stackknowledge.data.repository.auth + +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import kotlinx.coroutines.flow.Flow + +interface AuthRepository { + suspend fun login( + body: LoginRequest, + role: Authority + ): Flow + + suspend fun saveToken(token: LoginResponse) + + suspend fun logout(): Flow + + suspend fun requestAuthCode(code: String): Flow +} \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt new file mode 100644 index 00000000..0698942a --- /dev/null +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt @@ -0,0 +1,43 @@ +package com.stackknowledge.data.repository.auth + +import com.stackknowledge.datastore.LocalAuthDataSource +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import com.stackknowledge.network.datasource.auth.AuthDataSource +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class AuthRepositoryImpl @Inject constructor( + private val authDataSource: AuthDataSource, + private val localDataSource: LocalAuthDataSource +): AuthRepository { + override suspend fun login( + body: LoginRequest, + role: Authority + ): Flow { + return authDataSource.login( + body = body, + role = role + ) + } + + override suspend fun saveToken(token: LoginResponse) { + token.let { + localDataSource.setAccessToken(it.accessToken) + localDataSource.setAccessTime(it.expiredAt) + localDataSource.setRefreshToken(it.refreshToken) + localDataSource.setRefreshTime(it.expiredAt) + localDataSource.setAuthorityInfo(it.authority.toString()) + } + } + + override suspend fun logout(): Flow { + return authDataSource.logout() + } + + override suspend fun requestAuthCode(code: String): Flow { + return authDataSource.requestAuthCode(code = code) + } +} \ No newline at end of file From df63498b26040a84d75efe497ffb9af471eefeff Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:05:53 +0900 Subject: [PATCH 02/91] :memo: :: add version --- core/datastore/build.gradle.kts | 21 +-------------------- core/model/build.gradle.kts | 1 + core/network/build.gradle.kts | 5 ++++- feature/login/build.gradle.kts | 25 +++++++++++++++++++++++++ gradle/libs.versions.toml | 10 ++++++++++ 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index bb63c8e6..56e258cc 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -2,34 +2,15 @@ plugins { id("stackknowledge.android.core") id("stackknowledge.android.hilt") - alias(libs.plugins.protobuf) } android { namespace = "com.stackknowledge.datastore" } -protobuf { - protoc { - artifact = libs.protobuf.protoc.get().toString() - } - generateProtoTasks { - all().forEach { task -> - task.builtins { - register("java") { - option("lite") - } - register("kotlin") { - option("lite") - } - } - } - } -} - dependencies { implementation(project(":core:model")) implementation(libs.androidx.dataStore.core) - implementation(libs.protobuf.kotlin.lite) + implementation(libs.androidx.dataStore.preferences) } \ No newline at end of file diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts index f38fc392..1bacd4a1 100644 --- a/core/model/build.gradle.kts +++ b/core/model/build.gradle.kts @@ -5,4 +5,5 @@ plugins { dependencies { implementation(libs.kotlinx.datetime) + implementation(libs.moshi) } \ No newline at end of file diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index a3777571..58720b5c 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -14,9 +14,12 @@ android { defaultConfig { buildConfigField("String", "BASE_URL", getApiKey("BASE_URL")) + buildConfigField("String", "GOOGLE_CLIENT_ID", getApiKey("GOOGLE_CLIENT_ID")) + buildConfigField("String", "REDIRECT_URI", getApiKey("REDIRECT_URI")) + buildConfigField("String", "SCOPE", getApiKey("SCOPE")) } - namespace = "com.msg.network" + namespace = "com.stackknowledge.network" } dependencies { diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index 65db4e8a..ca1edaec 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -1,3 +1,6 @@ +import java.io.FileInputStream +import java.util.Properties + @Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed plugins { id("stackknowledge.android.feature") @@ -5,5 +8,27 @@ plugins { } android { + buildFeatures { + buildConfig = true + } + + defaultConfig { + buildConfigField("String", "REDIRECT_URI", getApiKey("REDIRECT_URI")) + buildConfigField("String", "GOOGLE_CLIENT_ID", getApiKey("GOOGLE_CLIENT_ID")) + buildConfigField("String","SCOPE", getApiKey("SCOPE")) + } namespace = "com.stackknowledge.login" +} + +dependencies { + implementation(libs.google.services) +// implementation(libs.firebase.auth) +// implementation(libs.firebase.bom) + implementation(libs.play.services.auth) +} +fun getApiKey(propertyKey: String): String { + val propFile = rootProject.file("./local.properties") + val properties = Properties() + properties.load(FileInputStream(propFile)) + return properties.getProperty(propertyKey) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ba54876e..663a9971 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -23,6 +23,7 @@ androidxTestRunner = "1.5.2" androidx-test-ext-junit = "1.1.5" androidxWindowManager = "1.2.0" coil = "2.4.0" +firebase-auth = "22.0.0" firebaseBom = "31.2.0" firebaseCrashlyticsPlugin = "2.9.2" firebasePerfPlugin = "1.4.2" @@ -47,6 +48,9 @@ retrofitKotlinxSerializableJson = "1.0.0" room = "2.6.1" org-jetbrains-kotlin-android = "1.8.10" lifecycle-runtime-ktx = "2.6.2" +google-services = "4.4.0" +play-services-auth = "20.7.0" +moshi = "1.15.1" [libraries] #Define Library @@ -68,6 +72,7 @@ androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util", ve androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" } androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" } androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" } +androidx-dataStore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDataStore" } androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHiltNavigationCompose" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "androidxLifecycle" } androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } @@ -103,6 +108,11 @@ retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "re room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" } room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" } room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" } +google-services = { group = "com.google.gms", name = "google-services", version.ref = "google-services" } +firebase-auth = { group = "com.google", name = "firebase-auth", version.ref = "firebase-auth" } +firebase-bom = { group = "com.google", name = "firebase-bom", version.ref = "firebaseBom" } +play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-services-auth" } +moshi = { group = "com.squareup.moshi", name = "moshi", version.ref = "moshi" } #Define Dependeicies used in build-logic android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } From 96ecaac535508053bc133d9774a19992ca30ad3d Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:08:07 +0900 Subject: [PATCH 03/91] :memo: :: add auth navigation --- .../java/com/stackknowledge/MainActivity.kt | 18 +++++++++++- .../StackKnowledgeApplication.kt | 5 ++++ .../navigation/StackKnowledgeNavHost.kt | 28 +++++++++++++++---- .../stackknowledge/ui/StackKnowledgeApp.kt | 3 +- .../ui/StackKnowledgeAppState.kt | 8 ++++-- 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/stackknowledge/MainActivity.kt b/app/src/main/java/com/stackknowledge/MainActivity.kt index 091b33d5..7fe08abb 100644 --- a/app/src/main/java/com/stackknowledge/MainActivity.kt +++ b/app/src/main/java/com/stackknowledge/MainActivity.kt @@ -1,5 +1,6 @@ package com.stackknowledge +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -7,8 +8,11 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.LoginActivity import com.stackknowledge.ui.StackKnowledgeApp +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class MainActivity : ComponentActivity() { @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { @@ -16,9 +20,21 @@ class MainActivity : ComponentActivity() { setContent { CompositionLocalProvider { StackKnowledgeAndroidTheme { _, _ -> - StackKnowledgeApp(windowSizeClass = calculateWindowSizeClass(this@MainActivity)) + StackKnowledgeApp( + windowSizeClass = calculateWindowSizeClass(this@MainActivity), + startLogin = { startLogin() } + ) } } } } + + private fun startLogin() { + startActivity( + Intent( + this, + LoginActivity::class.java + ) + ) + } } diff --git a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt b/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt index eac6dc4f..0ad4046a 100644 --- a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt +++ b/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt @@ -1,2 +1,7 @@ package com.stackknowledge +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class StackKnowledgeApplication : Application() {} \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt index 3f595fe0..30783267 100644 --- a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt @@ -1,23 +1,39 @@ package com.stackknowledge.navigation +import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.navigation.compose.NavHost +import com.stackknowledge.login.LoginActivity +import com.stackknowledge.login.navigation.loginRoute +import com.stackknowledge.login.navigation.loginScreen +import com.stackknowledge.login.navigation.navigateToLogin +import com.stackknowledge.login.navigation.roleCheckRoute +import com.stackknowledge.login.navigation.roleCheckScreen import com.stackknowledge.ui.StackKnowledgeAppState @Composable fun StackKnowledgeNavHost( appState: StackKnowledgeAppState, + startLogin: () -> Unit, modifier: Modifier = Modifier, - startDestination: String, // = 선생여부 묻는 스크린 Route <- 루트 추가 + startDestination: String = roleCheckRoute, ) { val navController = appState.navController // 아래의 NavHost의 startDestination은 GoogleOAuth작업 이후 학생 or 선생여부 묻는 스크린을 띄워주면 될 거 같아요 - // NavHost ( - // navController = navController, - // startDestination = startDestination, - // modifier = modfiier - // ) + NavHost ( + navController = navController, + startDestination = startDestination, + modifier = modifier + ) { + roleCheckScreen( + studentCheck = { startLogin() }, + teacherCheck = { startLogin() } + ) + loginScreen( + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt index f8f443bb..619110b9 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt @@ -11,8 +11,9 @@ fun StackKnowledgeApp( appState: StackKnowledgeAppState = rememberStackKnowledgeAppState( windowSizeClass = windowSizeClass ), + startLogin:() -> Unit ) { StackKnowledgeAndroidTheme { _, _ -> - // StackKnowledgeNavHost(appState = appState, startDestination = ) <- 이부분도 startDestination 스크린 작업 후 추가 + StackKnowledgeNavHost(appState = appState, startLogin = { startLogin() }) //startDestination = ) // <- 이부분도 startDestination 스크린 작업 후 추가 } } \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt index ab402e52..5f242b09 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt +++ b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt @@ -8,8 +8,10 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.navigation.NavController import androidx.navigation.NavDestination +import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.navigation.TopLevelDestination import kotlinx.coroutines.CoroutineScope @@ -17,7 +19,7 @@ import kotlinx.coroutines.CoroutineScope fun rememberStackKnowledgeAppState( windowSizeClass: WindowSizeClass, coroutineScope: CoroutineScope = rememberCoroutineScope(), - navController: NavController = rememberNavController(), + navController: NavHostController = rememberNavController(), ): StackKnowledgeAppState { return remember( navController, @@ -34,7 +36,7 @@ fun rememberStackKnowledgeAppState( @Stable class StackKnowledgeAppState( - val navController: NavController, + val navController: NavHostController, val coroutineScope: CoroutineScope, val windowSizeClass: WindowSizeClass ) { @@ -44,7 +46,7 @@ class StackKnowledgeAppState( val currentTopLevelDestination: TopLevelDestination? @Composable get() = when(currentDestination?.route) { - // loginRoute 작성 + loginRoute -> TopLevelDestination.LOGIN else -> null } From f75771e627504cf71f194fa240ff33be280a51ef Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:09:00 +0900 Subject: [PATCH 04/91] :memo: :: add permission --- app/src/main/AndroidManifest.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 075be8df..26442e91 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,10 @@ + + + + + + + + + + + \ No newline at end of file From 580f3419e18ee287d9bc7ee9abb2bd9ed638f3db Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:09:57 +0900 Subject: [PATCH 05/91] :sparkles: :: add auth DataStore --- .../datastore/LocalAuthDataSource.kt | 39 ++++++++ .../datastore/LocalAuthDataSourceImpl.kt | 88 +++++++++++++++++++ .../datastore/di/DataStoreModule.kt | 30 +++++++ .../datastore/di/LocalDataSourceModule.kt | 18 ++++ .../datastore/key/AuthPreferenceKey.kt | 16 ++++ .../com/stackknowledge/proto/authToken.proto | 12 --- 6 files changed, 191 insertions(+), 12 deletions(-) create mode 100644 core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt create mode 100644 core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt create mode 100644 core/datastore/src/main/java/com/stackknowledge/datastore/di/DataStoreModule.kt create mode 100644 core/datastore/src/main/java/com/stackknowledge/datastore/di/LocalDataSourceModule.kt create mode 100644 core/datastore/src/main/java/com/stackknowledge/datastore/key/AuthPreferenceKey.kt delete mode 100644 core/datastore/src/main/java/com/stackknowledge/proto/authToken.proto diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt new file mode 100644 index 00000000..824e6b57 --- /dev/null +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt @@ -0,0 +1,39 @@ +package com.stackknowledge.datastore + +import com.stackknowledge.model.remote.enumdatatype.Authority +import kotlinx.coroutines.flow.Flow + +interface LocalAuthDataSource { + // AccessToken + suspend fun getAccessToken(): Flow + + suspend fun setAccessToken(accessToken: String) + + suspend fun removeAccessToken() + + // AccessTime + suspend fun getAccessTime(): Flow + + suspend fun setAccessTime(accessTime: String) + + suspend fun removeAccessTime() + + // RefreshToken + suspend fun getRefreshToken(): Flow + + suspend fun setRefreshToken(refreshToken: String) + + suspend fun removeRefreshToken() + + // RefreshTime + suspend fun getRefreshTime(): Flow + + suspend fun setRefreshTime(refreshTime: String) + + suspend fun removeRefreshTime() + + // Authority + suspend fun setAuthorityInfo(authority: String) + + suspend fun getAuthorityInfo(): Flow +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt new file mode 100644 index 00000000..fa0afae8 --- /dev/null +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt @@ -0,0 +1,88 @@ +package com.stackknowledge.datastore + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import com.stackknowledge.datastore.key.AuthPreferenceKey +import com.stackknowledge.model.remote.enumdatatype.Authority +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class LocalAuthDataSourceImpl @Inject constructor( + private val dataStore: DataStore +): LocalAuthDataSource { + override suspend fun getAccessToken(): Flow = dataStore.data.map { + it[AuthPreferenceKey.ACCESS_TOKEN] ?: "" + } + + override suspend fun setAccessToken(accessToken: String) { + dataStore.edit { + it[AuthPreferenceKey.ACCESS_TOKEN] = accessToken + } + } + + override suspend fun removeAccessToken() { + dataStore.edit { + it.remove(AuthPreferenceKey.ACCESS_TOKEN) + } + } + + override suspend fun getAccessTime(): Flow = dataStore.data.map { + it[AuthPreferenceKey.ACCESS_TIME] ?: "" + } + + override suspend fun setAccessTime(accessTime: String) { + dataStore.edit { + it[AuthPreferenceKey.ACCESS_TIME] = accessTime + } + } + + override suspend fun removeAccessTime() { + dataStore.edit { + it.remove(AuthPreferenceKey.ACCESS_TIME) + } + } + + override suspend fun getRefreshToken(): Flow = dataStore.data.map { + it[AuthPreferenceKey.REFRESH_TOKEN] ?: "" + } + + override suspend fun setRefreshToken(refreshToken: String) { + dataStore.edit { + it[AuthPreferenceKey.REFRESH_TOKEN] = refreshToken + } + } + + override suspend fun removeRefreshToken() { + dataStore.edit { + it.remove(AuthPreferenceKey.REFRESH_TOKEN) + } + } + + override suspend fun getRefreshTime(): Flow = dataStore.data.map { + it[AuthPreferenceKey.REFRESH_TIME] ?: "" + } + + override suspend fun setRefreshTime(refreshTime: String) { + dataStore.edit { + it[AuthPreferenceKey.REFRESH_TIME] = refreshTime + } + } + + override suspend fun removeRefreshTime() { + dataStore.edit { + it.remove(AuthPreferenceKey.REFRESH_TIME) + } + } + + override suspend fun getAuthorityInfo(): Flow = dataStore.data.map { + it[AuthPreferenceKey.AUTHORITY] ?: "" + } + + override suspend fun setAuthorityInfo(authority: String) { + dataStore.edit { + it[AuthPreferenceKey.AUTHORITY] = authority + } + } +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/di/DataStoreModule.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/di/DataStoreModule.kt new file mode 100644 index 00000000..983998c7 --- /dev/null +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/di/DataStoreModule.kt @@ -0,0 +1,30 @@ +package com.stackknowledge.datastore.di + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.emptyPreferences +import androidx.datastore.preferences.preferencesDataStoreFile +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object DataStoreModule { + @Provides + @Singleton + fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore { + return PreferenceDataStoreFactory.create( + corruptionHandler = ReplaceFileCorruptionHandler( + produceNewData = { emptyPreferences() } + ), + produceFile = { context.preferencesDataStoreFile("autoDataStore") } + ) + } +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/di/LocalDataSourceModule.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/di/LocalDataSourceModule.kt new file mode 100644 index 00000000..73a42149 --- /dev/null +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/di/LocalDataSourceModule.kt @@ -0,0 +1,18 @@ +package com.stackknowledge.datastore.di + +import com.stackknowledge.datastore.LocalAuthDataSource +import com.stackknowledge.datastore.LocalAuthDataSourceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +abstract class LocalDataSourceModule { + @Binds + abstract fun provideLocalAuthDataSource( + localAuthDataSourceImpl: LocalAuthDataSourceImpl + ): LocalAuthDataSource +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/key/AuthPreferenceKey.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/key/AuthPreferenceKey.kt new file mode 100644 index 00000000..d6c9d522 --- /dev/null +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/key/AuthPreferenceKey.kt @@ -0,0 +1,16 @@ +package com.stackknowledge.datastore.key + +import androidx.datastore.preferences.core.stringPreferencesKey + +object AuthPreferenceKey { + + val ACCESS_TOKEN = stringPreferencesKey("access_token") + + val ACCESS_TIME = stringPreferencesKey("access_time") + + val REFRESH_TOKEN = stringPreferencesKey("refresh_token") + + val REFRESH_TIME = stringPreferencesKey("refresh_time") + + val AUTHORITY = stringPreferencesKey("authority") +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/proto/authToken.proto b/core/datastore/src/main/java/com/stackknowledge/proto/authToken.proto deleted file mode 100644 index 8978ca71..00000000 --- a/core/datastore/src/main/java/com/stackknowledge/proto/authToken.proto +++ /dev/null @@ -1,12 +0,0 @@ - syntax = "proto3"; - - option java_package = "com.msg.datastore"; - option java_multiple_files = true; - - message AuthToken { - string accessToken = 1; - string accessExp = 2; - string refreshToken = 3; - string refreshExp = 4; - string authority = 5; - } \ No newline at end of file From ba186320b4879da2b28cb484fc21ccb6d71233cd Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:10:58 +0900 Subject: [PATCH 06/91] :memo: :: add onClick --- .../design_system/component/button/GoogleButton.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/GoogleButton.kt b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/GoogleButton.kt index a71d3dbc..5c1eb76e 100644 --- a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/GoogleButton.kt +++ b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/GoogleButton.kt @@ -24,11 +24,12 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme @Composable fun GoogleButton( - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + onClick: () -> Unit = {} ) { StackKnowledgeAndroidTheme { colors, typography -> Button( - onClick = {}, + onClick = onClick, modifier = modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(10.dp)) From 4978d30658d067333cee03f36fa4c799275d4b40 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:11:26 +0900 Subject: [PATCH 07/91] :memo: :: add string check role --- core/design-system/src/main/res/values/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 57035008..abd22a10 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -30,4 +30,5 @@ 채점 만들기 상점 + 사용자가 학생인지\n선생님인지 선택해주세요. \ No newline at end of file From afb97425482048d902396aec184f7ad0b649967d Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:11:59 +0900 Subject: [PATCH 08/91] :sparkles: :: add auth usecase --- .../domain/auth/LoginUseCase.kt | 20 +++++++++++++++++++ .../domain/auth/LogoutUseCase.kt | 12 +++++++++++ .../domain/auth/RequestAuthCodeUseCase.kt | 12 +++++++++++ .../domain/auth/SaveTokenUseCase.kt | 13 ++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt new file mode 100644 index 00000000..c0ff51ca --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt @@ -0,0 +1,20 @@ +package com.stackknowledge.domain.auth + +import com.stackknowledge.data.repository.auth.AuthRepository +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import javax.inject.Inject + +class LoginUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke( + body: LoginRequest, + role: Authority + ) = runCatching { + authRepository.login( + body = body, + role = role + ) + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt new file mode 100644 index 00000000..13dc770e --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt @@ -0,0 +1,12 @@ +package com.stackknowledge.domain.auth + +import com.stackknowledge.data.repository.auth.AuthRepository +import javax.inject.Inject + +class LogoutUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke() = runCatching { + authRepository.logout() + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt new file mode 100644 index 00000000..369febe4 --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt @@ -0,0 +1,12 @@ +package com.stackknowledge.domain.auth + +import com.stackknowledge.data.repository.auth.AuthRepository +import javax.inject.Inject + +class RequestAuthCodeUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke(code: String) = runCatching { + authRepository.requestAuthCode(code = code) + } +} \ No newline at end of file diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt new file mode 100644 index 00000000..b64dd2de --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt @@ -0,0 +1,13 @@ +package com.stackknowledge.domain.auth + +import com.stackknowledge.data.repository.auth.AuthRepository +import com.stackknowledge.model.remote.response.auth.LoginResponse +import javax.inject.Inject + +class SaveTokenUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke(token: LoginResponse) = runCatching { + authRepository.saveToken(token = token) + } +} \ No newline at end of file From 54734be7e9692ef4df67237bf92dce74c7b6c9c3 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:12:23 +0900 Subject: [PATCH 09/91] :sparkles: :: add exception --- .../domain/exception/HttpException.kt | 42 +++++++++++++++++++ .../domain/exception/NeedLoginException.kt | 8 ++++ 2 files changed, 50 insertions(+) create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt diff --git a/core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt b/core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt new file mode 100644 index 00000000..967d0d0d --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt @@ -0,0 +1,42 @@ +package com.stackknowledge.domain.exception + +class BadRequestException( + override val message: String? +) : RuntimeException() + +class UnauthorizedException( + override val message: String? +) : RuntimeException() + +class ForBiddenException( + override val message: String? +) : RuntimeException() + +class NotFoundException( + override val message: String? +) : RuntimeException() + +class NotAcceptableException( + override val message: String? +) : RuntimeException() + +class ConflictException( + override val message: String? +) : RuntimeException() + +class TimeOutException( + override val message: String? +) : RuntimeException() + +class ServerException( + override val message: String? +) : RuntimeException() + +class OtherException( + override val message: String?, + val code: Int +) : RuntimeException() + +class UnknownException( + override val message: String? +) : RuntimeException() \ No newline at end of file diff --git a/core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt b/core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt new file mode 100644 index 00000000..0a6e82bc --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt @@ -0,0 +1,8 @@ +package com.stackknowledge.domain.exception + +import java.io.IOException + +class NeedLoginException : IOException() { + override val message: String + get() = "토큰이 만료되었습니다. 다시 로그인 해 주세요" +} \ No newline at end of file From 221cd41c915da56cb43bf0f2c6008268d6cacbb4 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:12:42 +0900 Subject: [PATCH 10/91] :sparkles: :: add auth model --- .../model/remote/enumdatatype/Authority.kt | 6 ++++++ .../model/remote/request/auth/LoginRequest.kt | 7 +++++++ .../model/remote/response/auth/CodeResponse.kt | 9 +++++++++ .../model/remote/response/auth/LoginResponse.kt | 10 ++++++++++ 4 files changed, 32 insertions(+) create mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt create mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt create mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt create mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt b/core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt new file mode 100644 index 00000000..3db8e4ee --- /dev/null +++ b/core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt @@ -0,0 +1,6 @@ +package com.stackknowledge.model.remote.enumdatatype + +enum class Authority { + ROLE_TEACHER, + ROLE_STUDENT +} \ No newline at end of file diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt b/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt new file mode 100644 index 00000000..dbef445c --- /dev/null +++ b/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt @@ -0,0 +1,7 @@ +package com.stackknowledge.model.remote.request.auth + +import com.stackknowledge.model.remote.enumdatatype.Authority + +data class LoginRequest( + val code: String +) \ No newline at end of file diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt b/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt new file mode 100644 index 00000000..6ac5a534 --- /dev/null +++ b/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt @@ -0,0 +1,9 @@ +package com.stackknowledge.model.remote.response.auth + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class AuthCodeResponse( + @Json(name = "code") val code: String +) \ No newline at end of file diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt b/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt new file mode 100644 index 00000000..f1e652d5 --- /dev/null +++ b/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt @@ -0,0 +1,10 @@ +package com.stackknowledge.model.remote.response.auth + +import com.stackknowledge.model.remote.enumdatatype.Authority + +data class LoginResponse( + val accessToken: String, + val refreshToken: String, + val expiredAt: String, + val authority: Authority +) \ No newline at end of file From a08084ba326c53a09eee367ef230e7a2500640af Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:13:29 +0900 Subject: [PATCH 11/91] :sparkles: :: add auth network --- .../com/stackknowledge/network/api/AuthAPI.kt | 33 +++++++++ .../network/datasource/auth/AuthDataSource.kt | 18 +++++ .../datasource/auth/AuthDataSourceImpl.kt | 49 +++++++++++++ .../network/di/DataSourceModule.kt | 17 +++++ .../network/di/NetworkModule.kt | 62 ++++++++++++++++ .../network/exception/HttpException.kt | 42 +++++++++++ .../network/exception/NeedLoginException.kt | 8 +++ .../network/exception/NetworkException.kt | 6 ++ .../network/util/AuthInterceptor.kt | 72 +++++++++++++++++++ .../network/util/DataTimeFormatter.kt | 21 ++++++ .../network/util/StackKnowledgeApiHandler.kt | 58 +++++++++++++++ 11 files changed, 386 insertions(+) create mode 100644 core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt create mode 100644 core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt diff --git a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt new file mode 100644 index 00000000..cfbcf440 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt @@ -0,0 +1,33 @@ +package com.stackknowledge.network.api + +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import com.stackknowledge.network.BuildConfig +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.POST +import retrofit2.http.Path +import retrofit2.http.Query +import retrofit2.http.Url + +interface AuthAPI { + @POST("/auth/{role}") + suspend fun login( + @Body body: LoginRequest, + @Path("role") role: Authority + ): LoginResponse + + @DELETE("/auth") + suspend fun logout() + + @POST + suspend fun requestAuthCode( + @Url url: String = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount", + @Query("response_type") code: String, + @Query("redirect_uri") redirectUri: String = BuildConfig.REDIRECT_URI, + @Query("scope") scope: String = BuildConfig.FIREST_SCOPE + BuildConfig.SECOND_SCOPE, + @Query("client_id") clientId: String = BuildConfig.GOOGLE_CLIENT_ID + ): AuthCodeResponse +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt new file mode 100644 index 00000000..d862b393 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt @@ -0,0 +1,18 @@ +package com.stackknowledge.network.datasource.auth + +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import kotlinx.coroutines.flow.Flow + +interface AuthDataSource { + suspend fun login( + body: LoginRequest, + role: Authority + ): Flow + + suspend fun logout(): Flow + + suspend fun requestAuthCode(code: String): Flow +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt new file mode 100644 index 00000000..d777d984 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt @@ -0,0 +1,49 @@ +package com.stackknowledge.network.datasource.auth + +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import com.stackknowledge.network.api.AuthAPI +import com.stackknowledge.network.util.StackKnowledgeApiHandler +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import javax.inject.Inject + +class AuthDataSourceImpl @Inject constructor( + private val authAPI: AuthAPI +) : AuthDataSource { + override suspend fun login( + body: LoginRequest, + role: Authority + ): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { + authAPI.login( + body = body, + role = role + ) + } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) + + override suspend fun logout(): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { authAPI.logout() } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) + + override suspend fun requestAuthCode(code: String): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { authAPI.requestAuthCode(code = code) } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt b/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt new file mode 100644 index 00000000..f9db20b3 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt @@ -0,0 +1,17 @@ +package com.stackknowledge.network.di + +import com.stackknowledge.network.datasource.auth.AuthDataSource +import com.stackknowledge.network.datasource.auth.AuthDataSourceImpl +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +abstract class DataSourceModule { + @Binds + abstract fun bindAuthDataSource( + authDataSourceImpl: AuthDataSourceImpl + ): AuthDataSource +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt b/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt new file mode 100644 index 00000000..72cbae58 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt @@ -0,0 +1,62 @@ +package com.stackknowledge.network.di + +import android.util.Log +import com.stackknowledge.network.BuildConfig +import com.stackknowledge.network.api.AuthAPI +import com.stackknowledge.network.util.AuthInterceptor +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NetworkModule { + @Provides + fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = + HttpLoggingInterceptor { message -> Log.v("HTTP", message) } + .setLevel(HttpLoggingInterceptor.Level.BODY) + + @Provides + @Singleton + fun provideOkhttpClient( + httpLoggingInterceptor: HttpLoggingInterceptor, + authInterceptor: AuthInterceptor + ): OkHttpClient { + return OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .addInterceptor(httpLoggingInterceptor) + .addInterceptor(authInterceptor) + .build() + } + + @Provides + fun provideRetrofitInstance( + okHttpClient: OkHttpClient, + gsonConverterFactory: GsonConverterFactory + ): Retrofit { + return Retrofit.Builder() + .baseUrl(BuildConfig.BASE_URL) + .client(okHttpClient) + .addConverterFactory(gsonConverterFactory) + .build() + } + + @Provides + fun provideGsonConverterFactory(): GsonConverterFactory { + return GsonConverterFactory.create() + } + + @Provides + fun provideAuthAPI(retrofit: Retrofit): AuthAPI = + retrofit.create(AuthAPI::class.java) +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt new file mode 100644 index 00000000..e8e66a7e --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt @@ -0,0 +1,42 @@ +package com.stackknowledge.network.exception + +class BadRequestException( + override val message: String? +) : RuntimeException() + +class UnauthorizedException( + override val message: String? +) : RuntimeException() + +class ForBiddenException( + override val message: String? +) : RuntimeException() + +class NotFoundException( + override val message: String? +) : RuntimeException() + +class NotAcceptableException( + override val message: String? +) : RuntimeException() + +class ConflictException( + override val message: String? +) : RuntimeException() + +class TimeOutException( + override val message: String? +) : RuntimeException() + +class ServerException( + override val message: String? +) : RuntimeException() + +class OtherException( + override val message: String?, + val code: Int +) : RuntimeException() + +class UnknownException( + override val message: String? +) : RuntimeException() \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt new file mode 100644 index 00000000..709bb1c8 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt @@ -0,0 +1,8 @@ +package com.stackknowledge.network.exception + +import java.io.IOException + +class NeedLoginException : IOException() { + override val message: String + get() = "토큰이 만료되었습니다. 다시 로그인 해 주세요" +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt new file mode 100644 index 00000000..f81e8d59 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt @@ -0,0 +1,6 @@ +package com.stackknowledge.network.exception + +class NetworkException : RuntimeException() { + override val message: String + get() = "네트워크가 불안정합니다. 데이터나 와이파이 연결 상태를 확인해 주세요" +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt b/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt new file mode 100644 index 00000000..66b1743b --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt @@ -0,0 +1,72 @@ +package com.stackknowledge.network.util + +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.stackknowledge.network.BuildConfig +import com.stackknowledge.datastore.LocalAuthDataSource +import com.stackknowledge.network.exception.NeedLoginException +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody +import okhttp3.Response +import javax.inject.Inject + +class AuthInterceptor @Inject constructor( + private val dataSource: LocalAuthDataSource +): Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + val request = chain.request() + val builder = request.newBuilder() + val currentTime = System.currentTimeMillis().toLocalDateTime() + val ignorePath = listOf("/auth") + val ignoreMethod = listOf("POST") + val path = request.url.encodedPath + val method = request.method + + ignorePath.forEachIndexed { index, s -> + if (path.contains(s) && ignoreMethod[index] == method) + return chain.proceed(request) + } + + runBlocking { + val refreshTime = dataSource.getRefreshTime().first().replace("\"", "") + val accessTime = dataSource.getAccessTime().first().replace("\"", "") + + if (refreshTime == "") { + return@runBlocking + } + + if (currentTime.after(refreshTime.toDate())) { + throw NeedLoginException() + } + + // access 토큰 재 발급 + if (currentTime.after(accessTime.toDate())) { + val client = OkHttpClient() + val refreshRequest = Request.Builder() + .url(BuildConfig.BASE_URL + "/auth") + .patch(chain.request().body ?: RequestBody.create(null, byteArrayOf())) + .addHeader( + "Refresh-Token", + dataSource.getRefreshToken().first().replace("\"", "") + ) + .build() + val jsonParser = JsonParser() + val response = client.newCall(refreshRequest).execute() + if (response.isSuccessful) { + val token = jsonParser.parse(response.body!!.string()) as JsonObject + dataSource.setAccessToken(token["accessToken"].toString()) + dataSource.setRefreshToken(token["refreshToken"].toString()) + dataSource.setAccessTime(token["expiredAt"].toString()) + dataSource.setRefreshTime(token["expiredAt"].toString()) + } else throw NeedLoginException() + } + val accessToken = dataSource.getAccessToken().first().replace("\"", "") + builder.addHeader("Authorization", "Bearer $accessToken") + } + return chain.proceed(builder.build()) + } +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt b/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt new file mode 100644 index 00000000..30a53a6e --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt @@ -0,0 +1,21 @@ +package com.stackknowledge.network.util + +import android.annotation.SuppressLint +import com.stackknowledge.network.exception.NeedLoginException +import java.text.SimpleDateFormat +import java.util.* + +@SuppressLint("SimpleDateFormat") +fun String.toDate(): Date { + kotlin.runCatching { + SimpleDateFormat("yyyy-MM-dd`T`HH:mm:ss").parse(this)!! + }.onSuccess { + return it + } + throw NeedLoginException() +} + +@SuppressLint("SimpleDateFormat") +fun Long.toLocalDateTime(): Date { + return SimpleDateFormat("yyyy-MM-dd`T`HH:mm:ss").format(this).toDate() +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt b/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt new file mode 100644 index 00000000..1b6e7431 --- /dev/null +++ b/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt @@ -0,0 +1,58 @@ +package com.stackknowledge.network.util + +import com.stackknowledge.network.exception.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import java.lang.Exception +import java.net.SocketTimeoutException +import java.net.UnknownHostException + +class StackKnowledgeApiHandler { + private lateinit var httpRequest: suspend () -> T + + fun httpRequest(httpRequest: suspend () -> T) = + this.apply { this.httpRequest = httpRequest } + + suspend fun sendRequest(): T { + return try { + withContext(Dispatchers.IO) { + httpRequest.invoke() + } + } catch (e: HttpException) { + val message = e.message + throw when(e.code()) { + 400 -> BadRequestException( + message = message + ) + 401 -> UnauthorizedException( + message = message + ) + 403 -> ForBiddenException( + message = message + ) + 404 -> NotFoundException( + message = message + ) + 409 -> ConflictException( + message = message + ) + 500, 501, 502, 503 -> ServerException( + message = message + ) + else -> OtherException( + message = message, + code = e.code() + ) + } + } catch (e: SocketTimeoutException) { + throw TimeOutException(message = e.message) + } catch (e: UnknownHostException) { + throw NetworkException() + } catch (e: NeedLoginException) { + throw NeedLoginException() + } catch (e: Exception) { + throw UnknownException(message = e.message) + } + } +} \ No newline at end of file From 593b4785e212ddea505313f576355b9da9149a4a Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 13 May 2024 21:15:33 +0900 Subject: [PATCH 12/91] :sparkles: :: add login --- .../com/stackknowledge/login/LoginActivity.kt | 56 +++++++++++++++ .../com/stackknowledge/login/LoginScreen.kt | 21 ++++-- .../stackknowledge/login/RoleCheckScreen.kt | 45 ++++++++++++ ...kground.kt => StackKnowledgeBackground.kt} | 6 +- .../login/navigation/LoginNavigation.kt | 43 +++++++++++ .../login/viewmodel/AuthViewModel.kt | 72 +++++++++++++++++++ .../login/viewmodel/util/Event.kt | 59 +++++++++++++++ .../login/viewmodel/util/errorHandling.kt | 67 +++++++++++++++++ 8 files changed, 362 insertions(+), 7 deletions(-) create mode 100644 feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt create mode 100644 feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt rename feature/login/src/main/java/com/stackknowledge/login/background/{LoginBackground.kt => StackKnowledgeBackground.kt} (93%) create mode 100644 feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt create mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt create mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt create mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt new file mode 100644 index 00000000..b056f231 --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -0,0 +1,56 @@ +package com.stackknowledge.login + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.CompositionLocalProvider +import androidx.lifecycle.ViewModel +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.common.api.Scope +import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.viewmodel.AuthViewModel + +class LoginActivity : ComponentActivity() { + private val viewModel: AuthViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + intentData(intent.data) + + setContent { + LoginScreen( + googleLogin = { googleSignIn() } + ) + } + } + + private fun googleSignIn() { + //val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=http://localhost:3001/auth/login&scope=https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email&client_id=853689307201-a3q5ep5c2ld77rqblsg3svk78i7sr2oa.apps.googleusercontent.com" + val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.FIRST_SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + Log.d("google_login",url) + } + + private fun intentData(uri: Uri?) { + uri?.let { + val code = it.getQueryParameter("code") + if (!code.isNullOrBlank()) { + viewModel.requestAuthCode(code) + } else { + Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() + } + } + } +} diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 8ad39138..a464b64e 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -18,14 +18,26 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.button.GoogleButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.background.LoginBackground +import com.stackknowledge.login.background.StackKnowledgeBackground +import com.stackknowledge.login.navigation.loginRoute +import com.stackknowledge.login.viewmodel.AuthViewModel + +@Composable +fun LoginRoute( + // googleLogin: () -> Unit, + viewModel: AuthViewModel = hiltViewModel() +) { + LoginScreen() +} @Composable fun LoginScreen( - modifier: Modifier = Modifier + modifier: Modifier = Modifier, + googleLogin: () -> Unit = {} ) { StackKnowledgeAndroidTheme { colors, typography -> Surface { @@ -33,7 +45,7 @@ fun LoginScreen( modifier = modifier.fillMaxSize() ) { Box() { - LoginBackground() + StackKnowledgeBackground() Column( modifier = modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally @@ -59,7 +71,8 @@ fun LoginScreen( .padding(horizontal = 16.dp) ) { GoogleButton( - modifier = modifier.height(60.dp) + modifier = modifier.height(60.dp), + onClick = googleLogin ) } } diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt new file mode 100644 index 00000000..f1802603 --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -0,0 +1,45 @@ +package com.stackknowledge.login + +import androidx.compose.material3.Button +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import com.stackknowledge.login.viewmodel.AuthViewModel + +@Composable +fun RoleCheckRoute( + viewModel: AuthViewModel = hiltViewModel(), + studentCheck: () -> Unit, + teacherCheck: () -> Unit, +) { + RoleCheckScreen( + studentCheck = studentCheck, + teacherCheck = teacherCheck + ) +} + +@Composable +fun RoleCheckScreen( + modifier: Modifier = Modifier, + studentCheck: () -> Unit = {}, + teacherCheck: () -> Unit = {} +) { + Button( + onClick = { studentCheck() } + ) { + + } + + Button( + onClick = { teacherCheck() } + ) { + + } +} + +@Preview +@Composable +fun RoleCheckScreenPre() { + RoleCheckScreen() +} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt b/feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt similarity index 93% rename from feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt rename to feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt index b5578370..0d9fdcc1 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.stackknowledge.design_system.R @Composable -fun LoginBackground( +fun StackKnowledgeBackground( modifier: Modifier = Modifier ) { Column( @@ -43,6 +43,6 @@ fun LoginBackground( @Preview @Composable -fun LoginBackgroundPre() { - LoginBackground() +fun StackKnowledgeBackgroundPre() { + StackKnowledgeBackground() } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt new file mode 100644 index 00000000..12ff99dc --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -0,0 +1,43 @@ +package com.stackknowledge.login.navigation + +import android.content.Intent +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavOptions +import androidx.navigation.compose.composable +import com.stackknowledge.login.LoginActivity +import com.stackknowledge.login.LoginRoute +import com.stackknowledge.login.RoleCheckRoute +import com.stackknowledge.login.RoleCheckScreen + +const val loginRoute = "login_route" +const val roleCheckRoute = "role_check_route" + +fun NavController.navigateToLogin(navOptions: NavOptions? = null) { + this.navigate(loginRoute, navOptions) +} + +fun NavGraphBuilder.loginScreen() { + composable(route = loginRoute) { + LoginRoute() + } +} + +fun NavController.navigateToRoleCheck(navOptions: NavOptions? = null) { + this.navigate(roleCheckRoute, navOptions) +} + +fun NavGraphBuilder.roleCheckScreen( + studentCheck: () -> Unit, + teacherCheck: () -> Unit +) { + composable(route = roleCheckRoute) { + RoleCheckRoute( + studentCheck = studentCheck, + teacherCheck = teacherCheck + ) + } +} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt new file mode 100644 index 00000000..0a9845a1 --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -0,0 +1,72 @@ +package com.stackknowledge.login.viewmodel + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.compose.viewModel +import com.stackknowledge.domain.auth.LogoutUseCase +import com.stackknowledge.domain.auth.SaveTokenUseCase +import com.stackknowledge.domain.auth.LoginUseCase +import com.stackknowledge.domain.auth.RequestAuthCodeUseCase +import com.stackknowledge.login.viewmodel.util.Event +import com.stackknowledge.login.viewmodel.util.errorHandling +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.model.remote.response.auth.AuthCodeResponse +import com.stackknowledge.model.remote.response.auth.LoginResponse +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class AuthViewModel @Inject constructor( + private val loginUseCase: LoginUseCase, + private val logoutUseCase: LogoutUseCase, + private val saveTokenUseCase: SaveTokenUseCase, + private val requestAuthCodeUseCase: RequestAuthCodeUseCase +) : ViewModel() { + private val _saveTokenRequest = MutableLiveData>() + val saveTokenRequest: LiveData> get() = _saveTokenRequest + + private val _loginRequest = MutableLiveData>() + val loginRequest: LiveData> get() = _loginRequest + + private val _getAuthorityResponse = MutableLiveData>() + val getAuthority: LiveData> get() = _getAuthorityResponse + + private val _requestAuthCode = MutableLiveData>() + val requestAuthCode: LiveData> get() = _requestAuthCode + + fun login( + body: LoginRequest, + role: Authority + ) = viewModelScope.launch { + loginUseCase( + body = body, + role = role + ).onSuccess { + it.catch { remoteError -> + _loginRequest.value = remoteError.errorHandling() + }.collect { response -> + _loginRequest.value = Event.Success(data = response) + } + }.onFailure { + _loginRequest.value = it.errorHandling() + } + } + + fun requestAuthCode(code: String) = viewModelScope.launch { + requestAuthCodeUseCase(code = code) + .onSuccess { + it.catch { remoteError -> + _requestAuthCode.value = remoteError.errorHandling() + }.collect { response -> + _requestAuthCode.value = Event.Success(data = response) + } + }.onFailure { + _requestAuthCode.value = it.errorHandling() + } + } +} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt new file mode 100644 index 00000000..93bcd407 --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt @@ -0,0 +1,59 @@ +package com.stackknowledge.login.viewmodel.util + +sealed class Event( + val data: T? = null +) { + + object Loading : Event() + + /** + * 성공 + */ + class Success(data: T? = null) : Event(data = data) + + /** + * 400번 요청이 올바르지 않은 경우 + */ + object BadRequest : Event() + + /** + * 401번 비인증 요청 + */ + object Unauthorized : Event() + + /** + * 403번 권한이 없음 + */ + object ForBidden : Event() + + /** + * 404 찾을 수 없는 경우 + */ + object NotFound : Event() + + /** + * 406 맞는 규격이 없는 경우 + */ + object NotAcceptable : Event() + + /** + * 408 요청이 너무 오래 걸리는 경우 + */ + object TimeOut : Event() + + /** + * 409 권한이 없을 때 + */ + object Conflict : Event() + + /** + * 50X 서버에러 + */ + object Server : Event() + + /** + * 예상치 못한 에러 + */ + object UnKnown : Event() + +} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt new file mode 100644 index 00000000..c923e02a --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt @@ -0,0 +1,67 @@ +package com.stackknowledge.login.viewmodel.util + +import android.util.Log +import com.stackknowledge.domain.exception.* + +suspend fun Throwable.errorHandling( + badRequestAction: suspend () -> Unit = {}, + unauthorizedAction: suspend () -> Unit = {}, + forBiddenAction: suspend () -> Unit = {}, + notFoundAction: suspend () -> Unit = {}, + notAcceptableAction: suspend () -> Unit = {}, + timeOutAction: suspend () -> Unit = {}, + conflictAction: suspend () -> Unit = {}, + serverAction: suspend () -> Unit = {}, + unknownAction: suspend () -> Unit = {}, +): Event = + when (this) { + is BadRequestException -> { + errorLog("BadRequestException", message) + badRequestAction() + Event.BadRequest + } + is UnauthorizedException, is NeedLoginException -> { + errorLog("UnauthorizedException", message) + unauthorizedAction() + Event.Unauthorized + } + is ForBiddenException -> { + errorLog("ForBiddenException", message) + forBiddenAction() + Event.ForBidden + } + is NotFoundException -> { + errorLog("NotFoundException", message) + notFoundAction() + Event.NotFound + } + is NotAcceptableException -> { + errorLog("NotAcceptableException", message) + notAcceptableAction() + Event.NotAcceptable + } + is TimeOutException -> { + errorLog("TimeOutException", message) + timeOutAction() + Event.TimeOut + } + is ConflictException -> { + errorLog("ConflictException", message) + conflictAction() + Event.Conflict + } + is ServerException -> { + errorLog("ServerException", message) + serverAction() + Event.Server + } + else -> { + errorLog("UnKnownException", message) + unknownAction() + Event.UnKnown + } + } + +private fun errorLog(tag: String, msg: String?) { + Log.d("ErrorHandling-$tag", msg ?: "알 수 없는 오류") +} \ No newline at end of file From 6225c342c3bc7591bc3b1ee2915c7a52253a5729 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Tue, 14 May 2024 11:08:09 +0900 Subject: [PATCH 13/91] =?UTF-8?q?:memo:=20::=20add=20hilt=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/stackknowledge/StackKnowledgeApplication.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt b/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt index 0ad4046a..5f9f76c4 100644 --- a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt +++ b/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt @@ -4,4 +4,4 @@ import android.app.Application import dagger.hilt.android.HiltAndroidApp @HiltAndroidApp -class StackKnowledgeApplication : Application() {} \ No newline at end of file +class StackKnowledgeApplication : Application() \ No newline at end of file From 28e393417fcfc50004bde6f2c042f9119c3534cd Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Tue, 14 May 2024 14:07:15 +0900 Subject: [PATCH 14/91] =?UTF-8?q?:recycler:=20::=20scope=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/stackknowledge/login/LoginActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index b056f231..61042bf8 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -37,7 +37,7 @@ class LoginActivity : ComponentActivity() { private fun googleSignIn() { //val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=http://localhost:3001/auth/login&scope=https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email&client_id=853689307201-a3q5ep5c2ld77rqblsg3svk78i7sr2oa.apps.googleusercontent.com" - val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.FIRST_SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" + val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) startActivity(intent) Log.d("google_login",url) From 74d669bc8a2c8658e9845ace602a5fb44ac58d0b Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Thu, 16 May 2024 01:20:23 +0900 Subject: [PATCH 15/91] :recycle: :: modify url scope --- .../src/main/java/com/stackknowledge/network/api/AuthAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt index cfbcf440..6ee72641 100644 --- a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt +++ b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt @@ -27,7 +27,7 @@ interface AuthAPI { @Url url: String = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount", @Query("response_type") code: String, @Query("redirect_uri") redirectUri: String = BuildConfig.REDIRECT_URI, - @Query("scope") scope: String = BuildConfig.FIREST_SCOPE + BuildConfig.SECOND_SCOPE, + @Query("scope") scope: String = BuildConfig.SCOPE, @Query("client_id") clientId: String = BuildConfig.GOOGLE_CLIENT_ID ): AuthCodeResponse } \ No newline at end of file From 818ebc1bbea1ae649d0873b723a43dde4ba93391 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 24 Jun 2024 17:06:49 +0900 Subject: [PATCH 16/91] :memo: :: add common module --- .../com/stackknowledge/domain/auth/LoginUseCase.kt | 2 +- .../domain/auth/RequestAuthCodeUseCase.kt | 12 ------------ settings.gradle.kts | 1 + 3 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt index c0ff51ca..614447d7 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt @@ -10,7 +10,7 @@ class LoginUseCase @Inject constructor( ) { suspend operator fun invoke( body: LoginRequest, - role: Authority + role: String ) = runCatching { authRepository.login( body = body, diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt deleted file mode 100644 index 369febe4..00000000 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/RequestAuthCodeUseCase.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.stackknowledge.domain.auth - -import com.stackknowledge.data.repository.auth.AuthRepository -import javax.inject.Inject - -class RequestAuthCodeUseCase @Inject constructor( - private val authRepository: AuthRepository -) { - suspend operator fun invoke(code: String) = runCatching { - authRepository.requestAuthCode(code = code) - } -} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index d09760bb..219dc1a4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,6 +17,7 @@ dependencyResolutionManagement { rootProject.name = "StackKnowledge" include(":app") +include(":core:common") include(":core:data") include(":core:datastore") include(":core:design-system") From 5f968cbe6d1e5720ed7e63197a619d65daafdf51 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 24 Jun 2024 17:07:22 +0900 Subject: [PATCH 17/91] :memo: :: modify intent filtter --- app/src/main/AndroidManifest.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 26442e91..bb3f391e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -34,8 +34,10 @@ + android:scheme="http" + android:host="localhost" + android:port="3001" + android:pathPrefix="/auth/login"/> From 927c907d67a02d9b388e05e937bef70c7b82581a Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 24 Jun 2024 17:14:02 +0900 Subject: [PATCH 18/91] :memo: :: modify files --- .../navigation/StackKnowledgeNavHost.kt | 8 +--- .../stackknowledge/ui/StackKnowledgeApp.kt | 2 +- .../data/repository/auth/AuthRepository.kt | 5 +- .../repository/auth/AuthRepositoryImpl.kt | 7 +-- .../component/button/StackKnowledgeButton.kt | 2 +- .../src/main/res/values/strings.xml | 2 + .../remote/response/auth/CodeResponse.kt | 9 ---- .../com/stackknowledge/network/api/AuthAPI.kt | 13 +----- .../network/datasource/auth/AuthDataSource.kt | 5 +- .../datasource/auth/AuthDataSourceImpl.kt | 11 +---- .../network/util/AuthInterceptor.kt | 46 ++++++++++--------- .../network/util/DataTimeFormatter.kt | 29 ++++++------ .../com/stackknowledge/login/LoginActivity.kt | 34 ++++++++------ .../stackknowledge/login/RoleCheckScreen.kt | 45 ------------------ .../login/navigation/LoginNavigation.kt | 19 -------- .../login/viewmodel/AuthViewModel.kt | 36 +++------------ 16 files changed, 74 insertions(+), 199 deletions(-) delete mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt delete mode 100644 feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt diff --git a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt index 30783267..f8858785 100644 --- a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt @@ -9,8 +9,6 @@ import com.stackknowledge.login.LoginActivity import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.login.navigation.loginScreen import com.stackknowledge.login.navigation.navigateToLogin -import com.stackknowledge.login.navigation.roleCheckRoute -import com.stackknowledge.login.navigation.roleCheckScreen import com.stackknowledge.ui.StackKnowledgeAppState @Composable @@ -18,7 +16,7 @@ fun StackKnowledgeNavHost( appState: StackKnowledgeAppState, startLogin: () -> Unit, modifier: Modifier = Modifier, - startDestination: String = roleCheckRoute, + startDestination: String, ) { val navController = appState.navController @@ -28,10 +26,6 @@ fun StackKnowledgeNavHost( startDestination = startDestination, modifier = modifier ) { - roleCheckScreen( - studentCheck = { startLogin() }, - teacherCheck = { startLogin() } - ) loginScreen( ) diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt index 619110b9..92b9a26b 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt @@ -14,6 +14,6 @@ fun StackKnowledgeApp( startLogin:() -> Unit ) { StackKnowledgeAndroidTheme { _, _ -> - StackKnowledgeNavHost(appState = appState, startLogin = { startLogin() }) //startDestination = ) // <- 이부분도 startDestination 스크린 작업 후 추가 + StackKnowledgeNavHost(appState = appState, startLogin = { }, startDestination = "") // <- 이부분도 startDestination 스크린 작업 후 추가 } } \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt index 14ac0b21..6c96f123 100644 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt @@ -2,19 +2,16 @@ package com.stackknowledge.data.repository.auth import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse import kotlinx.coroutines.flow.Flow interface AuthRepository { suspend fun login( body: LoginRequest, - role: Authority + role: String ): Flow suspend fun saveToken(token: LoginResponse) suspend fun logout(): Flow - - suspend fun requestAuthCode(code: String): Flow } \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt index 0698942a..b22dc911 100644 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt @@ -3,7 +3,6 @@ package com.stackknowledge.data.repository.auth import com.stackknowledge.datastore.LocalAuthDataSource import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse import com.stackknowledge.network.datasource.auth.AuthDataSource import kotlinx.coroutines.flow.Flow @@ -15,7 +14,7 @@ class AuthRepositoryImpl @Inject constructor( ): AuthRepository { override suspend fun login( body: LoginRequest, - role: Authority + role: String ): Flow { return authDataSource.login( body = body, @@ -36,8 +35,4 @@ class AuthRepositoryImpl @Inject constructor( override suspend fun logout(): Flow { return authDataSource.logout() } - - override suspend fun requestAuthCode(code: String): Flow { - return authDataSource.requestAuthCode(code = code) - } } \ No newline at end of file diff --git a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt index 01d1d834..e3d12850 100644 --- a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt +++ b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt @@ -21,7 +21,7 @@ fun StackKnowledgeButton( ) { StackKnowledgeAndroidTheme { colors, typography -> Button( - onClick = { /*TODO*/ }, + onClick = {}, modifier = modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(10.dp)) diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index abd22a10..9a2ff65e 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -31,4 +31,6 @@ 만들기 상점 사용자가 학생인지\n선생님인지 선택해주세요. + 학생 + 선생님 \ No newline at end of file diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt b/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt deleted file mode 100644 index 6ac5a534..00000000 --- a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/CodeResponse.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.stackknowledge.model.remote.response.auth - -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass - -@JsonClass(generateAdapter = true) -data class AuthCodeResponse( - @Json(name = "code") val code: String -) \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt index 6ee72641..a3e78f3f 100644 --- a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt +++ b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt @@ -2,9 +2,7 @@ package com.stackknowledge.network.api import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse -import com.stackknowledge.network.BuildConfig import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.POST @@ -16,18 +14,9 @@ interface AuthAPI { @POST("/auth/{role}") suspend fun login( @Body body: LoginRequest, - @Path("role") role: Authority + @Path("role") role: String ): LoginResponse @DELETE("/auth") suspend fun logout() - - @POST - suspend fun requestAuthCode( - @Url url: String = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount", - @Query("response_type") code: String, - @Query("redirect_uri") redirectUri: String = BuildConfig.REDIRECT_URI, - @Query("scope") scope: String = BuildConfig.SCOPE, - @Query("client_id") clientId: String = BuildConfig.GOOGLE_CLIENT_ID - ): AuthCodeResponse } \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt index d862b393..8fa85a88 100644 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt @@ -2,17 +2,14 @@ package com.stackknowledge.network.datasource.auth import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse import kotlinx.coroutines.flow.Flow interface AuthDataSource { suspend fun login( body: LoginRequest, - role: Authority + role: String ): Flow suspend fun logout(): Flow - - suspend fun requestAuthCode(code: String): Flow } \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt index d777d984..4a1b2071 100644 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt @@ -2,7 +2,6 @@ package com.stackknowledge.network.datasource.auth import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse import com.stackknowledge.network.api.AuthAPI import com.stackknowledge.network.util.StackKnowledgeApiHandler @@ -17,7 +16,7 @@ class AuthDataSourceImpl @Inject constructor( ) : AuthDataSource { override suspend fun login( body: LoginRequest, - role: Authority + role: String ): Flow = flow { emit( StackKnowledgeApiHandler() @@ -38,12 +37,4 @@ class AuthDataSourceImpl @Inject constructor( .sendRequest() ) }.flowOn(Dispatchers.IO) - - override suspend fun requestAuthCode(code: String): Flow = flow { - emit( - StackKnowledgeApiHandler() - .httpRequest { authAPI.requestAuthCode(code = code) } - .sendRequest() - ) - }.flowOn(Dispatchers.IO) } \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt b/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt index 66b1743b..1d89696d 100644 --- a/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt +++ b/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt @@ -39,30 +39,34 @@ class AuthInterceptor @Inject constructor( return@runBlocking } - if (currentTime.after(refreshTime.toDate())) { - throw NeedLoginException() + if (currentTime != null) { + if (currentTime.isAfter(refreshTime.toLocalDateTime())) { + throw NeedLoginException() + } } // access 토큰 재 발급 - if (currentTime.after(accessTime.toDate())) { - val client = OkHttpClient() - val refreshRequest = Request.Builder() - .url(BuildConfig.BASE_URL + "/auth") - .patch(chain.request().body ?: RequestBody.create(null, byteArrayOf())) - .addHeader( - "Refresh-Token", - dataSource.getRefreshToken().first().replace("\"", "") - ) - .build() - val jsonParser = JsonParser() - val response = client.newCall(refreshRequest).execute() - if (response.isSuccessful) { - val token = jsonParser.parse(response.body!!.string()) as JsonObject - dataSource.setAccessToken(token["accessToken"].toString()) - dataSource.setRefreshToken(token["refreshToken"].toString()) - dataSource.setAccessTime(token["expiredAt"].toString()) - dataSource.setRefreshTime(token["expiredAt"].toString()) - } else throw NeedLoginException() + if (currentTime != null) { + if (currentTime.isAfter(accessTime.toLocalDateTime())) { + val client = OkHttpClient() + val refreshRequest = Request.Builder() + .url(BuildConfig.BASE_URL + "/auth") + .patch(chain.request().body ?: RequestBody.create(null, byteArrayOf())) + .addHeader( + "Refresh-Token", + dataSource.getRefreshToken().first().replace("\"", "") + ) + .build() + val jsonParser = JsonParser() + val response = client.newCall(refreshRequest).execute() + if (response.isSuccessful) { + val token = jsonParser.parse(response.body!!.string()) as JsonObject + dataSource.setAccessToken(token["accessToken"].toString()) + dataSource.setRefreshToken(token["refreshToken"].toString()) + dataSource.setAccessTime(token["expiredAt"].toString()) + dataSource.setRefreshTime(token["expiredAt"].toString()) + } else throw NeedLoginException() + } } val accessToken = dataSource.getAccessToken().first().replace("\"", "") builder.addHeader("Authorization", "Bearer $accessToken") diff --git a/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt b/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt index 30a53a6e..c07a2311 100644 --- a/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt +++ b/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt @@ -1,21 +1,18 @@ package com.stackknowledge.network.util -import android.annotation.SuppressLint -import com.stackknowledge.network.exception.NeedLoginException -import java.text.SimpleDateFormat -import java.util.* +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeParseException -@SuppressLint("SimpleDateFormat") -fun String.toDate(): Date { - kotlin.runCatching { - SimpleDateFormat("yyyy-MM-dd`T`HH:mm:ss").parse(this)!! - }.onSuccess { - return it +fun Any?.toLocalDateTime(): LocalDateTime? { + val dateString = this?.toString() + if (dateString != null) { + return try { + LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-d'T'HH:mm:ss")) + } catch (e: DateTimeParseException) { + e.printStackTrace() + null + } } - throw NeedLoginException() -} - -@SuppressLint("SimpleDateFormat") -fun Long.toLocalDateTime(): Date { - return SimpleDateFormat("yyyy-MM-dd`T`HH:mm:ss").format(this).toDate() + return null } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index 61042bf8..fa8572de 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -10,47 +10,51 @@ import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels -import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass -import androidx.compose.runtime.CompositionLocalProvider -import androidx.lifecycle.ViewModel import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInClient import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.auth.api.signin.GoogleSignInResult +import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.Scope import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.navigation.roleCheckRoute import com.stackknowledge.login.viewmodel.AuthViewModel +import com.stackknowledge.model.remote.enumdatatype.Authority +import com.stackknowledge.model.remote.request.auth.LoginRequest +import dagger.hilt.android.AndroidEntryPoint +@AndroidEntryPoint class LoginActivity : ComponentActivity() { private val viewModel: AuthViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - intentData(intent.data) - setContent { LoginScreen( googleLogin = { googleSignIn() } ) } + + intentData(intent.data) } private fun googleSignIn() { - //val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=http://localhost:3001/auth/login&scope=https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email&client_id=853689307201-a3q5ep5c2ld77rqblsg3svk78i7sr2oa.apps.googleusercontent.com" - val url = "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" + val url = + "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) startActivity(intent) - Log.d("google_login",url) } private fun intentData(uri: Uri?) { - uri?.let { - val code = it.getQueryParameter("code") - if (!code.isNullOrBlank()) { - viewModel.requestAuthCode(code) - } else { - Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() - } + val code = uri?.getQueryParameter("code") + if (!code.isNullOrBlank()) { + viewModel.login( + body = LoginRequest(code), + role = "student" + ) + } else { + Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() } } } diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt deleted file mode 100644 index f1802603..00000000 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.stackknowledge.login - -import androidx.compose.material3.Button -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.navigation.compose.hiltViewModel -import com.stackknowledge.login.viewmodel.AuthViewModel - -@Composable -fun RoleCheckRoute( - viewModel: AuthViewModel = hiltViewModel(), - studentCheck: () -> Unit, - teacherCheck: () -> Unit, -) { - RoleCheckScreen( - studentCheck = studentCheck, - teacherCheck = teacherCheck - ) -} - -@Composable -fun RoleCheckScreen( - modifier: Modifier = Modifier, - studentCheck: () -> Unit = {}, - teacherCheck: () -> Unit = {} -) { - Button( - onClick = { studentCheck() } - ) { - - } - - Button( - onClick = { teacherCheck() } - ) { - - } -} - -@Preview -@Composable -fun RoleCheckScreenPre() { - RoleCheckScreen() -} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index 12ff99dc..e2e3c1f4 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -10,11 +10,8 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.login.LoginActivity import com.stackknowledge.login.LoginRoute -import com.stackknowledge.login.RoleCheckRoute -import com.stackknowledge.login.RoleCheckScreen const val loginRoute = "login_route" -const val roleCheckRoute = "role_check_route" fun NavController.navigateToLogin(navOptions: NavOptions? = null) { this.navigate(loginRoute, navOptions) @@ -24,20 +21,4 @@ fun NavGraphBuilder.loginScreen() { composable(route = loginRoute) { LoginRoute() } -} - -fun NavController.navigateToRoleCheck(navOptions: NavOptions? = null) { - this.navigate(roleCheckRoute, navOptions) -} - -fun NavGraphBuilder.roleCheckScreen( - studentCheck: () -> Unit, - teacherCheck: () -> Unit -) { - composable(route = roleCheckRoute) { - RoleCheckRoute( - studentCheck = studentCheck, - teacherCheck = teacherCheck - ) - } } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index 0a9845a1..bb7cb98f 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -4,18 +4,16 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import androidx.lifecycle.viewmodel.compose.viewModel import com.stackknowledge.domain.auth.LogoutUseCase import com.stackknowledge.domain.auth.SaveTokenUseCase import com.stackknowledge.domain.auth.LoginUseCase -import com.stackknowledge.domain.auth.RequestAuthCodeUseCase import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.login.viewmodel.util.errorHandling -import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.AuthCodeResponse import com.stackknowledge.model.remote.response.auth.LoginResponse import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import javax.inject.Inject @@ -25,23 +23,16 @@ class AuthViewModel @Inject constructor( private val loginUseCase: LoginUseCase, private val logoutUseCase: LogoutUseCase, private val saveTokenUseCase: SaveTokenUseCase, - private val requestAuthCodeUseCase: RequestAuthCodeUseCase ) : ViewModel() { - private val _saveTokenRequest = MutableLiveData>() - val saveTokenRequest: LiveData> get() = _saveTokenRequest + private val _saveTokenRequest = MutableStateFlow>(Event.Loading) + val saveTokenRequest = _saveTokenRequest.asStateFlow() - private val _loginRequest = MutableLiveData>() - val loginRequest: LiveData> get() = _loginRequest - - private val _getAuthorityResponse = MutableLiveData>() - val getAuthority: LiveData> get() = _getAuthorityResponse - - private val _requestAuthCode = MutableLiveData>() - val requestAuthCode: LiveData> get() = _requestAuthCode + private val _loginRequest = MutableStateFlow>(Event.Loading) + val loginRequest = _loginRequest.asStateFlow() fun login( body: LoginRequest, - role: Authority + role: String ) = viewModelScope.launch { loginUseCase( body = body, @@ -56,17 +47,4 @@ class AuthViewModel @Inject constructor( _loginRequest.value = it.errorHandling() } } - - fun requestAuthCode(code: String) = viewModelScope.launch { - requestAuthCodeUseCase(code = code) - .onSuccess { - it.catch { remoteError -> - _requestAuthCode.value = remoteError.errorHandling() - }.collect { response -> - _requestAuthCode.value = Event.Success(data = response) - } - }.onFailure { - _requestAuthCode.value = it.errorHandling() - } - } } \ No newline at end of file From 85a5da6ff4e9594ea0caeccd9292616c88dfef2f Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 24 Jun 2024 17:14:34 +0900 Subject: [PATCH 19/91] :fire: :: delete import --- .../src/main/java/com/stackknowledge/login/LoginActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index fa8572de..f0234296 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -17,7 +17,6 @@ import com.google.android.gms.auth.api.signin.GoogleSignInResult import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.Scope import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.navigation.roleCheckRoute import com.stackknowledge.login.viewmodel.AuthViewModel import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest From 0bce90f8ba331c1aa2a392fbe4364e7581957db3 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:35:33 +0900 Subject: [PATCH 20/91] :memo: :: add role check --- .../java/com/stackknowledge/MainActivity.kt | 18 +++++++++++------- .../navigation/StackKnowledgeNavHost.kt | 11 ++++++++++- .../com/stackknowledge/ui/StackKnowledgeApp.kt | 11 +++++++++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/stackknowledge/MainActivity.kt b/app/src/main/java/com/stackknowledge/MainActivity.kt index 7fe08abb..12f9296a 100644 --- a/app/src/main/java/com/stackknowledge/MainActivity.kt +++ b/app/src/main/java/com/stackknowledge/MainActivity.kt @@ -4,16 +4,21 @@ import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.activity.viewModels import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.LoginActivity +import com.stackknowledge.login.viewmodel.AuthViewModel import com.stackknowledge.ui.StackKnowledgeApp import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : ComponentActivity() { + private var isStudent = false + private var isTeacher = false + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -22,7 +27,9 @@ class MainActivity : ComponentActivity() { StackKnowledgeAndroidTheme { _, _ -> StackKnowledgeApp( windowSizeClass = calculateWindowSizeClass(this@MainActivity), - startLogin = { startLogin() } + startLogin = { startLogin() }, + isStudent = { isStudent = it }, + isTeacher = { isTeacher = it }, ) } } @@ -30,11 +37,8 @@ class MainActivity : ComponentActivity() { } private fun startLogin() { - startActivity( - Intent( - this, - LoginActivity::class.java - ) - ) + val intent = Intent(this, LoginActivity::class.java) + intent.putExtra("isStudent", isStudent) + startActivity(intent) } } diff --git a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt index f8858785..bdd6bcf8 100644 --- a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt @@ -9,6 +9,8 @@ import com.stackknowledge.login.LoginActivity import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.login.navigation.loginScreen import com.stackknowledge.login.navigation.navigateToLogin +import com.stackknowledge.login.navigation.roleCheckRoute +import com.stackknowledge.login.navigation.roleCheckScreen import com.stackknowledge.ui.StackKnowledgeAppState @Composable @@ -16,7 +18,9 @@ fun StackKnowledgeNavHost( appState: StackKnowledgeAppState, startLogin: () -> Unit, modifier: Modifier = Modifier, - startDestination: String, + startDestination: String = roleCheckRoute, + isStudent: (Boolean) -> Unit, + isTeacher: (Boolean) -> Unit, ) { val navController = appState.navController @@ -26,6 +30,11 @@ fun StackKnowledgeNavHost( startDestination = startDestination, modifier = modifier ) { + roleCheckScreen( + navigateToLogin = startLogin, + isStudent = isStudent, + isTeacher = isTeacher, + ) loginScreen( ) diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt index 92b9a26b..ef7787ae 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt @@ -11,9 +11,16 @@ fun StackKnowledgeApp( appState: StackKnowledgeAppState = rememberStackKnowledgeAppState( windowSizeClass = windowSizeClass ), - startLogin:() -> Unit + startLogin:() -> Unit, + isStudent: (Boolean) -> Unit, + isTeacher: (Boolean) -> Unit, ) { StackKnowledgeAndroidTheme { _, _ -> - StackKnowledgeNavHost(appState = appState, startLogin = { }, startDestination = "") // <- 이부분도 startDestination 스크린 작업 후 추가 + StackKnowledgeNavHost( + appState = appState, + startLogin = { startLogin() }, + isStudent = isStudent, + isTeacher = isTeacher, + ) //startDestination = ) // <- 이부분도 startDestination 스크린 작업 후 추가 } } \ No newline at end of file From a7248c0ebd8107c79fa0b08d029e4175199b658a Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:36:00 +0900 Subject: [PATCH 21/91] :memo: :: add common module --- core/common/consumer-rules.pro | 0 core/common/proguard-rules.pro | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 core/common/consumer-rules.pro create mode 100644 core/common/proguard-rules.pro diff --git a/core/common/consumer-rules.pro b/core/common/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/core/common/proguard-rules.pro b/core/common/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/core/common/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 From bb69cd2117cc01ab85e1eee0af87472d01824564 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:37:46 +0900 Subject: [PATCH 22/91] =?UTF-8?q?:memo:=20::=20login=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=20=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../data/repository/auth/AuthRepository.kt | 7 +++++-- .../repository/auth/AuthRepositoryImpl.kt | 14 +++++++------ ...LoginUseCase.kt => LoginStudentUseCase.kt} | 7 ++----- .../domain/auth/LoginTeacherUseCase.kt | 17 +++++++++++++++ .../com/stackknowledge/network/api/AuthAPI.kt | 10 ++++++--- .../network/datasource/auth/AuthDataSource.kt | 7 +++++-- .../datasource/auth/AuthDataSourceImpl.kt | 21 +++++++++++++------ 7 files changed, 59 insertions(+), 24 deletions(-) rename core/domain/src/main/java/com/stackknowledge/domain/auth/{LoginUseCase.kt => LoginStudentUseCase.kt} (67%) create mode 100644 core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt index 6c96f123..5544fc7b 100644 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt @@ -6,9 +6,12 @@ import com.stackknowledge.model.remote.response.auth.LoginResponse import kotlinx.coroutines.flow.Flow interface AuthRepository { - suspend fun login( + suspend fun loginStudent( + body: LoginRequest, + ): Flow + + suspend fun loginTeacher( body: LoginRequest, - role: String ): Flow suspend fun saveToken(token: LoginResponse) diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt index b22dc911..d0cc435a 100644 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt @@ -12,13 +12,15 @@ class AuthRepositoryImpl @Inject constructor( private val authDataSource: AuthDataSource, private val localDataSource: LocalAuthDataSource ): AuthRepository { - override suspend fun login( - body: LoginRequest, - role: String - ): Flow { - return authDataSource.login( + override suspend fun loginStudent(body: LoginRequest): Flow { + return authDataSource.loginStudent( + body = body, + ) + } + + override suspend fun loginTeacher(body: LoginRequest): Flow { + return authDataSource.loginTeacher( body = body, - role = role ) } diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt similarity index 67% rename from core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt rename to core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt index 614447d7..3fa37778 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginUseCase.kt +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt @@ -1,20 +1,17 @@ package com.stackknowledge.domain.auth import com.stackknowledge.data.repository.auth.AuthRepository -import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest import javax.inject.Inject -class LoginUseCase @Inject constructor( +class LoginStudentUseCase @Inject constructor( private val authRepository: AuthRepository ) { suspend operator fun invoke( body: LoginRequest, - role: String ) = runCatching { - authRepository.login( + authRepository.loginStudent( body = body, - role = role ) } } \ No newline at end of file diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt new file mode 100644 index 00000000..bdafb7ac --- /dev/null +++ b/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt @@ -0,0 +1,17 @@ +package com.stackknowledge.domain.auth + +import com.stackknowledge.data.repository.auth.AuthRepository +import com.stackknowledge.model.remote.request.auth.LoginRequest +import javax.inject.Inject + +class LoginTeacherUseCase @Inject constructor( + private val authRepository: AuthRepository +) { + suspend operator fun invoke( + body: LoginRequest, + ) = runCatching { + authRepository.loginTeacher( + body = body, + ) + } +} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt index a3e78f3f..fef629d1 100644 --- a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt +++ b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt @@ -11,10 +11,14 @@ import retrofit2.http.Query import retrofit2.http.Url interface AuthAPI { - @POST("/auth/{role}") - suspend fun login( + @POST("/auth/student") + suspend fun loginStudent( + @Body body: LoginRequest, + ): LoginResponse + + @POST("/auth/teacher") + suspend fun loginTeacher( @Body body: LoginRequest, - @Path("role") role: String ): LoginResponse @DELETE("/auth") diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt index 8fa85a88..fe1fa977 100644 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt @@ -6,9 +6,12 @@ import com.stackknowledge.model.remote.response.auth.LoginResponse import kotlinx.coroutines.flow.Flow interface AuthDataSource { - suspend fun login( + suspend fun loginStudent( + body: LoginRequest, + ): Flow + + suspend fun loginTeacher( body: LoginRequest, - role: String ): Flow suspend fun logout(): Flow diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt index 4a1b2071..c7d06dd3 100644 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt +++ b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt @@ -9,21 +9,30 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import java.util.Stack import javax.inject.Inject class AuthDataSourceImpl @Inject constructor( private val authAPI: AuthAPI ) : AuthDataSource { - override suspend fun login( - body: LoginRequest, - role: String - ): Flow = flow { + override suspend fun loginStudent(body: LoginRequest): Flow = flow { emit( StackKnowledgeApiHandler() .httpRequest { - authAPI.login( + authAPI.loginStudent( + body = body, + ) + } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) + + override suspend fun loginTeacher(body: LoginRequest): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { + authAPI.loginTeacher( body = body, - role = role ) } .sendRequest() From 88b33e783b47ffbe5e5d5c6348d83dc574da1e20 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:38:16 +0900 Subject: [PATCH 23/91] :lipstick: :: add button onclick --- .../design_system/component/button/StackKnowledgeButton.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt index e3d12850..2f712538 100644 --- a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt +++ b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt @@ -17,11 +17,12 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme @Composable fun StackKnowledgeButton( modifier: Modifier = Modifier, + onClick: () -> Unit = {}, text: String, ) { StackKnowledgeAndroidTheme { colors, typography -> Button( - onClick = {}, + onClick = { onClick() }, modifier = modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(10.dp)) From cbaced332a7787f658394bbf2cd02f9b382f1260 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:38:37 +0900 Subject: [PATCH 24/91] :memo: :: add strings --- core/design-system/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 9a2ff65e..72f66023 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -30,7 +30,7 @@ 채점 만들기 상점 - 사용자가 학생인지\n선생님인지 선택해주세요. + 사용자가 학생인지\n선생님인지 선택해주세요. 학생 선생님 \ No newline at end of file From 50d1bc2b09eb7a3eec7b13e71b90f626604d7968 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:39:44 +0900 Subject: [PATCH 25/91] :listick: :: publishing roleCheckScreen --- .../stackknowledge/login/RoleCheckScreen.kt | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt new file mode 100644 index 00000000..3d33b13c --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -0,0 +1,133 @@ +package com.stackknowledge.login + +import android.util.Log +import androidx.activity.ComponentActivity +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import com.stackknowledge.design_system.R +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +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 androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.stackknowledge.design_system.component.button.StackKnowledgeButton +import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.background.LoginBackground +import com.stackknowledge.login.viewmodel.AuthViewModel +import com.stackknowledge.login.viewmodel.util.Event + +@Composable +fun RoleCheckRoute( + navigateToLogin: () -> Unit, + isStudent: (Boolean) -> Unit, + isTeacher: (Boolean) -> Unit, + viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), +) { + RoleCheckScreen( + navigateToLogin = navigateToLogin, + viewModel = viewModel, + isStudent = isStudent, + isTeacher = isTeacher, + ) +} + +@Composable +fun RoleCheckScreen( + modifier: Modifier = Modifier, + viewModel: AuthViewModel, + isStudent: (Boolean) -> Unit = {}, + isTeacher: (Boolean) -> Unit = {}, + navigateToLogin: () -> Unit, +) { + val student by viewModel.isStudent.collectAsStateWithLifecycle() + // val teacher by viewModel.isTeacher.collectAsStateWithLifecycle() + + LaunchedEffect(student) { + Log.d("testt", student.toString()) + isStudent(student) + navigateToLogin() + /*else { + isStudent(!student) + navigateToLogin() + }*/ + } + + StackKnowledgeAndroidTheme { colors, typography -> + Box( + modifier = modifier.background(color = colors.WHITE), + ) { + LoginBackground() + Column( + modifier = modifier + .fillMaxSize() + .padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = modifier.height(260.dp)) + + Text( + text = stringResource(id = R.string.select_role_text), + style = typography.titleMedium, + color = colors.BLACK, + textAlign = TextAlign.Center + ) + + Spacer(modifier = modifier.weight(1f)) + + Row( + modifier = modifier.fillMaxWidth() + ) { + StackKnowledgeButton( + text = stringResource(id = R.string.student), + modifier = modifier + .height(60.dp) + .weight(1f), + onClick = { + viewModel.roleCheck(role = true) + } + ) + + Spacer(modifier = modifier.width(8.dp)) + + StackKnowledgeButton( + text = stringResource(id = R.string.teacher), + modifier = modifier + .height(60.dp) + .weight(1f), + onClick = { + viewModel.roleCheck(role = false) + } + ) + } + + Spacer(modifier = modifier.height(102.dp)) + } + } + } +} + +@Preview +@Composable +fun RoleCheckScreenPre() { + //RoleCheckScreen() +} \ No newline at end of file From d02723fd4b956e608ebdfc8bfb1702a10d2ffa8c Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:40:13 +0900 Subject: [PATCH 26/91] :memo: :: modify function name --- .../{StackKnowledgeBackground.kt => LoginBackground.kt} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename feature/login/src/main/java/com/stackknowledge/login/background/{StackKnowledgeBackground.kt => LoginBackground.kt} (93%) diff --git a/feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt b/feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt similarity index 93% rename from feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt rename to feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt index 0d9fdcc1..b5578370 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/background/StackKnowledgeBackground.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/background/LoginBackground.kt @@ -15,7 +15,7 @@ import androidx.compose.ui.tooling.preview.Preview import com.stackknowledge.design_system.R @Composable -fun StackKnowledgeBackground( +fun LoginBackground( modifier: Modifier = Modifier ) { Column( @@ -43,6 +43,6 @@ fun StackKnowledgeBackground( @Preview @Composable -fun StackKnowledgeBackgroundPre() { - StackKnowledgeBackground() +fun LoginBackgroundPre() { + LoginBackground() } \ No newline at end of file From e9bb30b198e215e31e40668e54ad1b8e5994cd90 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 11:40:56 +0900 Subject: [PATCH 27/91] :sparkle: :: add user role check --- .../com/stackknowledge/login/LoginActivity.kt | 44 ++++++++++++---- .../com/stackknowledge/login/LoginScreen.kt | 45 ++++++++++++++--- .../login/navigation/LoginNavigation.kt | 21 ++++++++ .../login/viewmodel/AuthViewModel.kt | 50 ++++++++++++++++--- 4 files changed, 136 insertions(+), 24 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index f0234296..9e7fd12b 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -10,6 +10,10 @@ import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.Observer import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInClient import com.google.android.gms.auth.api.signin.GoogleSignInOptions @@ -18,6 +22,7 @@ import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.Scope import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.viewmodel.AuthViewModel +import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.model.remote.enumdatatype.Authority import com.stackknowledge.model.remote.request.auth.LoginRequest import dagger.hilt.android.AndroidEntryPoint @@ -25,33 +30,54 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class LoginActivity : ComponentActivity() { private val viewModel: AuthViewModel by viewModels() + private var isStudent = false + private var isTeacher = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + intent?.let { + isStudent = it.getBooleanExtra("isStudent", false) + viewModel.roleCheck(isStudent) + Log.d("LoginActivity", "Intent extra isStudent: $isStudent") + } + setContent { - LoginScreen( - googleLogin = { googleSignIn() } + val isStudentState = rememberSaveable { mutableStateOf(false) } + + LoginRoute( + viewModel = viewModel, + googleLogin = { googleSignIn() }, + isStudent = { isStudentState.value = it }, + // isTeacher = { isTeacher = it } ) } + Log.d("roleCheck", isStudent.toString()) + viewModel.roleCheck(role = isStudent) - intentData(intent.data) + Log.d("LoginActivity", "Intent data: ${intent.data}") + intentData(intent.data, isStudent) } private fun googleSignIn() { val url = - "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}" + "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}&prompt=select_account" val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) startActivity(intent) } - private fun intentData(uri: Uri?) { + private fun intentData( + uri: Uri?, + isStudent: Boolean, + ) { val code = uri?.getQueryParameter("code") + Log.d("LoginActivity", "Extracted code: $code") if (!code.isNullOrBlank()) { - viewModel.login( - body = LoginRequest(code), - role = "student" - ) + Log.d("isStudent", isStudent.toString()) + when (isStudent) { + true -> viewModel.loginStudent(body = LoginRequest(code)) + false -> viewModel.loginTeacher(body = LoginRequest(code)) + } } else { Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() } diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index a464b64e..0068fbc9 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -1,5 +1,7 @@ package com.stackknowledge.login +import android.util.Log +import androidx.activity.ComponentActivity import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -12,40 +14,69 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.button.GoogleButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.background.StackKnowledgeBackground +import com.stackknowledge.login.background.LoginBackground import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.login.viewmodel.AuthViewModel @Composable fun LoginRoute( - // googleLogin: () -> Unit, - viewModel: AuthViewModel = hiltViewModel() + googleLogin: () -> Unit = {}, + isStudent: (Boolean) -> Unit = {}, + isTeacher: (Boolean) -> Unit = {}, + viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { - LoginScreen() + val roleCheck by viewModel.isStudent.collectAsStateWithLifecycle() + + LoginScreen( + googleLogin = googleLogin, + isStudent = isStudent, + // isTeacher = isTeacher, + viewModel = viewModel, + roleCheck = roleCheck, + // student = student, + // teacher = teacher, + ) } @Composable fun LoginScreen( modifier: Modifier = Modifier, - googleLogin: () -> Unit = {} + viewModel: AuthViewModel, + googleLogin: () -> Unit = {}, + isStudent: (Boolean) -> Unit = {}, + // isTeacher: (Boolean) -> Unit = {}, + roleCheck: Boolean, + // student: Boolean, + // teacher: Boolean, ) { + LaunchedEffect(roleCheck) { + isStudent(roleCheck) + Log.d("student", roleCheck.toString()) + // isTeacher(!roleCheck) + } + StackKnowledgeAndroidTheme { colors, typography -> Surface { Column( modifier = modifier.fillMaxSize() ) { Box() { - StackKnowledgeBackground() + LoginBackground() Column( modifier = modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally @@ -85,5 +116,5 @@ fun LoginScreen( @Preview @Composable fun LoginScreenPre() { - LoginScreen() + //LoginScreen() } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index e2e3c1f4..e30700b5 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -10,8 +10,11 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.login.LoginActivity import com.stackknowledge.login.LoginRoute +import com.stackknowledge.login.RoleCheckRoute +import com.stackknowledge.login.RoleCheckScreen const val loginRoute = "login_route" +const val roleCheckRoute = "role_check_route" fun NavController.navigateToLogin(navOptions: NavOptions? = null) { this.navigate(loginRoute, navOptions) @@ -21,4 +24,22 @@ fun NavGraphBuilder.loginScreen() { composable(route = loginRoute) { LoginRoute() } +} + +fun NavController.navigateToRoleCheck(navOptions: NavOptions? = null) { + this.navigate(roleCheckRoute, navOptions) +} + +fun NavGraphBuilder.roleCheckScreen( + navigateToLogin: () -> Unit, + isStudent: (Boolean) -> Unit, + isTeacher: (Boolean) -> Unit, +) { + composable(route = roleCheckRoute) { + RoleCheckRoute( + navigateToLogin = navigateToLogin, + isStudent = isStudent, + isTeacher = isTeacher + ) + } } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index bb7cb98f..f88cbb6e 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -1,12 +1,12 @@ package com.stackknowledge.login.viewmodel -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData +import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.stackknowledge.domain.auth.LogoutUseCase import com.stackknowledge.domain.auth.SaveTokenUseCase -import com.stackknowledge.domain.auth.LoginUseCase +import com.stackknowledge.domain.auth.LoginStudentUseCase +import com.stackknowledge.domain.auth.LoginTeacherUseCase import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.login.viewmodel.util.errorHandling import com.stackknowledge.model.remote.request.auth.LoginRequest @@ -20,7 +20,8 @@ import javax.inject.Inject @HiltViewModel class AuthViewModel @Inject constructor( - private val loginUseCase: LoginUseCase, + private val loginStudentUseCase: LoginStudentUseCase, + private val loginTeacherUseCase: LoginTeacherUseCase, private val logoutUseCase: LogoutUseCase, private val saveTokenUseCase: SaveTokenUseCase, ) : ViewModel() { @@ -30,13 +31,33 @@ class AuthViewModel @Inject constructor( private val _loginRequest = MutableStateFlow>(Event.Loading) val loginRequest = _loginRequest.asStateFlow() - fun login( + private val _isStudent = MutableStateFlow(false) + val isStudent = _isStudent.asStateFlow() + +// private val _isTeacher = MutableStateFlow(false) +// val isTeacher = _isTeacher.asStateFlow() + + fun loginStudent( + body: LoginRequest, + ) = viewModelScope.launch { + loginStudentUseCase( + body = body, + ).onSuccess { + it.catch { remoteError -> + _loginRequest.value = remoteError.errorHandling() + }.collect { response -> + _loginRequest.value = Event.Success(data = response) + } + }.onFailure { + _loginRequest.value = it.errorHandling() + } + } + + fun loginTeacher( body: LoginRequest, - role: String ) = viewModelScope.launch { - loginUseCase( + loginTeacherUseCase( body = body, - role = role ).onSuccess { it.catch { remoteError -> _loginRequest.value = remoteError.errorHandling() @@ -47,4 +68,17 @@ class AuthViewModel @Inject constructor( _loginRequest.value = it.errorHandling() } } + + fun roleCheck(role: Boolean) { + viewModelScope.launch { + _isStudent.value = role + Log.d("isStudent", isStudent.value.toString()) + } + } + +// fun roleTeacher(role: Boolean) { +// viewModelScope.launch { +// _isUser.value = role +// } +// } } \ No newline at end of file From 6e4243587cadb2ee03f5d1aed52fbfb2fe1a5ae0 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Wed, 26 Jun 2024 17:41:42 +0900 Subject: [PATCH 28/91] :sparkle: :: google oauth --- .../com/stackknowledge/login/LoginActivity.kt | 59 +++++++++++++++---- .../com/stackknowledge/login/LoginScreen.kt | 25 ++++---- .../stackknowledge/login/RoleCheckScreen.kt | 15 ++--- 3 files changed, 70 insertions(+), 29 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index 9e7fd12b..77c78740 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -31,7 +31,18 @@ import dagger.hilt.android.AndroidEntryPoint class LoginActivity : ComponentActivity() { private val viewModel: AuthViewModel by viewModels() private var isStudent = false - private var isTeacher = false + private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } + private val googleAuthLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) + + try { + val account = task.getResult(ApiException::class.java) + Log.e("try launch", account.toString()) + account.serverAuthCode?.let { viewModel.loginStudent(LoginRequest(it)) } // 서버에 idToken 보내기 + } catch (e: ApiException) { + Log.e(LoginActivity::class.java.simpleName, e.stackTraceToString()) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -47,7 +58,11 @@ class LoginActivity : ComponentActivity() { LoginRoute( viewModel = viewModel, - googleLogin = { googleSignIn() }, + googleLogin = { + googleSignIn( + isStudent = isStudent + ) + }, isStudent = { isStudentState.value = it }, // isTeacher = { isTeacher = it } ) @@ -56,14 +71,34 @@ class LoginActivity : ComponentActivity() { viewModel.roleCheck(role = isStudent) Log.d("LoginActivity", "Intent data: ${intent.data}") - intentData(intent.data, isStudent) +// intentData(intent.data, isStudent) } - private fun googleSignIn() { - val url = - "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?ei5r49r2ou9pflsn9bas5hvj4c13uroq.apps.googleusercontent.com&response_type=code&redirect_uri=${BuildConfig.REDIRECT_URI}&scope=${BuildConfig.SCOPE}&client_id=${BuildConfig.GOOGLE_CLIENT_ID}&prompt=select_account" - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - startActivity(intent) + private fun googleSignIn( + isStudent: Boolean + ) { + googleSignInClient.signOut() + val signInIntent = googleSignInClient.signInIntent + googleAuthLauncher.launch(signInIntent) + if (isStudent) { + intentData(intent.data, isStudent) + } + } + + private fun getGoogleClient(): GoogleSignInClient { + val googleSignInOption = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestServerAuthCode(BuildConfig.GOOGLE_CLIENT_ID) + .build() + + return GoogleSignIn.getClient(this, googleSignInOption) + } + + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + Log.d("LoginActivity", "onNewIntent called") + intent.data?.let { + intentData(it, isStudent) + } } private fun intentData( @@ -73,10 +108,10 @@ class LoginActivity : ComponentActivity() { val code = uri?.getQueryParameter("code") Log.d("LoginActivity", "Extracted code: $code") if (!code.isNullOrBlank()) { - Log.d("isStudent", isStudent.toString()) - when (isStudent) { - true -> viewModel.loginStudent(body = LoginRequest(code)) - false -> viewModel.loginTeacher(body = LoginRequest(code)) + if(isStudent) { + viewModel.loginStudent(body = LoginRequest(code)) + } else { + viewModel.loginTeacher(body = LoginRequest(code)) } } else { Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 0068fbc9..3a7d4893 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -48,8 +48,8 @@ fun LoginRoute( // isTeacher = isTeacher, viewModel = viewModel, roleCheck = roleCheck, - // student = student, - // teacher = teacher, +// student = student, +// teacher = teacher, ) } @@ -59,16 +59,21 @@ fun LoginScreen( viewModel: AuthViewModel, googleLogin: () -> Unit = {}, isStudent: (Boolean) -> Unit = {}, - // isTeacher: (Boolean) -> Unit = {}, + //isTeacher: (Boolean) -> Unit = {}, roleCheck: Boolean, - // student: Boolean, - // teacher: Boolean, +// student: Boolean, +// teacher: Boolean, ) { - LaunchedEffect(roleCheck) { - isStudent(roleCheck) - Log.d("student", roleCheck.toString()) - // isTeacher(!roleCheck) - } + + /* LaunchedEffect(student, teacher) { + isStudent(student) + Log.d("student", student.toString()) + isTeacher(teacher) + }*/ + + isStudent(roleCheck) + Log.d("student", roleCheck.toString()) + // isTeacher(!roleCheck) StackKnowledgeAndroidTheme { colors, typography -> Surface { diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt index 3d33b13c..1d59c1bb 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -63,13 +63,14 @@ fun RoleCheckScreen( // val teacher by viewModel.isTeacher.collectAsStateWithLifecycle() LaunchedEffect(student) { - Log.d("testt", student.toString()) - isStudent(student) - navigateToLogin() - /*else { - isStudent(!student) - navigateToLogin() - }*/ + if (student) { + Log.d("testt",student.toString()) + isStudent(student) + navigateToLogin() + } /*else { + isStudent(!student) + navigateToLogin() + }*/ } StackKnowledgeAndroidTheme { colors, typography -> From 0bd77dbd1c32d52e05126bfdd75f37f88cc078bb Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 27 Jun 2024 10:37:14 +0900 Subject: [PATCH 29/91] :twisted_rightwards_arrows: :: Stash Commit :: Stash Commit --- .../java/com/stackknowledge/MainActivity.kt | 12 -- .../navigation/StackKnowledgeNavHost.kt | 28 ++--- .../stackknowledge/ui/StackKnowledgeApp.kt | 8 +- .../AndroidFeatureConventionPlugin.kt | 1 + feature/login/build.gradle.kts | 2 - .../com/stackknowledge/login/LoginActivity.kt | 107 +----------------- .../com/stackknowledge/login/LoginScreen.kt | 88 +++++++------- .../stackknowledge/login/RoleCheckScreen.kt | 38 +++++-- .../login/navigation/LoginNavigation.kt | 14 +-- .../login/viewmodel/AuthViewModel.kt | 106 ++++++++++++----- 10 files changed, 175 insertions(+), 229 deletions(-) diff --git a/app/src/main/java/com/stackknowledge/MainActivity.kt b/app/src/main/java/com/stackknowledge/MainActivity.kt index 12f9296a..dfb34222 100644 --- a/app/src/main/java/com/stackknowledge/MainActivity.kt +++ b/app/src/main/java/com/stackknowledge/MainActivity.kt @@ -16,9 +16,6 @@ import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class MainActivity : ComponentActivity() { - private var isStudent = false - private var isTeacher = false - @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -27,18 +24,9 @@ class MainActivity : ComponentActivity() { StackKnowledgeAndroidTheme { _, _ -> StackKnowledgeApp( windowSizeClass = calculateWindowSizeClass(this@MainActivity), - startLogin = { startLogin() }, - isStudent = { isStudent = it }, - isTeacher = { isTeacher = it }, ) } } } } - - private fun startLogin() { - val intent = Intent(this, LoginActivity::class.java) - intent.putExtra("isStudent", isStudent) - startActivity(intent) - } } diff --git a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt index bdd6bcf8..d8791a5c 100644 --- a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt @@ -1,12 +1,8 @@ package com.stackknowledge.navigation -import android.content.Intent import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.navigation.compose.NavHost -import com.stackknowledge.login.LoginActivity -import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.login.navigation.loginScreen import com.stackknowledge.login.navigation.navigateToLogin import com.stackknowledge.login.navigation.roleCheckRoute @@ -16,27 +12,21 @@ import com.stackknowledge.ui.StackKnowledgeAppState @Composable fun StackKnowledgeNavHost( appState: StackKnowledgeAppState, - startLogin: () -> Unit, - modifier: Modifier = Modifier, startDestination: String = roleCheckRoute, - isStudent: (Boolean) -> Unit, - isTeacher: (Boolean) -> Unit, + modifier: Modifier = Modifier, ) { val navController = appState.navController - // 아래의 NavHost의 startDestination은 GoogleOAuth작업 이후 학생 or 선생여부 묻는 스크린을 띄워주면 될 거 같아요 - NavHost ( + NavHost( navController = navController, startDestination = startDestination, modifier = modifier - ) { - roleCheckScreen( - navigateToLogin = startLogin, - isStudent = isStudent, - isTeacher = isTeacher, - ) - loginScreen( + ) { + roleCheckScreen( + onRoleButtonClick = navController::navigateToLogin + ) + loginScreen( - ) - } + ) + } } \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt index ef7787ae..e062c785 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt @@ -11,16 +11,10 @@ fun StackKnowledgeApp( appState: StackKnowledgeAppState = rememberStackKnowledgeAppState( windowSizeClass = windowSizeClass ), - startLogin:() -> Unit, - isStudent: (Boolean) -> Unit, - isTeacher: (Boolean) -> Unit, ) { StackKnowledgeAndroidTheme { _, _ -> StackKnowledgeNavHost( appState = appState, - startLogin = { startLogin() }, - isStudent = isStudent, - isTeacher = isTeacher, - ) //startDestination = ) // <- 이부분도 startDestination 스크린 작업 후 추가 + ) } } \ No newline at end of file diff --git a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt index 47de15e0..511458c6 100644 --- a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt @@ -21,6 +21,7 @@ class AndroidFeatureConventionPlugin : Plugin { add("implementation", project(":core:data")) add("implementation", project(":core:domain")) add("implementation", project(":core:datastore")) + add("implementation", project(":core:common")) add("implementation", libs.findLibrary("coil.kt").get()) diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index ca1edaec..db9844d5 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -22,8 +22,6 @@ android { dependencies { implementation(libs.google.services) -// implementation(libs.firebase.auth) -// implementation(libs.firebase.bom) implementation(libs.play.services.auth) } fun getApiKey(propertyKey: String): String { diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index 77c78740..f378bc11 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -1,120 +1,23 @@ package com.stackknowledge.login -import android.content.Intent -import android.net.Uri import android.os.Bundle -import android.util.Log -import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.result.ActivityResultLauncher -import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.viewModels -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.platform.LocalContext -import androidx.lifecycle.Observer -import com.google.android.gms.auth.api.signin.GoogleSignIn -import com.google.android.gms.auth.api.signin.GoogleSignInClient -import com.google.android.gms.auth.api.signin.GoogleSignInOptions -import com.google.android.gms.auth.api.signin.GoogleSignInResult -import com.google.android.gms.common.api.ApiException -import com.google.android.gms.common.api.Scope +import androidx.compose.runtime.CompositionLocalProvider import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.viewmodel.AuthViewModel -import com.stackknowledge.login.viewmodel.util.Event -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint class LoginActivity : ComponentActivity() { - private val viewModel: AuthViewModel by viewModels() - private var isStudent = false - private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } - private val googleAuthLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) - - try { - val account = task.getResult(ApiException::class.java) - Log.e("try launch", account.toString()) - account.serverAuthCode?.let { viewModel.loginStudent(LoginRequest(it)) } // 서버에 idToken 보내기 - } catch (e: ApiException) { - Log.e(LoginActivity::class.java.simpleName, e.stackTraceToString()) - } - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - intent?.let { - isStudent = it.getBooleanExtra("isStudent", false) - viewModel.roleCheck(isStudent) - Log.d("LoginActivity", "Intent extra isStudent: $isStudent") - } - setContent { - val isStudentState = rememberSaveable { mutableStateOf(false) } - - LoginRoute( - viewModel = viewModel, - googleLogin = { - googleSignIn( - isStudent = isStudent - ) - }, - isStudent = { isStudentState.value = it }, - // isTeacher = { isTeacher = it } - ) - } - Log.d("roleCheck", isStudent.toString()) - viewModel.roleCheck(role = isStudent) - - Log.d("LoginActivity", "Intent data: ${intent.data}") -// intentData(intent.data, isStudent) - } - - private fun googleSignIn( - isStudent: Boolean - ) { - googleSignInClient.signOut() - val signInIntent = googleSignInClient.signInIntent - googleAuthLauncher.launch(signInIntent) - if (isStudent) { - intentData(intent.data, isStudent) - } - } - - private fun getGoogleClient(): GoogleSignInClient { - val googleSignInOption = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestServerAuthCode(BuildConfig.GOOGLE_CLIENT_ID) - .build() - - return GoogleSignIn.getClient(this, googleSignInOption) - } - - override fun onNewIntent(intent: Intent) { - super.onNewIntent(intent) - Log.d("LoginActivity", "onNewIntent called") - intent.data?.let { - intentData(it, isStudent) - } - } - - private fun intentData( - uri: Uri?, - isStudent: Boolean, - ) { - val code = uri?.getQueryParameter("code") - Log.d("LoginActivity", "Extracted code: $code") - if (!code.isNullOrBlank()) { - if(isStudent) { - viewModel.loginStudent(body = LoginRequest(code)) - } else { - viewModel.loginTeacher(body = LoginRequest(code)) + CompositionLocalProvider { + StackKnowledgeAndroidTheme { _, _ -> + LoginRoute() + } } - } else { - Toast.makeText(this, "로그인 실패", Toast.LENGTH_SHORT).show() } } } diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 3a7d4893..0d73c623 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -1,6 +1,5 @@ package com.stackknowledge.login -import android.util.Log import androidx.activity.ComponentActivity import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box @@ -14,9 +13,6 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -25,62 +21,55 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.button.GoogleButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.background.LoginBackground -import com.stackknowledge.login.navigation.loginRoute import com.stackknowledge.login.viewmodel.AuthViewModel +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.rememberCoroutineScope +import com.stackknowledge.login.viewmodel.util.Event +import kotlinx.coroutines.launch @Composable fun LoginRoute( - googleLogin: () -> Unit = {}, - isStudent: (Boolean) -> Unit = {}, - isTeacher: (Boolean) -> Unit = {}, viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { - val roleCheck by viewModel.isStudent.collectAsStateWithLifecycle() + val context = LocalContext.current + val coroutineScope = rememberCoroutineScope() + + rememberLauncherForActivityResult( + contract = ActivityResultContracts.StartActivityForResult() + ) { result -> + viewModel.handleGoogleSignInResult(result) + } LoginScreen( - googleLogin = googleLogin, - isStudent = isStudent, - // isTeacher = isTeacher, - viewModel = viewModel, - roleCheck = roleCheck, -// student = student, -// teacher = teacher, + onGoogleLoginButtonClicked = { + viewModel.googleSocialLogin() + coroutineScope.launch { + getLoginData( + viewModel = viewModel, + onSuccess = {}, + onFailure = {} + ) + } + }, ) } @Composable fun LoginScreen( modifier: Modifier = Modifier, - viewModel: AuthViewModel, - googleLogin: () -> Unit = {}, - isStudent: (Boolean) -> Unit = {}, - //isTeacher: (Boolean) -> Unit = {}, - roleCheck: Boolean, -// student: Boolean, -// teacher: Boolean, + onGoogleLoginButtonClicked: () -> Unit, ) { - - /* LaunchedEffect(student, teacher) { - isStudent(student) - Log.d("student", student.toString()) - isTeacher(teacher) - }*/ - - isStudent(roleCheck) - Log.d("student", roleCheck.toString()) - // isTeacher(!roleCheck) - StackKnowledgeAndroidTheme { colors, typography -> Surface { Column( modifier = modifier.fillMaxSize() ) { - Box() { + Box { LoginBackground() Column( modifier = modifier.fillMaxSize(), @@ -108,7 +97,7 @@ fun LoginScreen( ) { GoogleButton( modifier = modifier.height(60.dp), - onClick = googleLogin + onClick = onGoogleLoginButtonClicked ) } } @@ -118,8 +107,31 @@ fun LoginScreen( } } +private suspend fun getLoginData( + viewModel: AuthViewModel, + onSuccess: () -> Unit, + onFailure: () -> Unit, +) { + viewModel.loginResponse.collect { response -> + when (response) { + is Event.Success -> { + viewModel.saveToken(response.data!!) + onSuccess() + } + + is Event.BadRequest -> { + onFailure() + } + + else -> {} + } + } +} + @Preview @Composable fun LoginScreenPre() { - //LoginScreen() + LoginScreen( + onGoogleLoginButtonClicked = {} + ) } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt index 93e9a8d8..5af2d803 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -1,6 +1,5 @@ package com.stackknowledge.login -import android.util.Log import androidx.activity.ComponentActivity import androidx.compose.foundation.background import com.stackknowledge.design_system.R @@ -15,8 +14,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.Text import androidx.compose.runtime.Composable +<<<<<<< Updated upstream import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +======= +>>>>>>> Stashed changes import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -25,7 +27,6 @@ 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 androidx.lifecycle.compose.collectAsStateWithLifecycle import com.stackknowledge.design_system.component.button.StackKnowledgeButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.background.LoginBackground @@ -33,27 +34,33 @@ import com.stackknowledge.login.viewmodel.AuthViewModel @Composable fun RoleCheckRoute( - navigateToLogin: () -> Unit, - isStudent: (Boolean) -> Unit, - isTeacher: (Boolean) -> Unit, + onRoleButtonClick: () -> Unit, viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { RoleCheckScreen( +<<<<<<< Updated upstream navigateToLogin = navigateToLogin, isStudent = isStudent, isTeacher = isTeacher, viewModel = viewModel +======= + onTeacherButtonClick = { isTeacher -> + viewModel.isTeacher.value = isTeacher + }, + onStudentButtonClick = { isStudent -> + viewModel.isStudent.value = isStudent + } +>>>>>>> Stashed changes ) } @Composable fun RoleCheckScreen( modifier: Modifier = Modifier, - viewModel: AuthViewModel, - isStudent: (Boolean) -> Unit = {}, - isTeacher: (Boolean) -> Unit = {}, - navigateToLogin: () -> Unit, + onTeacherButtonClick: (Boolean) -> Unit, + onStudentButtonClick: (Boolean) -> Unit, ) { +<<<<<<< Updated upstream val student by viewModel.isStudent.collectAsStateWithLifecycle() // val teacher by viewModel.isTeacher.collectAsStateWithLifecycle() @@ -67,6 +74,8 @@ fun RoleCheckScreen( navigateToLogin() }*/ } +======= +>>>>>>> Stashed changes StackKnowledgeAndroidTheme { colors, typography -> Box( modifier = modifier.background(color = colors.WHITE), @@ -98,7 +107,7 @@ fun RoleCheckScreen( .height(60.dp) .weight(1f), onClick = { - viewModel.roleCheck(role = true) + onStudentButtonClick(true) } ) @@ -111,7 +120,7 @@ fun RoleCheckScreen( .height(60.dp) .weight(1f), onClick = { - viewModel.roleCheck(role = false) + onTeacherButtonClick(true) } ) @@ -126,4 +135,11 @@ fun RoleCheckScreen( @Preview @Composable fun RoleCheckScreenPre() { +<<<<<<< Updated upstream +======= + RoleCheckScreen( + onTeacherButtonClick = {}, + onStudentButtonClick = {}, + ) +>>>>>>> Stashed changes } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index e30700b5..17ca4875 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -1,17 +1,11 @@ package com.stackknowledge.login.navigation -import android.content.Intent -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable -import com.stackknowledge.login.LoginActivity import com.stackknowledge.login.LoginRoute import com.stackknowledge.login.RoleCheckRoute -import com.stackknowledge.login.RoleCheckScreen const val loginRoute = "login_route" const val roleCheckRoute = "role_check_route" @@ -31,15 +25,11 @@ fun NavController.navigateToRoleCheck(navOptions: NavOptions? = null) { } fun NavGraphBuilder.roleCheckScreen( - navigateToLogin: () -> Unit, - isStudent: (Boolean) -> Unit, - isTeacher: (Boolean) -> Unit, + onRoleButtonClick: () -> Unit, ) { composable(route = roleCheckRoute) { RoleCheckRoute( - navigateToLogin = navigateToLogin, - isStudent = isStudent, - isTeacher = isTeacher + onRoleButtonClick = onRoleButtonClick ) } } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index f88cbb6e..e7c390b1 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -1,17 +1,26 @@ package com.stackknowledge.login.viewmodel -import android.util.Log +import android.app.Activity +import android.content.Context +import androidx.activity.result.ActivityResult +import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.stackknowledge.domain.auth.LogoutUseCase +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Scope import com.stackknowledge.domain.auth.SaveTokenUseCase import com.stackknowledge.domain.auth.LoginStudentUseCase import com.stackknowledge.domain.auth.LoginTeacherUseCase +import com.stackknowledge.login.BuildConfig import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.login.viewmodel.util.errorHandling import com.stackknowledge.model.remote.request.auth.LoginRequest import com.stackknowledge.model.remote.response.auth.LoginResponse import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch @@ -20,65 +29,110 @@ import javax.inject.Inject @HiltViewModel class AuthViewModel @Inject constructor( + @ApplicationContext private val context: Context, private val loginStudentUseCase: LoginStudentUseCase, private val loginTeacherUseCase: LoginTeacherUseCase, - private val logoutUseCase: LogoutUseCase, private val saveTokenUseCase: SaveTokenUseCase, ) : ViewModel() { private val _saveTokenRequest = MutableStateFlow>(Event.Loading) val saveTokenRequest = _saveTokenRequest.asStateFlow() - private val _loginRequest = MutableStateFlow>(Event.Loading) - val loginRequest = _loginRequest.asStateFlow() + private val _loginResponse = MutableStateFlow>(Event.Loading) + val loginResponse = _loginResponse.asStateFlow() - private val _isStudent = MutableStateFlow(false) - val isStudent = _isStudent.asStateFlow() + private val _googleAuthResult = MutableStateFlow(null) + val googleAuthResult = _googleAuthResult.asStateFlow() -// private val _isTeacher = MutableStateFlow(false) -// val isTeacher = _isTeacher.asStateFlow() + private val _signInError = MutableStateFlow(null) + val signInError = _signInError.asStateFlow() - fun loginStudent( + private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } + var isTeacher = mutableStateOf(false) + private set + + var isStudent = mutableStateOf(false) + private set + + private var googleAuthCode = mutableStateOf("") + + init { + _googleAuthResult.value = null + } + + internal fun loginStudent( body: LoginRequest, ) = viewModelScope.launch { loginStudentUseCase( body = body, ).onSuccess { it.catch { remoteError -> - _loginRequest.value = remoteError.errorHandling() + _loginResponse.value = remoteError.errorHandling() }.collect { response -> - _loginRequest.value = Event.Success(data = response) + _loginResponse.value = Event.Success(data = response) } }.onFailure { - _loginRequest.value = it.errorHandling() + _loginResponse.value = it.errorHandling() } } - fun loginTeacher( + internal fun loginTeacher( body: LoginRequest, ) = viewModelScope.launch { loginTeacherUseCase( body = body, ).onSuccess { it.catch { remoteError -> - _loginRequest.value = remoteError.errorHandling() + _loginResponse.value = remoteError.errorHandling() }.collect { response -> - _loginRequest.value = Event.Success(data = response) + _loginResponse.value = Event.Success(data = response) } }.onFailure { - _loginRequest.value = it.errorHandling() + _loginResponse.value = it.errorHandling() + } + } + + internal fun saveToken( + token: LoginResponse, + ) = viewModelScope.launch { + saveTokenUseCase( + token = token + ).onSuccess { + _saveTokenRequest.value = Event.Success() + }.onFailure { + _saveTokenRequest.value = it.errorHandling() } } - fun roleCheck(role: Boolean) { - viewModelScope.launch { - _isStudent.value = role - Log.d("isStudent", isStudent.value.toString()) + internal fun googleSocialLogin() = viewModelScope.launch { + googleSignInClient.signOut() + val signInIntent = googleSignInClient.signInIntent + _googleAuthResult.value = ActivityResult(Activity.RESULT_OK, signInIntent) + } + + fun handleGoogleSignInResult(result: ActivityResult) { + val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) + try { + val account = task.getResult(ApiException::class.java) + account.serverAuthCode?.let { authCode -> + setGoogleAuthCode(authCode) + } + _googleAuthResult.value = result + } catch (e: ApiException) { + _signInError.value = e.stackTraceToString() } } -// fun roleTeacher(role: Boolean) { -// viewModelScope.launch { -// _isUser.value = role -// } -// } + private fun getGoogleClient(): GoogleSignInClient { + val googleSignInOption = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestScopes(Scope("${BuildConfig.SCOPE}")) + .requestServerAuthCode("${BuildConfig.GOOGLE_CLIENT_ID}") + .requestEmail() + .build() + + return GoogleSignIn.getClient(context, googleSignInOption) + } + + private fun setGoogleAuthCode(authCode: String) { + googleAuthCode.value = authCode + } } \ No newline at end of file From 00902b21cba4603a48110f20cb623186688d51bb Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:49:49 +0900 Subject: [PATCH 30/91] =?UTF-8?q?=F0=9F=94=A5::=20FeatureConvention=20data?= =?UTF-8?q?,=20dataStore=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=82=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/convention/AndroidFeatureConventionPlugin.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt index 511458c6..d3cc1e0c 100644 --- a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt @@ -18,9 +18,7 @@ class AndroidFeatureConventionPlugin : Plugin { add("implementation", project(":core:model")) add("implementation", project(":core:ui")) add("implementation", project(":core:design-system")) - add("implementation", project(":core:data")) add("implementation", project(":core:domain")) - add("implementation", project(":core:datastore")) add("implementation", project(":core:common")) add("implementation", libs.findLibrary("coil.kt").get()) From b4061e28f4067d19f2286054599667bfde8e9e88 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:50:24 +0900 Subject: [PATCH 31/91] =?UTF-8?q?=F0=9F=94=A5::=20Kotlin=EC=9D=B4=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20Java=20Build=20Package=EC=97=90=EC=84=9C?= =?UTF-8?q?=20Error=EB=A5=BC=20=EC=95=BC=EA=B8=B0=ED=95=98=EB=8D=98=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EB=93=A4=20=EC=A0=84=EB=B6=80=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 22 +++--- .../data/di/RepositoryModule.kt | 17 ----- .../data/repository/auth/AuthRepository.kt | 20 ----- .../repository/auth/AuthRepositoryImpl.kt | 40 ---------- .../main/kotlin/enumdatatype/MissionStatus.kt | 7 -- .../com/stackknowledge/network/api/AuthAPI.kt | 26 ------- .../network/datasource/auth/AuthDataSource.kt | 18 ----- .../datasource/auth/AuthDataSourceImpl.kt | 49 ------------ .../network/di/DataSourceModule.kt | 17 ----- .../network/di/NetworkModule.kt | 62 --------------- .../network/exception/HttpException.kt | 42 ---------- .../network/exception/NeedLoginException.kt | 8 -- .../network/exception/NetworkException.kt | 6 -- .../network/util/AuthInterceptor.kt | 76 ------------------- .../network/util/DataTimeFormatter.kt | 18 ----- .../network/util/StackKnowledgeApiHandler.kt | 58 -------------- .../login/ExampleInstrumentedTest.kt | 24 ------ .../stackknowledge/login/ExampleUnitTest.kt | 17 ----- 18 files changed, 11 insertions(+), 516 deletions(-) delete mode 100644 core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt delete mode 100644 core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt delete mode 100644 core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt delete mode 100644 core/model/src/main/kotlin/enumdatatype/MissionStatus.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt delete mode 100644 core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt delete mode 100644 feature/login/src/androidTest/java/com/stackknowledge/login/ExampleInstrumentedTest.kt delete mode 100644 feature/login/src/test/java/com/stackknowledge/login/ExampleUnitTest.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bb3f391e..6edb3e2e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,32 +15,32 @@ android:supportsRtl="true" android:theme="@style/Theme.StackKnowledge" tools:targetApi="31"> + - - + + + + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.StackKnowledge">> - + + - + - - \ No newline at end of file + diff --git a/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt b/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt deleted file mode 100644 index 67555ec5..00000000 --- a/core/data/src/main/java/com/stackknowledge/data/di/RepositoryModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.stackknowledge.data.di - -import com.stackknowledge.data.repository.auth.AuthRepository -import com.stackknowledge.data.repository.auth.AuthRepositoryImpl -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -abstract class RepositoryModule { - @Binds - abstract fun bindAuthRepository( - authRepositoryImpl: AuthRepositoryImpl - ): AuthRepository -} \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt deleted file mode 100644 index 5544fc7b..00000000 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepository.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.stackknowledge.data.repository.auth - -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse -import kotlinx.coroutines.flow.Flow - -interface AuthRepository { - suspend fun loginStudent( - body: LoginRequest, - ): Flow - - suspend fun loginTeacher( - body: LoginRequest, - ): Flow - - suspend fun saveToken(token: LoginResponse) - - suspend fun logout(): Flow -} \ No newline at end of file diff --git a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt deleted file mode 100644 index d0cc435a..00000000 --- a/core/data/src/main/java/com/stackknowledge/data/repository/auth/AuthRepositoryImpl.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.stackknowledge.data.repository.auth - -import com.stackknowledge.datastore.LocalAuthDataSource -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse -import com.stackknowledge.network.datasource.auth.AuthDataSource -import kotlinx.coroutines.flow.Flow -import javax.inject.Inject - -class AuthRepositoryImpl @Inject constructor( - private val authDataSource: AuthDataSource, - private val localDataSource: LocalAuthDataSource -): AuthRepository { - override suspend fun loginStudent(body: LoginRequest): Flow { - return authDataSource.loginStudent( - body = body, - ) - } - - override suspend fun loginTeacher(body: LoginRequest): Flow { - return authDataSource.loginTeacher( - body = body, - ) - } - - override suspend fun saveToken(token: LoginResponse) { - token.let { - localDataSource.setAccessToken(it.accessToken) - localDataSource.setAccessTime(it.expiredAt) - localDataSource.setRefreshToken(it.refreshToken) - localDataSource.setRefreshTime(it.expiredAt) - localDataSource.setAuthorityInfo(it.authority.toString()) - } - } - - override suspend fun logout(): Flow { - return authDataSource.logout() - } -} \ No newline at end of file diff --git a/core/model/src/main/kotlin/enumdatatype/MissionStatus.kt b/core/model/src/main/kotlin/enumdatatype/MissionStatus.kt deleted file mode 100644 index 842feaed..00000000 --- a/core/model/src/main/kotlin/enumdatatype/MissionStatus.kt +++ /dev/null @@ -1,7 +0,0 @@ -package enumdatatype - -enum class MissionStatus { - CLOSED, - OPENED, - AVAILABLE_OPEN, -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt b/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt deleted file mode 100644 index fef629d1..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/api/AuthAPI.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.stackknowledge.network.api - -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.POST -import retrofit2.http.Path -import retrofit2.http.Query -import retrofit2.http.Url - -interface AuthAPI { - @POST("/auth/student") - suspend fun loginStudent( - @Body body: LoginRequest, - ): LoginResponse - - @POST("/auth/teacher") - suspend fun loginTeacher( - @Body body: LoginRequest, - ): LoginResponse - - @DELETE("/auth") - suspend fun logout() -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt deleted file mode 100644 index fe1fa977..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSource.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.stackknowledge.network.datasource.auth - -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse -import kotlinx.coroutines.flow.Flow - -interface AuthDataSource { - suspend fun loginStudent( - body: LoginRequest, - ): Flow - - suspend fun loginTeacher( - body: LoginRequest, - ): Flow - - suspend fun logout(): Flow -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt deleted file mode 100644 index c7d06dd3..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/datasource/auth/AuthDataSourceImpl.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.stackknowledge.network.datasource.auth - -import com.stackknowledge.model.remote.enumdatatype.Authority -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse -import com.stackknowledge.network.api.AuthAPI -import com.stackknowledge.network.util.StackKnowledgeApiHandler -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOn -import java.util.Stack -import javax.inject.Inject - -class AuthDataSourceImpl @Inject constructor( - private val authAPI: AuthAPI -) : AuthDataSource { - override suspend fun loginStudent(body: LoginRequest): Flow = flow { - emit( - StackKnowledgeApiHandler() - .httpRequest { - authAPI.loginStudent( - body = body, - ) - } - .sendRequest() - ) - }.flowOn(Dispatchers.IO) - - override suspend fun loginTeacher(body: LoginRequest): Flow = flow { - emit( - StackKnowledgeApiHandler() - .httpRequest { - authAPI.loginTeacher( - body = body, - ) - } - .sendRequest() - ) - }.flowOn(Dispatchers.IO) - - override suspend fun logout(): Flow = flow { - emit( - StackKnowledgeApiHandler() - .httpRequest { authAPI.logout() } - .sendRequest() - ) - }.flowOn(Dispatchers.IO) -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt b/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt deleted file mode 100644 index f9db20b3..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/di/DataSourceModule.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.stackknowledge.network.di - -import com.stackknowledge.network.datasource.auth.AuthDataSource -import com.stackknowledge.network.datasource.auth.AuthDataSourceImpl -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent - -@Module -@InstallIn(SingletonComponent::class) -abstract class DataSourceModule { - @Binds - abstract fun bindAuthDataSource( - authDataSourceImpl: AuthDataSourceImpl - ): AuthDataSource -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt b/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt deleted file mode 100644 index 72cbae58..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/di/NetworkModule.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.stackknowledge.network.di - -import android.util.Log -import com.stackknowledge.network.BuildConfig -import com.stackknowledge.network.api.AuthAPI -import com.stackknowledge.network.util.AuthInterceptor -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import retrofit2.Retrofit -import retrofit2.converter.gson.GsonConverterFactory -import java.util.concurrent.TimeUnit -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object NetworkModule { - @Provides - fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = - HttpLoggingInterceptor { message -> Log.v("HTTP", message) } - .setLevel(HttpLoggingInterceptor.Level.BODY) - - @Provides - @Singleton - fun provideOkhttpClient( - httpLoggingInterceptor: HttpLoggingInterceptor, - authInterceptor: AuthInterceptor - ): OkHttpClient { - return OkHttpClient.Builder() - .connectTimeout(30, TimeUnit.SECONDS) - .readTimeout(30, TimeUnit.SECONDS) - .writeTimeout(30, TimeUnit.SECONDS) - .addInterceptor(httpLoggingInterceptor) - .addInterceptor(authInterceptor) - .build() - } - - @Provides - fun provideRetrofitInstance( - okHttpClient: OkHttpClient, - gsonConverterFactory: GsonConverterFactory - ): Retrofit { - return Retrofit.Builder() - .baseUrl(BuildConfig.BASE_URL) - .client(okHttpClient) - .addConverterFactory(gsonConverterFactory) - .build() - } - - @Provides - fun provideGsonConverterFactory(): GsonConverterFactory { - return GsonConverterFactory.create() - } - - @Provides - fun provideAuthAPI(retrofit: Retrofit): AuthAPI = - retrofit.create(AuthAPI::class.java) -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt deleted file mode 100644 index e8e66a7e..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/exception/HttpException.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.stackknowledge.network.exception - -class BadRequestException( - override val message: String? -) : RuntimeException() - -class UnauthorizedException( - override val message: String? -) : RuntimeException() - -class ForBiddenException( - override val message: String? -) : RuntimeException() - -class NotFoundException( - override val message: String? -) : RuntimeException() - -class NotAcceptableException( - override val message: String? -) : RuntimeException() - -class ConflictException( - override val message: String? -) : RuntimeException() - -class TimeOutException( - override val message: String? -) : RuntimeException() - -class ServerException( - override val message: String? -) : RuntimeException() - -class OtherException( - override val message: String?, - val code: Int -) : RuntimeException() - -class UnknownException( - override val message: String? -) : RuntimeException() \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt deleted file mode 100644 index 709bb1c8..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/exception/NeedLoginException.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.stackknowledge.network.exception - -import java.io.IOException - -class NeedLoginException : IOException() { - override val message: String - get() = "토큰이 만료되었습니다. 다시 로그인 해 주세요" -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt b/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt deleted file mode 100644 index f81e8d59..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/exception/NetworkException.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.stackknowledge.network.exception - -class NetworkException : RuntimeException() { - override val message: String - get() = "네트워크가 불안정합니다. 데이터나 와이파이 연결 상태를 확인해 주세요" -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt b/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt deleted file mode 100644 index 1d89696d..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/util/AuthInterceptor.kt +++ /dev/null @@ -1,76 +0,0 @@ -package com.stackknowledge.network.util - -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.stackknowledge.network.BuildConfig -import com.stackknowledge.datastore.LocalAuthDataSource -import com.stackknowledge.network.exception.NeedLoginException -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking -import okhttp3.Interceptor -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.RequestBody -import okhttp3.Response -import javax.inject.Inject - -class AuthInterceptor @Inject constructor( - private val dataSource: LocalAuthDataSource -): Interceptor { - override fun intercept(chain: Interceptor.Chain): Response { - val request = chain.request() - val builder = request.newBuilder() - val currentTime = System.currentTimeMillis().toLocalDateTime() - val ignorePath = listOf("/auth") - val ignoreMethod = listOf("POST") - val path = request.url.encodedPath - val method = request.method - - ignorePath.forEachIndexed { index, s -> - if (path.contains(s) && ignoreMethod[index] == method) - return chain.proceed(request) - } - - runBlocking { - val refreshTime = dataSource.getRefreshTime().first().replace("\"", "") - val accessTime = dataSource.getAccessTime().first().replace("\"", "") - - if (refreshTime == "") { - return@runBlocking - } - - if (currentTime != null) { - if (currentTime.isAfter(refreshTime.toLocalDateTime())) { - throw NeedLoginException() - } - } - - // access 토큰 재 발급 - if (currentTime != null) { - if (currentTime.isAfter(accessTime.toLocalDateTime())) { - val client = OkHttpClient() - val refreshRequest = Request.Builder() - .url(BuildConfig.BASE_URL + "/auth") - .patch(chain.request().body ?: RequestBody.create(null, byteArrayOf())) - .addHeader( - "Refresh-Token", - dataSource.getRefreshToken().first().replace("\"", "") - ) - .build() - val jsonParser = JsonParser() - val response = client.newCall(refreshRequest).execute() - if (response.isSuccessful) { - val token = jsonParser.parse(response.body!!.string()) as JsonObject - dataSource.setAccessToken(token["accessToken"].toString()) - dataSource.setRefreshToken(token["refreshToken"].toString()) - dataSource.setAccessTime(token["expiredAt"].toString()) - dataSource.setRefreshTime(token["expiredAt"].toString()) - } else throw NeedLoginException() - } - } - val accessToken = dataSource.getAccessToken().first().replace("\"", "") - builder.addHeader("Authorization", "Bearer $accessToken") - } - return chain.proceed(builder.build()) - } -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt b/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt deleted file mode 100644 index c07a2311..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/util/DataTimeFormatter.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.stackknowledge.network.util - -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import java.time.format.DateTimeParseException - -fun Any?.toLocalDateTime(): LocalDateTime? { - val dateString = this?.toString() - if (dateString != null) { - return try { - LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-d'T'HH:mm:ss")) - } catch (e: DateTimeParseException) { - e.printStackTrace() - null - } - } - return null -} \ No newline at end of file diff --git a/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt b/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt deleted file mode 100644 index 1b6e7431..00000000 --- a/core/network/src/main/java/com/stackknowledge/network/util/StackKnowledgeApiHandler.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.stackknowledge.network.util - -import com.stackknowledge.network.exception.* -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import retrofit2.HttpException -import java.lang.Exception -import java.net.SocketTimeoutException -import java.net.UnknownHostException - -class StackKnowledgeApiHandler { - private lateinit var httpRequest: suspend () -> T - - fun httpRequest(httpRequest: suspend () -> T) = - this.apply { this.httpRequest = httpRequest } - - suspend fun sendRequest(): T { - return try { - withContext(Dispatchers.IO) { - httpRequest.invoke() - } - } catch (e: HttpException) { - val message = e.message - throw when(e.code()) { - 400 -> BadRequestException( - message = message - ) - 401 -> UnauthorizedException( - message = message - ) - 403 -> ForBiddenException( - message = message - ) - 404 -> NotFoundException( - message = message - ) - 409 -> ConflictException( - message = message - ) - 500, 501, 502, 503 -> ServerException( - message = message - ) - else -> OtherException( - message = message, - code = e.code() - ) - } - } catch (e: SocketTimeoutException) { - throw TimeOutException(message = e.message) - } catch (e: UnknownHostException) { - throw NetworkException() - } catch (e: NeedLoginException) { - throw NeedLoginException() - } catch (e: Exception) { - throw UnknownException(message = e.message) - } - } -} \ No newline at end of file diff --git a/feature/login/src/androidTest/java/com/stackknowledge/login/ExampleInstrumentedTest.kt b/feature/login/src/androidTest/java/com/stackknowledge/login/ExampleInstrumentedTest.kt deleted file mode 100644 index 6ee0b701..00000000 --- a/feature/login/src/androidTest/java/com/stackknowledge/login/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.stackknowledge.login - -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.teamgrapefruit.login.test", appContext.packageName) - } -} \ No newline at end of file diff --git a/feature/login/src/test/java/com/stackknowledge/login/ExampleUnitTest.kt b/feature/login/src/test/java/com/stackknowledge/login/ExampleUnitTest.kt deleted file mode 100644 index 54deaa69..00000000 --- a/feature/login/src/test/java/com/stackknowledge/login/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.stackknowledge.login - -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 From 58f1ed5fc3efad1abe0d535aa4fe50992642f278 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:54:17 +0900 Subject: [PATCH 32/91] =?UTF-8?q?=F0=9F=94=A5::=20feature:login=20build.gr?= =?UTF-8?q?adle.kts=20BuildConfig=20get=ED=95=A8=EC=88=98=20=EC=82=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/login/build.gradle.kts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index db9844d5..4ecd3bc6 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -8,25 +8,10 @@ plugins { } android { - buildFeatures { - buildConfig = true - } - - defaultConfig { - buildConfigField("String", "REDIRECT_URI", getApiKey("REDIRECT_URI")) - buildConfigField("String", "GOOGLE_CLIENT_ID", getApiKey("GOOGLE_CLIENT_ID")) - buildConfigField("String","SCOPE", getApiKey("SCOPE")) - } namespace = "com.stackknowledge.login" } dependencies { implementation(libs.google.services) implementation(libs.play.services.auth) -} -fun getApiKey(propertyKey: String): String { - val propFile = rootProject.file("./local.properties") - val properties = Properties() - properties.load(FileInputStream(propFile)) - return properties.getProperty(propertyKey) } \ No newline at end of file From d02ba125997b4307dac6dbbb0e7173dd51a78f1a Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:54:34 +0900 Subject: [PATCH 33/91] =?UTF-8?q?=F0=9F=94=A5::=20LoginRequest=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/remote/request/auth/LoginRequest.kt | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt b/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt deleted file mode 100644 index dbef445c..00000000 --- a/core/model/src/main/java/com/stackknowledge/model/remote/request/auth/LoginRequest.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.stackknowledge.model.remote.request.auth - -import com.stackknowledge.model.remote.enumdatatype.Authority - -data class LoginRequest( - val code: String -) \ No newline at end of file From 3e471bcaaa7fde3a08273ae32978f3572072e441 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:55:13 +0900 Subject: [PATCH 34/91] =?UTF-8?q?=E2=9C=A8::=20BuildConfig=20Hilt=EC=97=90?= =?UTF-8?q?=20=EB=93=B1=EB=A1=9D=ED=95=98=EC=97=AC=20=EC=84=A0=EC=96=B8?= =?UTF-8?q?=ED=95=B4=20=EC=82=AC=EC=9A=A9=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=ED=95=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/di/AppConfigModule.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 core/network/src/main/kotlin/com/stackknowledge/di/AppConfigModule.kt diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/AppConfigModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/AppConfigModule.kt new file mode 100644 index 00000000..39f1adc3 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/di/AppConfigModule.kt @@ -0,0 +1,20 @@ +package com.stackknowledge.di + +import com.stackknowledge.network.BuildConfig +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Named + +@Module +@InstallIn(SingletonComponent::class) +object AppConfigModule { + @Provides + @Named("GOOGLE_CLIENT_ID") + fun provideGoogleClientId(): String = BuildConfig.GOOGLE_CLIENT_ID + + @Provides + @Named("SCOPE") + fun provideScope(): String = BuildConfig.SCOPE +} \ No newline at end of file From e848151ee220563c3ea646a708f93aced3bc990f Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:55:54 +0900 Subject: [PATCH 35/91] =?UTF-8?q?=E2=9C=A8::=20Local=20Auth=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/stackknowledge/MainActivity.kt | 9 +- .../com/stackknowledge/di/RepositoryModule.kt | 14 +++ .../repository/auth/AuthRepository.kt | 19 ++++ .../repository/auth/AuthRepositoryImpl.kt | 41 ++++++++ .../datastore/LocalAuthDataSource.kt | 1 - .../datastore/LocalAuthDataSourceImpl.kt | 1 - .../usecase}/auth/LoginStudentUseCase.kt | 8 +- .../usecase}/auth/LoginTeacherUseCase.kt | 6 +- .../usecase}/auth/LogoutUseCase.kt | 4 +- .../usecase}/auth/SaveTokenUseCase.kt | 6 +- .../usecase}/exception/HttpException.kt | 2 +- .../usecase}/exception/NeedLoginException.kt | 2 +- .../enumdata}/Authority.kt | 2 +- .../src/main/kotlin/enumdata/MissionStatus.kt | 6 +- .../remote/request/auth/LoginRequest.kt | 5 + .../remote/response/auth/LoginResponse.kt | 4 +- .../response/mission/MissionResponseModel.kt | 3 - .../remote/response/mission/MissionsModel.kt | 2 +- .../kotlin/com/stackknowledge/api/AuthAPI.kt | 22 +++++ .../datasource/auth/AuthDataSource.kt | 11 +++ .../datasource/auth/AuthDataSourceImpl.kt | 50 ++++++++++ .../com/stackknowledge/di/NetworkModule.kt | 37 ++++--- .../di/RemoteDataSourceModule.kt | 16 +++ .../mission/GetMissionListResponse.kt | 1 - .../dto/response/mission/Missions.kt | 2 +- .../stackknowledge/util/AuthInterceptor.kt | 85 +++++++++++++++- .../com/stackknowledge/login/LoginActivity.kt | 99 +++++++++++++++++-- .../com/stackknowledge/login/LoginScreen.kt | 33 ++----- .../stackknowledge/login/RoleCheckScreen.kt | 45 ++------- .../login/navigation/LoginNavigation.kt | 5 +- .../login/viewmodel/AuthViewModel.kt | 71 +++---------- .../login/viewmodel/util/errorHandling.kt | 10 +- gradle/libs.versions.toml | 3 +- 33 files changed, 441 insertions(+), 184 deletions(-) create mode 100644 core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt create mode 100644 core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/auth/LoginStudentUseCase.kt (57%) rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/auth/LoginTeacherUseCase.kt (63%) rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/auth/LogoutUseCase.kt (67%) rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/auth/SaveTokenUseCase.kt (59%) rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/exception/HttpException.kt (94%) rename core/domain/src/main/{java/com/stackknowledge/domain => kotlin/com/stackknowledge/usecase}/exception/NeedLoginException.kt (80%) rename core/model/src/main/{java/com/stackknowledge/model/remote/enumdatatype => kotlin/enumdata}/Authority.kt (53%) create mode 100644 core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt rename core/model/src/main/{java/com/stackknowledge/model => kotlin}/remote/response/auth/LoginResponse.kt (55%) create mode 100644 core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt create mode 100644 core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt create mode 100644 core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt diff --git a/app/src/main/java/com/stackknowledge/MainActivity.kt b/app/src/main/java/com/stackknowledge/MainActivity.kt index dfb34222..68668f22 100644 --- a/app/src/main/java/com/stackknowledge/MainActivity.kt +++ b/app/src/main/java/com/stackknowledge/MainActivity.kt @@ -1,16 +1,13 @@ package com.stackknowledge -import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.activity.viewModels import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.LoginActivity -import com.stackknowledge.login.viewmodel.AuthViewModel import com.stackknowledge.ui.StackKnowledgeApp import dagger.hilt.android.AndroidEntryPoint @@ -20,7 +17,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - CompositionLocalProvider { + CompositionLocalProvider(LocalViewModelStoreOwner provides this) { StackKnowledgeAndroidTheme { _, _ -> StackKnowledgeApp( windowSizeClass = calculateWindowSizeClass(this@MainActivity), @@ -29,4 +26,4 @@ class MainActivity : ComponentActivity() { } } } -} +} \ No newline at end of file diff --git a/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt b/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt index fa183c26..a9c9cb82 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt @@ -1,9 +1,13 @@ package com.stackknowledge.di +import com.stackknowledge.repository.auth.AuthRepository +import com.stackknowledge.repository.auth.AuthRepositoryImpl import com.stackknowledge.repository.mission.MissionRepository import com.stackknowledge.repository.mission.MissionRepositoryImpl import com.stackknowledge.repository.student.StudentRepository import com.stackknowledge.repository.student.StudentRepositoryImpl +import com.stackknowledge.repository.user.UserRepository +import com.stackknowledge.repository.user.UserRepositoryImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -12,6 +16,11 @@ import dagger.hilt.components.SingletonComponent @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { + @Binds + abstract fun bindAuthRepository( + missionRepositoryImpl: AuthRepositoryImpl + ): AuthRepository + @Binds abstract fun bindMissionRepository( missionRepositoryImpl: MissionRepositoryImpl @@ -21,4 +30,9 @@ abstract class RepositoryModule { abstract fun bindStudentRepository( studentRepositoryImpl: StudentRepositoryImpl ): StudentRepository + + @Binds + abstract fun bindUserRepository( + userRepositoryImpl: UserRepositoryImpl + ): UserRepository } \ No newline at end of file diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt new file mode 100644 index 00000000..9c4c7c51 --- /dev/null +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt @@ -0,0 +1,19 @@ +package com.stackknowledge.repository.auth + +import kotlinx.coroutines.flow.Flow +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse + +interface AuthRepository { + fun loginStudent( + body: LoginRequest, + ): Flow + + fun loginTeacher( + body: LoginRequest, + ): Flow + + suspend fun saveToken(token: LoginResponse) + + fun logout(): Flow +} \ No newline at end of file diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt new file mode 100644 index 00000000..61faeb47 --- /dev/null +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -0,0 +1,41 @@ +package com.stackknowledge.repository.auth + +import android.util.Log +import com.stackknowledge.datasource.auth.AuthDataSource +import com.stackknowledge.datastore.LocalAuthDataSource +import kotlinx.coroutines.flow.Flow +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse +import javax.inject.Inject + +class AuthRepositoryImpl @Inject constructor( + private val authDataSource: AuthDataSource, + private val localDataSource: LocalAuthDataSource +): AuthRepository { + override fun loginStudent(body: LoginRequest): Flow { + Log.e("repository loginStudent", "loginStudent") + return authDataSource.loginStudent( + body = body, + ) + } + + override fun loginTeacher(body: LoginRequest): Flow { + return authDataSource.loginTeacher( + body = body, + ) + } + + override suspend fun saveToken(token: LoginResponse) { + token.let { + localDataSource.setAccessToken(it.accessToken) + localDataSource.setAccessTime(it.expiredAt) + localDataSource.setRefreshToken(it.refreshToken) + localDataSource.setRefreshTime(it.expiredAt) + localDataSource.setAuthorityInfo(it.authority.toString()) + } + } + + override fun logout(): Flow { + return authDataSource.logout() + } +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt index 824e6b57..44d3cef6 100644 --- a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt @@ -1,6 +1,5 @@ package com.stackknowledge.datastore -import com.stackknowledge.model.remote.enumdatatype.Authority import kotlinx.coroutines.flow.Flow interface LocalAuthDataSource { diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt index fa0afae8..c4af7226 100644 --- a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt @@ -4,7 +4,6 @@ import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences import androidx.datastore.preferences.core.edit import com.stackknowledge.datastore.key.AuthPreferenceKey -import com.stackknowledge.model.remote.enumdatatype.Authority import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt similarity index 57% rename from core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt index 3fa37778..5fd54a21 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginStudentUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt @@ -1,7 +1,8 @@ -package com.stackknowledge.domain.auth +package com.stackknowledge.usecase.auth -import com.stackknowledge.data.repository.auth.AuthRepository -import com.stackknowledge.model.remote.request.auth.LoginRequest +import android.util.Log +import com.stackknowledge.repository.auth.AuthRepository +import remote.request.auth.LoginRequest import javax.inject.Inject class LoginStudentUseCase @Inject constructor( @@ -10,6 +11,7 @@ class LoginStudentUseCase @Inject constructor( suspend operator fun invoke( body: LoginRequest, ) = runCatching { + Log.e("useCase loginStudent", "loginStudent") authRepository.loginStudent( body = body, ) diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt similarity index 63% rename from core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt index bdafb7ac..17df1e0e 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/LoginTeacherUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt @@ -1,7 +1,7 @@ -package com.stackknowledge.domain.auth +package com.stackknowledge.usecase.auth -import com.stackknowledge.data.repository.auth.AuthRepository -import com.stackknowledge.model.remote.request.auth.LoginRequest +import com.stackknowledge.repository.auth.AuthRepository +import remote.request.auth.LoginRequest import javax.inject.Inject class LoginTeacherUseCase @Inject constructor( diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt similarity index 67% rename from core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt index 13dc770e..00b0ca88 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/LogoutUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt @@ -1,6 +1,6 @@ -package com.stackknowledge.domain.auth +package com.stackknowledge.usecase.auth -import com.stackknowledge.data.repository.auth.AuthRepository +import com.stackknowledge.repository.auth.AuthRepository import javax.inject.Inject class LogoutUseCase @Inject constructor( diff --git a/core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt similarity index 59% rename from core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt index b64dd2de..425f400f 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/auth/SaveTokenUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt @@ -1,7 +1,7 @@ -package com.stackknowledge.domain.auth +package com.stackknowledge.usecase.auth -import com.stackknowledge.data.repository.auth.AuthRepository -import com.stackknowledge.model.remote.response.auth.LoginResponse +import com.stackknowledge.repository.auth.AuthRepository +import remote.response.auth.LoginResponse import javax.inject.Inject class SaveTokenUseCase @Inject constructor( diff --git a/core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/HttpException.kt similarity index 94% rename from core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/HttpException.kt index 967d0d0d..b9fd36b5 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/exception/HttpException.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/HttpException.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.domain.exception +package com.stackknowledge.usecase.exception class BadRequestException( override val message: String? diff --git a/core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/NeedLoginException.kt similarity index 80% rename from core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt rename to core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/NeedLoginException.kt index 0a6e82bc..fbeb5280 100644 --- a/core/domain/src/main/java/com/stackknowledge/domain/exception/NeedLoginException.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/exception/NeedLoginException.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.domain.exception +package com.stackknowledge.usecase.exception import java.io.IOException diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt b/core/model/src/main/kotlin/enumdata/Authority.kt similarity index 53% rename from core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt rename to core/model/src/main/kotlin/enumdata/Authority.kt index 3db8e4ee..7c8f9761 100644 --- a/core/model/src/main/java/com/stackknowledge/model/remote/enumdatatype/Authority.kt +++ b/core/model/src/main/kotlin/enumdata/Authority.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.model.remote.enumdatatype +package enumdata enum class Authority { ROLE_TEACHER, diff --git a/core/model/src/main/kotlin/enumdata/MissionStatus.kt b/core/model/src/main/kotlin/enumdata/MissionStatus.kt index 9fe37c1b..1a45c91f 100644 --- a/core/model/src/main/kotlin/enumdata/MissionStatus.kt +++ b/core/model/src/main/kotlin/enumdata/MissionStatus.kt @@ -1,7 +1,7 @@ package enumdata enum class MissionStatus { - CLOSED, // Mission을 풀 수 없는 상태 - OPENED, // Mission을 풀 수 있는 상태 - AVAILABLE_OPEN, // Mission을 내일 풀 수 있는 상태 + CLOSED, + OPENED, + AVAILABLE_OPEN, } \ No newline at end of file diff --git a/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt b/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt new file mode 100644 index 00000000..4b393099 --- /dev/null +++ b/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt @@ -0,0 +1,5 @@ +package remote.request.auth + +data class LoginRequest( + val code: String +) \ No newline at end of file diff --git a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt b/core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt similarity index 55% rename from core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt rename to core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt index f1e652d5..5fee62bf 100644 --- a/core/model/src/main/java/com/stackknowledge/model/remote/response/auth/LoginResponse.kt +++ b/core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt @@ -1,6 +1,6 @@ -package com.stackknowledge.model.remote.response.auth +package remote.response.auth -import com.stackknowledge.model.remote.enumdatatype.Authority +import enumdata.Authority data class LoginResponse( val accessToken: String, diff --git a/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt b/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt index 81338719..f78b3954 100644 --- a/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt +++ b/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt @@ -2,9 +2,6 @@ package remote.response.mission import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import enumdatatype.MissionStatus -import remote.user.UserModel -import java.util.UUID @JsonClass(generateAdapter = true) data class MissionResponseModel( diff --git a/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt b/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt index 390b7b55..f9037069 100644 --- a/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt +++ b/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt @@ -2,7 +2,7 @@ package remote.response.mission import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import enumdatatype.MissionStatus +import enumdata.MissionStatus import remote.user.UserModel import java.util.UUID diff --git a/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt b/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt new file mode 100644 index 00000000..c26b03d3 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt @@ -0,0 +1,22 @@ +package com.stackknowledge.api + +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse +import retrofit2.http.Body +import retrofit2.http.DELETE +import retrofit2.http.POST + +interface AuthAPI { + @POST("/auth/student") + suspend fun loginStudent( + @Body body: LoginRequest, + ): LoginResponse + + @POST("/auth/teacher") + suspend fun loginTeacher( + @Body body: LoginRequest, + ): LoginResponse + + @DELETE("/auth") + suspend fun logout() +} diff --git a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt new file mode 100644 index 00000000..b06a5320 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt @@ -0,0 +1,11 @@ +package com.stackknowledge.datasource.auth + +import kotlinx.coroutines.flow.Flow +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse + +interface AuthDataSource { + fun loginStudent(body: LoginRequest): Flow + fun loginTeacher(body: LoginRequest, ): Flow + fun logout(): Flow +} \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt new file mode 100644 index 00000000..a98e80b9 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt @@ -0,0 +1,50 @@ +package com.stackknowledge.datasource.auth + +import android.util.Log +import com.stackknowledge.api.AuthAPI +import com.stackknowledge.util.StackKnowledgeApiHandler +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse +import javax.inject.Inject + +class AuthDataSourceImpl @Inject constructor( + private val authAPI: AuthAPI +) : AuthDataSource { + override fun loginStudent(body: LoginRequest): Flow = flow { + Log.e("dataSource loginStudent", "loginStudent") + emit( + StackKnowledgeApiHandler() + .httpRequest { + authAPI.loginStudent( + body = body, + ) + } + .sendRequest() + ) + Log.e("dataSource loginStudent", "loginStudent") + }.flowOn(Dispatchers.IO) + + override fun loginTeacher(body: LoginRequest): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { + authAPI.loginTeacher( + body = body, + ) + } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) + + override fun logout(): Flow = flow { + emit( + StackKnowledgeApiHandler() + .httpRequest { authAPI.logout() } + .sendRequest() + ) + }.flowOn(Dispatchers.IO) +} \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt index 69535588..b62913d9 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt @@ -1,14 +1,17 @@ package com.stackknowledge.di -import com.msg.network.BuildConfig +import android.util.Log import com.squareup.moshi.Moshi +import com.stackknowledge.api.AuthAPI import com.stackknowledge.api.MissionAPI import com.stackknowledge.api.StudentAPI +import com.stackknowledge.api.UserAPI +import com.stackknowledge.network.BuildConfig +import com.stackknowledge.util.AuthInterceptor import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import okhttp3.CookieJar import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import retrofit2.Retrofit @@ -19,38 +22,35 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) object NetworkModule { + @Provides + fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor = + HttpLoggingInterceptor { message -> Log.v("HTTP", message) } + .setLevel(HttpLoggingInterceptor.Level.BODY) @Provides @Singleton fun provideOkhttpClient( httpLoggingInterceptor: HttpLoggingInterceptor, + authInterceptor: AuthInterceptor ): OkHttpClient { return OkHttpClient.Builder() - .cookieJar(CookieJar.NO_COOKIES) .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) .addInterceptor(httpLoggingInterceptor) + .addInterceptor(authInterceptor) .build() } @Provides @Singleton - fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor { - return HttpLoggingInterceptor().apply { - level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY else HttpLoggingInterceptor.Level.NONE - } - } - - @Provides - @Singleton - fun provideMoshiInstance(): Moshi { + fun provideMoshi(): Moshi { return Moshi.Builder().build() } @Provides @Singleton - fun provideConverterFactory(moshi: Moshi): MoshiConverterFactory { + fun provideMoshiConverterFactory(moshi: Moshi): MoshiConverterFactory { return MoshiConverterFactory.create(moshi) } @@ -66,6 +66,12 @@ object NetworkModule { .addConverterFactory(moshiConverterFactory) .build() } + + @Provides + @Singleton + fun provideAuthAPI(retrofit: Retrofit): AuthAPI = + retrofit.create(AuthAPI::class.java) + @Provides @Singleton fun provideMissionAPI(retrofit: Retrofit): MissionAPI = @@ -75,4 +81,9 @@ object NetworkModule { @Singleton fun provideStudentAPI(retrofit: Retrofit): StudentAPI = retrofit.create(StudentAPI::class.java) + + @Provides + @Singleton + fun provideUserAPI(retrofit: Retrofit): UserAPI = + retrofit.create(UserAPI::class.java) } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt index ae473068..b15bb574 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt @@ -1,9 +1,13 @@ package com.stackknowledge.di +import com.stackknowledge.datasource.auth.AuthDataSource +import com.stackknowledge.datasource.auth.AuthDataSourceImpl import com.stackknowledge.datasource.mission.MissionDataSource import com.stackknowledge.datasource.mission.MissionDataSourceImpl import com.stackknowledge.datasource.student.StudentDataSource import com.stackknowledge.datasource.student.StudentDataSourceImpl +import com.stackknowledge.datasource.user.UserDataSource +import com.stackknowledge.datasource.user.UserDataSourceImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -13,6 +17,12 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) abstract class RemoteDataSourceModule { + @Binds + @Singleton + abstract fun bindAuthDataSource( + authDataSourceImpl: AuthDataSourceImpl + ): AuthDataSource + @Binds @Singleton abstract fun bindMissionDataSource( @@ -24,4 +34,10 @@ abstract class RemoteDataSourceModule { abstract fun bindStudentDataSource( studentDataSourceImpl: StudentDataSourceImpl ): StudentDataSource + + @Binds + @Singleton + abstract fun bindUserDataSource( + userDataSourceImpl: UserDataSourceImpl + ): UserDataSource } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/GetMissionListResponse.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/GetMissionListResponse.kt index 0935e52a..73b90378 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/GetMissionListResponse.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/GetMissionListResponse.kt @@ -1,6 +1,5 @@ package com.stackknowledge.dto.response.mission -import com.stackknowledge.dto.user.User import enumdata.MissionStatus import java.util.UUID diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/Missions.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/Missions.kt index af28f99c..8f387747 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/Missions.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/Missions.kt @@ -2,7 +2,7 @@ package com.stackknowledge.dto.response.mission import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import enumdatatype.MissionStatus +import enumdata.MissionStatus import remote.user.UserModel import java.util.UUID diff --git a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt index da0d6367..0911f817 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt @@ -1,11 +1,90 @@ package com.stackknowledge.util +import com.example.common.exception.NeedLoginException +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory +import com.stackknowledge.network.BuildConfig +import com.stackknowledge.datastore.LocalAuthDataSource +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking import okhttp3.Interceptor +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.RequestBody import okhttp3.Response import javax.inject.Inject -class AuthInterceptor @Inject constructor(): Interceptor { +class AuthInterceptor @Inject constructor( + private val dataSource: LocalAuthDataSource +): Interceptor { + + private val moshi: Moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + + data class TokenResponse( + val accessToken: String, + val refreshToken: String, + val expiredAt: String + ) + override fun intercept(chain: Interceptor.Chain): Response { - TODO("Not yet implemented") + val request = chain.request() + val builder = request.newBuilder() + val currentTime = System.currentTimeMillis().toLocalDateTime() + val ignorePath = listOf("/auth") + val ignoreMethod = listOf("POST") + val path = request.url.encodedPath + val method = request.method + + ignorePath.forEachIndexed { index, s -> + if (path.contains(s) && ignoreMethod[index] == method) + return chain.proceed(request) + } + + runBlocking { + val refreshTime = dataSource.getRefreshTime().first().replace("\"", "") + val accessTime = dataSource.getAccessTime().first().replace("\"", "") + + if (refreshTime == "") { + return@runBlocking + } + + if (currentTime != null) { + if (currentTime.isAfter(refreshTime.toLocalDateTime())) { + throw NeedLoginException() + } + } + + // access 토큰 재 발급 + if (currentTime != null) { + if (currentTime.isAfter(accessTime.toLocalDateTime())) { + val client = OkHttpClient() + val refreshRequest = Request.Builder() + .url(BuildConfig.BASE_URL + "/auth") + .patch(chain.request().body ?: RequestBody.create(null, byteArrayOf())) + .addHeader( + "Refresh-Token", + dataSource.getRefreshToken().first().replace("\"", "") + ) + .build() + val response = client.newCall(refreshRequest).execute() + if (response.isSuccessful) { + val adapter = moshi.adapter(TokenResponse::class.java) + val tokenResponse = adapter.fromJson(response.body!!.string()) + + tokenResponse?.let { + dataSource.setAccessToken(it.accessToken) + dataSource.setRefreshToken(it.refreshToken) + dataSource.setAccessTime(it.expiredAt) + dataSource.setRefreshTime(it.expiredAt) + } ?: throw NeedLoginException() + } else throw NeedLoginException() + } + } + val accessToken = dataSource.getAccessToken().first().replace("\"", "") + builder.addHeader("Authorization", "Bearer $accessToken") + } + return chain.proceed(builder.build()) } -} \ No newline at end of file +} diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt index f378bc11..2ff8b786 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt @@ -1,23 +1,110 @@ package com.stackknowledge.login +import android.content.Intent import android.os.Bundle +import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.runtime.CompositionLocalProvider +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInAccount +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Scope +import com.google.android.gms.tasks.Task import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.viewmodel.AuthViewModel import dagger.hilt.android.AndroidEntryPoint +import remote.request.auth.LoginRequest +import javax.inject.Inject +import javax.inject.Named @AndroidEntryPoint class LoginActivity : ComponentActivity() { + @Inject + @Named("GOOGLE_CLIENT_ID") + lateinit var googleClientId: String + + @Inject + @Named("SCOPE") + lateinit var scope: String + + private val viewModel by viewModels() + private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } + + private val googleSignInLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + val task: Task = GoogleSignIn.getSignedInAccountFromIntent(result.data) + handleGoogleSignInResult(task) + } + + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContent { - CompositionLocalProvider { - StackKnowledgeAndroidTheme { _, _ -> - LoginRoute() + StackKnowledgeAndroidTheme { _, _ -> + //임의로 LoginFlow 설정 이거 수정해야함 + RoleCheckRoute( + onTeacherButtonClick = { isTeacher -> + viewModel.showLoginRoute.value = true + viewModel.isTeacher.value = isTeacher + }, + onStudentButtonClick = { isStudent -> + viewModel.showLoginRoute.value = true + viewModel.isStudent.value = isStudent + } + ) + if (viewModel.showLoginRoute.value) { + LoginRoute( + onGoogleLoginButtonClicked = { + googleSocialLogin() + } + ) + } + } + } + } + + private fun googleSocialLogin() { + googleSignInClient.signOut().addOnCompleteListener { + val signInIntent = googleSignInClient.signInIntent + googleSignInLauncher.launch(signInIntent) + } + } + + private fun getGoogleClient(): GoogleSignInClient { + val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestScopes(Scope(scope)) + .requestServerAuthCode(googleClientId) + .requestIdToken(googleClientId) + .requestEmail() + .build() + + return GoogleSignIn.getClient(this@LoginActivity, googleSignInOptions) + } + + private fun handleGoogleSignInResult(task: Task) { + Log.e("handleGoogleSignInResult", "${task.result}") + try { + val account = task.getResult(ApiException::class.java) + account?.idToken?.let { idToken -> + if (viewModel.isStudent.value) { + viewModel.loginStudent(body = LoginRequest(code = idToken)) + } else { + viewModel.loginTeacher(body = LoginRequest(code = idToken)) } + moveToMainActivity() } + } catch (e: ApiException) { + Log.e("LoginActivity", "Google sign-in failed: ${e.statusCode}") } } -} + + private fun moveToMainActivity() { + val intent = Intent().setClassName(this, "com.stackknowledge.MainActivity") + startActivity(intent) + finish() + } +} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 0d73c623..34c66ec6 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -1,6 +1,5 @@ package com.stackknowledge.login -import androidx.activity.ComponentActivity import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -15,47 +14,25 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.button.GoogleButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.background.LoginBackground import com.stackknowledge.login.viewmodel.AuthViewModel -import androidx.activity.compose.rememberLauncherForActivityResult -import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.runtime.rememberCoroutineScope import com.stackknowledge.login.viewmodel.util.Event -import kotlinx.coroutines.launch @Composable fun LoginRoute( - viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), + onGoogleLoginButtonClicked: () -> Unit = {}, ) { - val context = LocalContext.current - val coroutineScope = rememberCoroutineScope() - - rememberLauncherForActivityResult( - contract = ActivityResultContracts.StartActivityForResult() - ) { result -> - viewModel.handleGoogleSignInResult(result) - } - LoginScreen( onGoogleLoginButtonClicked = { - viewModel.googleSocialLogin() - coroutineScope.launch { - getLoginData( - viewModel = viewModel, - onSuccess = {}, - onFailure = {} - ) - } - }, + onGoogleLoginButtonClicked() + } ) } @@ -97,7 +74,9 @@ fun LoginScreen( ) { GoogleButton( modifier = modifier.height(60.dp), - onClick = onGoogleLoginButtonClicked + onClick = { + onGoogleLoginButtonClicked() + } ) } } diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt index 5af2d803..e51034d1 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -1,6 +1,6 @@ package com.stackknowledge.login -import androidx.activity.ComponentActivity + import androidx.compose.foundation.background import com.stackknowledge.design_system.R import androidx.compose.foundation.layout.Box @@ -14,11 +14,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material3.Text import androidx.compose.runtime.Composable -<<<<<<< Updated upstream -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -======= ->>>>>>> Stashed changes import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -33,49 +28,26 @@ import com.stackknowledge.login.background.LoginBackground import com.stackknowledge.login.viewmodel.AuthViewModel @Composable -fun RoleCheckRoute( - onRoleButtonClick: () -> Unit, - viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), +internal fun RoleCheckRoute( + onTeacherButtonClick: (Boolean) -> Unit = {}, + onStudentButtonClick: (Boolean) -> Unit = {}, ) { RoleCheckScreen( -<<<<<<< Updated upstream - navigateToLogin = navigateToLogin, - isStudent = isStudent, - isTeacher = isTeacher, - viewModel = viewModel -======= onTeacherButtonClick = { isTeacher -> - viewModel.isTeacher.value = isTeacher + onTeacherButtonClick(isTeacher) }, onStudentButtonClick = { isStudent -> - viewModel.isStudent.value = isStudent + onStudentButtonClick(isStudent) } ->>>>>>> Stashed changes ) } @Composable -fun RoleCheckScreen( +internal fun RoleCheckScreen( modifier: Modifier = Modifier, onTeacherButtonClick: (Boolean) -> Unit, onStudentButtonClick: (Boolean) -> Unit, ) { -<<<<<<< Updated upstream - val student by viewModel.isStudent.collectAsStateWithLifecycle() - // val teacher by viewModel.isTeacher.collectAsStateWithLifecycle() - - LaunchedEffect(student) { - if (student) { - Log.d("testt",student.toString()) - isStudent(student) - navigateToLogin() - } /*else { - isStudent(!student) - navigateToLogin() - }*/ - } -======= ->>>>>>> Stashed changes StackKnowledgeAndroidTheme { colors, typography -> Box( modifier = modifier.background(color = colors.WHITE), @@ -135,11 +107,8 @@ fun RoleCheckScreen( @Preview @Composable fun RoleCheckScreenPre() { -<<<<<<< Updated upstream -======= RoleCheckScreen( onTeacherButtonClick = {}, onStudentButtonClick = {}, ) ->>>>>>> Stashed changes } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index 17ca4875..5abb9d45 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -16,7 +16,9 @@ fun NavController.navigateToLogin(navOptions: NavOptions? = null) { fun NavGraphBuilder.loginScreen() { composable(route = loginRoute) { - LoginRoute() + LoginRoute( + + ) } } @@ -29,7 +31,6 @@ fun NavGraphBuilder.roleCheckScreen( ) { composable(route = roleCheckRoute) { RoleCheckRoute( - onRoleButtonClick = onRoleButtonClick ) } } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index e7c390b1..f4aff683 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -1,26 +1,19 @@ package com.stackknowledge.login.viewmodel -import android.app.Activity -import android.content.Context -import androidx.activity.result.ActivityResult +import android.util.Log +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.google.android.gms.auth.api.signin.GoogleSignIn -import com.google.android.gms.auth.api.signin.GoogleSignInClient -import com.google.android.gms.auth.api.signin.GoogleSignInOptions -import com.google.android.gms.common.api.ApiException -import com.google.android.gms.common.api.Scope -import com.stackknowledge.domain.auth.SaveTokenUseCase -import com.stackknowledge.domain.auth.LoginStudentUseCase -import com.stackknowledge.domain.auth.LoginTeacherUseCase -import com.stackknowledge.login.BuildConfig +import com.stackknowledge.usecase.auth.SaveTokenUseCase +import com.stackknowledge.usecase.auth.LoginStudentUseCase +import com.stackknowledge.usecase.auth.LoginTeacherUseCase import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.login.viewmodel.util.errorHandling -import com.stackknowledge.model.remote.request.auth.LoginRequest -import com.stackknowledge.model.remote.response.auth.LoginResponse +import remote.request.auth.LoginRequest +import remote.response.auth.LoginResponse import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch @@ -29,7 +22,6 @@ import javax.inject.Inject @HiltViewModel class AuthViewModel @Inject constructor( - @ApplicationContext private val context: Context, private val loginStudentUseCase: LoginStudentUseCase, private val loginTeacherUseCase: LoginTeacherUseCase, private val saveTokenUseCase: SaveTokenUseCase, @@ -40,24 +32,15 @@ class AuthViewModel @Inject constructor( private val _loginResponse = MutableStateFlow>(Event.Loading) val loginResponse = _loginResponse.asStateFlow() - private val _googleAuthResult = MutableStateFlow(null) - val googleAuthResult = _googleAuthResult.asStateFlow() - - private val _signInError = MutableStateFlow(null) - val signInError = _signInError.asStateFlow() - - private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } var isTeacher = mutableStateOf(false) private set var isStudent = mutableStateOf(false) private set - private var googleAuthCode = mutableStateOf("") + var showLoginRoute = mutableStateOf(false) + private set - init { - _googleAuthResult.value = null - } internal fun loginStudent( body: LoginRequest, @@ -65,6 +48,7 @@ class AuthViewModel @Inject constructor( loginStudentUseCase( body = body, ).onSuccess { + Log.e("viewModel loginStudent", "loginStudent") it.catch { remoteError -> _loginResponse.value = remoteError.errorHandling() }.collect { response -> @@ -102,37 +86,4 @@ class AuthViewModel @Inject constructor( _saveTokenRequest.value = it.errorHandling() } } - - internal fun googleSocialLogin() = viewModelScope.launch { - googleSignInClient.signOut() - val signInIntent = googleSignInClient.signInIntent - _googleAuthResult.value = ActivityResult(Activity.RESULT_OK, signInIntent) - } - - fun handleGoogleSignInResult(result: ActivityResult) { - val task = GoogleSignIn.getSignedInAccountFromIntent(result.data) - try { - val account = task.getResult(ApiException::class.java) - account.serverAuthCode?.let { authCode -> - setGoogleAuthCode(authCode) - } - _googleAuthResult.value = result - } catch (e: ApiException) { - _signInError.value = e.stackTraceToString() - } - } - - private fun getGoogleClient(): GoogleSignInClient { - val googleSignInOption = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestScopes(Scope("${BuildConfig.SCOPE}")) - .requestServerAuthCode("${BuildConfig.GOOGLE_CLIENT_ID}") - .requestEmail() - .build() - - return GoogleSignIn.getClient(context, googleSignInOption) - } - - private fun setGoogleAuthCode(authCode: String) { - googleAuthCode.value = authCode - } } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt index c923e02a..ae9e40e0 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt @@ -1,7 +1,15 @@ package com.stackknowledge.login.viewmodel.util import android.util.Log -import com.stackknowledge.domain.exception.* +import com.stackknowledge.usecase.exception.BadRequestException +import com.stackknowledge.usecase.exception.ConflictException +import com.stackknowledge.usecase.exception.ForBiddenException +import com.stackknowledge.usecase.exception.NeedLoginException +import com.stackknowledge.usecase.exception.NotAcceptableException +import com.stackknowledge.usecase.exception.NotFoundException +import com.stackknowledge.usecase.exception.ServerException +import com.stackknowledge.usecase.exception.TimeOutException +import com.stackknowledge.usecase.exception.UnauthorizedException suspend fun Throwable.errorHandling( badRequestAction: suspend () -> Unit = {}, diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 693bd482..590dbab9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ org-jetbrains-kotlin-android = "1.8.10" lifecycle-runtime-ktx = "2.6.2" google-services = "4.4.0" play-services-auth = "20.7.0" -moshi = "1.15.1" +moshi = "1.15.0" [libraries] #Define Library @@ -100,6 +100,7 @@ kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "lint" } moshi = { group = "com.squareup.moshi", name = "moshi", version.ref = "moshi" } +moshi-kotlin = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi" } okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } From da55bcfcad9b0bc643047758e6211f8a0cf534ce Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Mon, 1 Jul 2024 16:57:03 +0900 Subject: [PATCH 36/91] =?UTF-8?q?:bug:=20::=20ksp=20->=20implementation?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20ksp=EC=97=90=EB=9F=AC=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :: ksp -> implementation으로 ksp에러 fix --- .../kotlin/sessions/kotlin-compiler-609898098056680773.salive | 0 core/network/build.gradle.kts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive diff --git a/build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive b/build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive new file mode 100644 index 00000000..e69de29b diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 54d91b03..87e47d90 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -36,7 +36,7 @@ dependencies { implementation(libs.retrofit.kotlin.serialization) implementation(libs.retrofit.moshi.converter) implementation(libs.moshi) - ksp(libs.retrofit.moshi.codegen) + implementation(libs.retrofit.moshi.codegen) } fun getApiKey(propertyKey: String): String { val propFile = rootProject.file("./local.properties") From 5956027aaffffec7d4771abf57cf35930ec0a8be Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:25:01 +0900 Subject: [PATCH 37/91] =?UTF-8?q?=E2=9C=A8::=20google-services.json=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/google-services.json | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 app/google-services.json diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 00000000..6219a2d1 --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "322299804217", + "project_id": "stack-knowledge-v2", + "storage_bucket": "stack-knowledge-v2.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:322299804217:android:e15d7c6ad9b47cc65e2be8", + "android_client_info": { + "package_name": "com.kdn.stack_knowledge" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBxMjD7Mg9vzfBiuZVBzyR12Ubr-uEZ_hQ" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file From 9329a1f755c6e3ab145073b99a0bf6c24c7f061f Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:25:33 +0900 Subject: [PATCH 38/91] =?UTF-8?q?=E2=9C=A8::=20LoginResponse=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20LoginUiState=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/viewmodel/uistate/LoginUiState.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/uistate/LoginUiState.kt diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/uistate/LoginUiState.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/uistate/LoginUiState.kt new file mode 100644 index 00000000..89f1a33f --- /dev/null +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/uistate/LoginUiState.kt @@ -0,0 +1,9 @@ +package com.stackknowledge.login.viewmodel.uistate + +import remote.response.auth.LoginResponseModel + +sealed interface LoginUiState { + object Loading : LoginUiState + data class Success(val loginResponseModel: LoginResponseModel) : LoginUiState + data class Error(val exception: Throwable) : LoginUiState +} \ No newline at end of file From 4dff910749ab6cd0db5e56da1b4ebd1811363b76 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:25:46 +0900 Subject: [PATCH 39/91] =?UTF-8?q?=E2=9C=A8::=20LoginResponseModel=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/remote/response/auth/LoginResponseModel.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 core/model/src/main/kotlin/remote/response/auth/LoginResponseModel.kt diff --git a/core/model/src/main/kotlin/remote/response/auth/LoginResponseModel.kt b/core/model/src/main/kotlin/remote/response/auth/LoginResponseModel.kt new file mode 100644 index 00000000..2517da7e --- /dev/null +++ b/core/model/src/main/kotlin/remote/response/auth/LoginResponseModel.kt @@ -0,0 +1,10 @@ +package remote.response.auth + +import enumdata.Authority + +data class LoginResponseModel( + val accessToken: String, + val refreshToken: String, + val expiredAt: String, + val authority: Authority, +) \ No newline at end of file From 23c740ab8645292bce15640c5d2a13684bd6c420 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:25:52 +0900 Subject: [PATCH 40/91] =?UTF-8?q?=E2=9C=A8::=20LoginResponseMapper=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/response/auth/LoginResponseMapper.kt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt diff --git a/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt b/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt new file mode 100644 index 00000000..4c3b614d --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt @@ -0,0 +1,11 @@ +package com.stackknowledge.mapper.response.auth + +import com.stackknowledge.dto.response.auth.LoginResponse +import remote.response.auth.LoginResponseModel + +fun LoginResponse.toModel(): LoginResponseModel = LoginResponseModel( + accessToken = accessToken, + refreshToken = refreshToken, + expiredAt = expiredAt, + authority = authority, +) \ No newline at end of file From 3c4222f327f76b74912b365bf188dfe1f1784391 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:26:05 +0900 Subject: [PATCH 41/91] =?UTF-8?q?=E2=9C=A8::=20LoginResponse=20Moshi=20?= =?UTF-8?q?=EC=A7=81=EB=A0=AC=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/remote/response/auth/LoginResponse.kt | 10 ---------- .../dto/response/auth/LoginResponse.kt | 13 +++++++++++++ 2 files changed, 13 insertions(+), 10 deletions(-) delete mode 100644 core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt create mode 100644 core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt diff --git a/core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt b/core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt deleted file mode 100644 index 5fee62bf..00000000 --- a/core/model/src/main/kotlin/remote/response/auth/LoginResponse.kt +++ /dev/null @@ -1,10 +0,0 @@ -package remote.response.auth - -import enumdata.Authority - -data class LoginResponse( - val accessToken: String, - val refreshToken: String, - val expiredAt: String, - val authority: Authority -) \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt new file mode 100644 index 00000000..1827f577 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt @@ -0,0 +1,13 @@ +package com.stackknowledge.dto.response.auth + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import enumdata.Authority + +@JsonClass(generateAdapter = true) +data class LoginResponse( + @Json(name = "accessToken") val accessToken: String, + @Json(name = "refreshToken") val refreshToken: String, + @Json(name = "expiredAt") val expiredAt: String, + @Json(name = "authority") val authority: Authority +) \ No newline at end of file From 72305902ad0792318573a9e1e8d2915183321d36 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:26:23 +0900 Subject: [PATCH 42/91] =?UTF-8?q?=E2=9C=A8::=20LoginRequestModel=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/remote/request/auth/LoginRequestModel.kt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 core/model/src/main/kotlin/remote/request/auth/LoginRequestModel.kt diff --git a/core/model/src/main/kotlin/remote/request/auth/LoginRequestModel.kt b/core/model/src/main/kotlin/remote/request/auth/LoginRequestModel.kt new file mode 100644 index 00000000..e002a47c --- /dev/null +++ b/core/model/src/main/kotlin/remote/request/auth/LoginRequestModel.kt @@ -0,0 +1,5 @@ +package remote.request.auth + +data class LoginRequestModel( + val code: String, +) From 22ff2540a57f2980a4386d31cd7b93197b356c1f Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:26:29 +0900 Subject: [PATCH 43/91] =?UTF-8?q?=E2=9C=A8::=20LoginRequestMapper=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/request/auth/LoginRequestMapper.kt | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 core/network/src/main/kotlin/com/stackknowledge/mapper/request/auth/LoginRequestMapper.kt diff --git a/core/network/src/main/kotlin/com/stackknowledge/mapper/request/auth/LoginRequestMapper.kt b/core/network/src/main/kotlin/com/stackknowledge/mapper/request/auth/LoginRequestMapper.kt new file mode 100644 index 00000000..bfda8797 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/mapper/request/auth/LoginRequestMapper.kt @@ -0,0 +1,8 @@ +package com.stackknowledge.mapper.request.auth + +import com.stackknowledge.dto.request.auth.LoginRequest +import remote.request.auth.LoginRequestModel + +fun LoginRequestModel.toDto(): LoginRequest = LoginRequest( + code = this.code, +) \ No newline at end of file From cc2db79d84b700b09502f7d1af0dcfd324a9d5ba Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:27:01 +0900 Subject: [PATCH 44/91] =?UTF-8?q?=E2=9C=A8::=20MainActivity=20GoogleSignIn?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20app=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A8=ED=82=A4=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kdn/stack_knowledge/MainActivity.kt | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt diff --git a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt new file mode 100644 index 00000000..93bedc55 --- /dev/null +++ b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt @@ -0,0 +1,125 @@ +package com.kdn.stack_knowledge + +import android.os.Bundle +import android.util.Log +import android.widget.Toast +import androidx.activity.ComponentActivity +import androidx.activity.OnBackPressedCallback +import androidx.activity.compose.setContent +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.CompositionLocalProvider +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import com.google.android.gms.auth.api.signin.GoogleSignIn +import com.google.android.gms.auth.api.signin.GoogleSignInAccount +import com.google.android.gms.auth.api.signin.GoogleSignInClient +import com.google.android.gms.auth.api.signin.GoogleSignInOptions +import com.google.android.gms.common.api.ApiException +import com.google.android.gms.common.api.Scope +import com.google.android.gms.tasks.Task +import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme +import com.stackknowledge.login.viewmodel.AuthViewModel +import com.kdn.stack_knowledge.ui.StackKnowledgeApp +import com.stackknowledge.user.R +import dagger.hilt.android.AndroidEntryPoint +import remote.request.auth.LoginRequestModel +import javax.inject.Inject +import javax.inject.Named + +@AndroidEntryPoint +class MainActivity : ComponentActivity() { + + @Inject + @Named("GOOGLE_CLIENT_ID") + lateinit var googleClientId: String + + @Inject + @Named("SCOPE") + lateinit var scope: String + + private val viewModel by viewModels() + + private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } + + private val googleSignInLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + val task: Task = + GoogleSignIn.getSignedInAccountFromIntent(result.data) + handleGoogleSignInResult(task) + } + + private var doubleBackToExitPressedOnce = false + + private var backPressedTimestamp = 0L + + private val onBackPressedCallback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + controlTheStackWhenBackPressed() + } + } + + @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.onBackPressedDispatcher.addCallback(this, onBackPressedCallback) + setContent { + CompositionLocalProvider(LocalViewModelStoreOwner provides this) { + StackKnowledgeAndroidTheme { _, _ -> + StackKnowledgeApp( + windowSizeClass = calculateWindowSizeClass(this@MainActivity), + onLoginButtonClick = { + googleSocialLogin() + } + ) + } + } + } + } + + private fun controlTheStackWhenBackPressed() { + val currentTime = System.currentTimeMillis() + if (doubleBackToExitPressedOnce && currentTime - backPressedTimestamp <= 2000) { + finishAffinity() + } else { + doubleBackToExitPressedOnce = true + backPressedTimestamp = currentTime + Toast.makeText(this, getString(R.string.close_app), Toast.LENGTH_SHORT).show() + } + } + + private fun googleSocialLogin() { + googleSignInClient.signOut().addOnCompleteListener { + val signInIntent = googleSignInClient.signInIntent + googleSignInLauncher.launch(signInIntent) + } + } + + private fun getGoogleClient(): GoogleSignInClient { + val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestScopes(Scope(scope)) + .requestServerAuthCode(googleClientId) + .requestEmail() + .build() + + return GoogleSignIn.getClient(this@MainActivity, googleSignInOptions) + } + + private fun handleGoogleSignInResult(task: Task) { + try { + val account = task.getResult(ApiException::class.java) + + with(viewModel) { + if (isStudent.value) { + Log.e("serverAuthCode", account.serverAuthCode.toString()) + loginStudent(body = LoginRequestModel(code = account.serverAuthCode.toString())) + } else { + loginTeacher(body = LoginRequestModel(code = account.serverAuthCode.toString())) + } + } + } catch (e: ApiException) { + Log.e("GoogleSignIn", "Google sign-in failed: ${e.statusCode}", e) + } + } +} \ No newline at end of file From e202f4102e8b80af0c1b078fb7b347c214f8d604 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 12:27:22 +0900 Subject: [PATCH 45/91] =?UTF-8?q?=E2=9C=A8::=20app=20=EB=82=B4=EB=B6=80=20?= =?UTF-8?q?file=20=EB=A6=AC=ED=8C=A8=ED=82=A4=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StackKnowledgeApplication.kt | 2 +- .../navigation/StackKnowledgeNavHost.kt | 17 +++++++++-------- .../navigation/TopLevelDestination.kt | 5 +++++ .../navigation/util/BottomNavigationNavigate.kt | 4 ++-- .../stack_knowledge}/ui/StackKnowledgeApp.kt | 13 ++++--------- .../ui/StackKnowledgeAppState.kt | 9 ++++----- 6 files changed, 25 insertions(+), 25 deletions(-) rename app/src/main/java/com/{stackknowledge => kdn/stack_knowledge}/StackKnowledgeApplication.kt (81%) rename app/src/main/java/com/{stackknowledge => kdn/stack_knowledge}/navigation/StackKnowledgeNavHost.kt (88%) create mode 100644 app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt rename app/src/main/java/com/{stackknowledge => kdn/stack_knowledge}/navigation/util/BottomNavigationNavigate.kt (96%) rename app/src/main/java/com/{stackknowledge => kdn/stack_knowledge}/ui/StackKnowledgeApp.kt (62%) rename app/src/main/java/com/{stackknowledge => kdn/stack_knowledge}/ui/StackKnowledgeAppState.kt (88%) diff --git a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt b/app/src/main/java/com/kdn/stack_knowledge/StackKnowledgeApplication.kt similarity index 81% rename from app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt rename to app/src/main/java/com/kdn/stack_knowledge/StackKnowledgeApplication.kt index 5f9f76c4..21f9b8e6 100644 --- a/app/src/main/java/com/stackknowledge/StackKnowledgeApplication.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/StackKnowledgeApplication.kt @@ -1,4 +1,4 @@ -package com.stackknowledge +package com.kdn.stack_knowledge import android.app.Application import dagger.hilt.android.HiltAndroidApp diff --git a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt similarity index 88% rename from app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt rename to app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index 8207202d..8cceb9f2 100644 --- a/app/src/main/java/com/stackknowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.navigation +package com.kdn.stack_knowledge.navigation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -7,10 +7,9 @@ import com.stackknowledge.login.navigation.loginScreen import com.stackknowledge.login.navigation.navigateToLogin import com.stackknowledge.login.navigation.roleCheckRoute import com.stackknowledge.login.navigation.roleCheckScreen -import com.stackknowledge.main.navigation.mainPageRoute import com.stackknowledge.main.navigation.mainScreen import com.stackknowledge.main.navigation.navigateToMain -import com.stackknowledge.navigation.util.bottomNavigationNavigate +import com.kdn.stack_knowledge.navigation.util.bottomNavigationNavigate import com.stackknowledge.ranking.navigation.rankingScreen import com.stackknowledge.ranking.navigation.teacherRankingScreen import com.stackknowledge.score_mission.navigation.gradingAnswerScreen @@ -18,10 +17,8 @@ import com.stackknowledge.score_mission.navigation.navigateToGradingAnswer import com.stackknowledge.score_mission.navigation.solvedMissionScreen import com.stackknowledge.shop.navigation.shopScreen import com.stackknowledge.shop.navigation.teacherShopScreen -import com.stackknowledge.ui.StackKnowledgeAppState -import com.stackkowledge.mission.navigation.createMissionRoute +import com.kdn.stack_knowledge.ui.StackKnowledgeAppState import com.stackkowledge.mission.navigation.createMissionScreen -import com.stackkowledge.mission.navigation.entireMissionRoute import com.stackkowledge.mission.navigation.entireMissionScreen import com.stackkowledge.mission.navigation.navigateToResolveMission import com.stackkowledge.mission.navigation.resolveMissionScreen @@ -31,6 +28,7 @@ fun StackKnowledgeNavHost( appState: StackKnowledgeAppState, startDestination: String = roleCheckRoute, modifier: Modifier = Modifier, + onLoginButtonClick: () -> Unit = {}, ) { val navController = appState.navController @@ -39,9 +37,12 @@ fun StackKnowledgeNavHost( startDestination = startDestination, modifier = modifier ) { - loginScreen() + loginScreen( + onSuccess = navController::navigateToMain, + onLoginButtonClick = onLoginButtonClick + ) roleCheckScreen( - + onRoleButtonClick = navController::navigateToLogin ) mainScreen( onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) } diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt new file mode 100644 index 00000000..03b87dc0 --- /dev/null +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt @@ -0,0 +1,5 @@ +package com.kdn.stack_knowledge.navigation + +enum class TopLevelDestination { + ROLE_CHECK, +} \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/navigation/util/BottomNavigationNavigate.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt similarity index 96% rename from app/src/main/java/com/stackknowledge/navigation/util/BottomNavigationNavigate.kt rename to app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt index 77adbbf6..cf47d712 100644 --- a/app/src/main/java/com/stackknowledge/navigation/util/BottomNavigationNavigate.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.navigation.util +package com.kdn.stack_knowledge.navigation.util import androidx.navigation.NavController import androidx.navigation.NavGraph.Companion.findStartDestination @@ -12,7 +12,7 @@ import com.stackknowledge.shop.navigation.navigateToShop import com.stackknowledge.shop.navigation.navigateToTeacherShop import com.stackkowledge.mission.navigation.navigateToCreateMission import com.stackkowledge.mission.navigation.navigateToEntireMission -import enumdatatype.Authority +import enumdata.Authority fun bottomNavigationNavigate( role: Authority, diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt similarity index 62% rename from app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt rename to app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt index b8f55d2a..ee988f04 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt @@ -1,9 +1,9 @@ -package com.stackknowledge.ui +package com.kdn.stack_knowledge.ui import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.runtime.Composable import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.navigation.StackKnowledgeNavHost +import com.kdn.stack_knowledge.navigation.StackKnowledgeNavHost @Composable fun StackKnowledgeApp( @@ -11,17 +11,12 @@ fun StackKnowledgeApp( appState: StackKnowledgeAppState = rememberStackKnowledgeAppState( windowSizeClass = windowSizeClass ), + onLoginButtonClick: () -> Unit = {}, ) { StackKnowledgeAndroidTheme { _, _ -> -<<<<<<< HEAD StackKnowledgeNavHost( appState = appState, + onLoginButtonClick = onLoginButtonClick ) -======= - StackKnowledgeNavHost( - appState = appState, - //startDestination = "" <- auth 작업후에 추가 - ) ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b } } \ No newline at end of file diff --git a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt similarity index 88% rename from app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt rename to app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt index 5f242b09..59fe2488 100644 --- a/app/src/main/java/com/stackknowledge/ui/StackKnowledgeAppState.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt @@ -1,4 +1,4 @@ -package com.stackknowledge.ui +package com.kdn.stack_knowledge.ui import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass @@ -6,13 +6,12 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.navigation.NavController import androidx.navigation.NavDestination import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController -import com.stackknowledge.login.navigation.loginRoute -import com.stackknowledge.navigation.TopLevelDestination +import com.kdn.stack_knowledge.navigation.TopLevelDestination +import com.stackknowledge.login.navigation.roleCheckRoute import kotlinx.coroutines.CoroutineScope @Composable @@ -46,7 +45,7 @@ class StackKnowledgeAppState( val currentTopLevelDestination: TopLevelDestination? @Composable get() = when(currentDestination?.route) { - loginRoute -> TopLevelDestination.LOGIN + roleCheckRoute -> TopLevelDestination.ROLE_CHECK else -> null } From 4f57712f634b0a73524e4b240491b289a8bfdcc8 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:45:57 +0900 Subject: [PATCH 46/91] =?UTF-8?q?=E2=9C=A8::=20LoginRequest=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/dto/request/auth/LoginRequest.kt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt new file mode 100644 index 00000000..bdc701b4 --- /dev/null +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt @@ -0,0 +1,9 @@ +package com.stackknowledge.dto.request.auth + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +data class LoginRequest( + @Json(name = "code") val code: String +) \ No newline at end of file From 7e1b91151e646b79ce6a8ec59498cec5129bc672 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:46:47 +0900 Subject: [PATCH 47/91] =?UTF-8?q?=F0=9F=94=A5::=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=EB=90=9C=20enum=20=EA=B4=80=EB=A6=AC=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/model/src/main/kotlin/enumdatatype/Authority.kt | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 core/model/src/main/kotlin/enumdatatype/Authority.kt diff --git a/core/model/src/main/kotlin/enumdatatype/Authority.kt b/core/model/src/main/kotlin/enumdatatype/Authority.kt deleted file mode 100644 index 4049a8d7..00000000 --- a/core/model/src/main/kotlin/enumdatatype/Authority.kt +++ /dev/null @@ -1,6 +0,0 @@ -package enumdatatype - -enum class Authority { - ROLE_STUDENT, - ROLE_TEACHER -} \ No newline at end of file From 8ced4118edd8a08798bfc6afd5c17d0557d627bc Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:46:59 +0900 Subject: [PATCH 48/91] =?UTF-8?q?=F0=9F=94=A5::=20sessions=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/sessions/kotlin-compiler-609898098056680773.salive | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive diff --git a/build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive b/build-logic/build/kotlin/sessions/kotlin-compiler-609898098056680773.salive deleted file mode 100644 index e69de29b..00000000 From 2014057410c0c028e14f4a01212a3a024b9519c2 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:47:16 +0900 Subject: [PATCH 49/91] =?UTF-8?q?=F0=9F=94=A5::=20LoginActivity=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/login/LoginActivity.kt | 103 ------------------ 1 file changed, 103 deletions(-) delete mode 100644 feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt deleted file mode 100644 index 059bd652..00000000 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginActivity.kt +++ /dev/null @@ -1,103 +0,0 @@ -package com.stackknowledge.login - -import android.content.Intent -import android.os.Bundle -import android.util.Log -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.result.contract.ActivityResultContracts -import androidx.activity.viewModels -import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.login.viewmodel.AuthViewModel -import dagger.hilt.android.AndroidEntryPoint -import remote.request.auth.LoginRequest -import javax.inject.Inject -import javax.inject.Named - -@AndroidEntryPoint -class LoginActivity : ComponentActivity() { - @Inject - @Named("GOOGLE_CLIENT_ID") - lateinit var googleClientId: String - - @Inject - @Named("SCOPE") - lateinit var scope: String - - private val viewModel by viewModels() -// private val googleSignInClient: GoogleSignInClient by lazy { getGoogleClient() } -// -// private val googleSignInLauncher = -// registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> -// val task: Task = GoogleSignIn.getSignedInAccountFromIntent(result.data) -// handleGoogleSignInResult(task) -// } - - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) -// setContent { -// StackKnowledgeAndroidTheme { _, _ -> -// //임의로 LoginFlow 설정 이거 수정해야함 -// RoleCheckRoute( -// onTeacherButtonClick = { isTeacher -> -// viewModel.showLoginRoute.value = true -// viewModel.isTeacher.value = isTeacher -// }, -// onStudentButtonClick = { isStudent -> -// viewModel.showLoginRoute.value = true -// viewModel.isStudent.value = isStudent -// } -// ) -// if (viewModel.showLoginRoute.value) { -// LoginRoute( -// onGoogleLoginButtonClicked = { -// googleSocialLogin() -// } -// ) -// } -// } -// } - } - -// private fun googleSocialLogin() { -// googleSignInClient.signOut().addOnCompleteListener { -// val signInIntent = googleSignInClient.signInIntent -// googleSignInLauncher.launch(signInIntent) -// } -// } - -// private fun getGoogleClient(): GoogleSignInClient { -// val googleSignInOptions = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) -// .requestScopes(Scope(scope)) -// .requestServerAuthCode(googleClientId) -// .requestIdToken(googleClientId) -// .requestEmail() -// .build() -// -// return GoogleSignIn.getClient(this@LoginActivity, googleSignInOptions) -// } -// -// private fun handleGoogleSignInResult(task: Task) { -// Log.e("handleGoogleSignInResult", "${task.result}") -// try { -// val account = task.getResult(ApiException::class.java) -// account?.idToken?.let { idToken -> -// if (viewModel.isStudent.value) { -// viewModel.loginStudent(body = LoginRequest(code = idToken)) -// } else { -// viewModel.loginTeacher(body = LoginRequest(code = idToken)) -// } -// moveToMainActivity() -// } -// } catch (e: ApiException) { -// Log.e("LoginActivity", "Google sign-in failed: ${e.statusCode}") -// } -// } -// -// private fun moveToMainActivity() { -// val intent = Intent().setClassName(this, "com.stackknowledge.MainActivity") -// startActivity(intent) -// finish() -// } -} \ No newline at end of file From fe05c84191537936fd290d617405590e33af5e9e Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:47:30 +0900 Subject: [PATCH 50/91] =?UTF-8?q?=F0=9F=94=A5::=20=EA=B5=AC=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20MainActivity=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/remote/request/auth/LoginRequest.kt | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt diff --git a/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt b/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt deleted file mode 100644 index 4b393099..00000000 --- a/core/model/src/main/kotlin/remote/request/auth/LoginRequest.kt +++ /dev/null @@ -1,5 +0,0 @@ -package remote.request.auth - -data class LoginRequest( - val code: String -) \ No newline at end of file From 391d22c648acf17906f7aade5f9edd38c4e57dfb Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:47:33 +0900 Subject: [PATCH 51/91] =?UTF-8?q?=F0=9F=94=A5::=20=EA=B5=AC=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20MainActivity=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/stackknowledge/MainActivity.kt | 51 ------------------- 1 file changed, 51 deletions(-) delete mode 100644 app/src/main/java/com/stackknowledge/MainActivity.kt diff --git a/app/src/main/java/com/stackknowledge/MainActivity.kt b/app/src/main/java/com/stackknowledge/MainActivity.kt deleted file mode 100644 index 90b9aaf2..00000000 --- a/app/src/main/java/com/stackknowledge/MainActivity.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.stackknowledge - -import android.os.Bundle -import android.widget.Toast -import androidx.activity.ComponentActivity -import androidx.activity.OnBackPressedCallback -import androidx.activity.compose.setContent -import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi -import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass -import androidx.compose.runtime.CompositionLocalProvider -import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner -import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.ui.StackKnowledgeApp -import com.stackknowledge.user.R -import dagger.hilt.android.AndroidEntryPoint - -@AndroidEntryPoint -class MainActivity : ComponentActivity() { - private var doubleBackToExitPressedOnce = false - private var backPressedTimestamp = 0L - private val onBackPressedCallback = object : OnBackPressedCallback(true) { - override fun handleOnBackPressed() { - controlTheStackWhenBackPressed() - } - } - @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - this.onBackPressedDispatcher.addCallback(this, onBackPressedCallback) - setContent { - CompositionLocalProvider(LocalViewModelStoreOwner provides this) { - StackKnowledgeAndroidTheme { _, _ -> - StackKnowledgeApp( - windowSizeClass = calculateWindowSizeClass(this@MainActivity), - ) - } - } - } - } - - private fun controlTheStackWhenBackPressed() { - val currentTime = System.currentTimeMillis() - if (doubleBackToExitPressedOnce && currentTime - backPressedTimestamp <= 2000) { - finishAffinity() - } else { - doubleBackToExitPressedOnce = true - backPressedTimestamp = currentTime - Toast.makeText(this, getString(R.string.close_app),Toast.LENGTH_SHORT).show() - } - } -} From 6190facbe39da94ba0276577c084e1c2a6590e56 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:48:52 +0900 Subject: [PATCH 52/91] =?UTF-8?q?=F0=9F=94=A5::=20=EA=B5=AC=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20TopLevelDestination=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/navigation/TopLevelDestination.kt | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 app/src/main/java/com/stackknowledge/navigation/TopLevelDestination.kt diff --git a/app/src/main/java/com/stackknowledge/navigation/TopLevelDestination.kt b/app/src/main/java/com/stackknowledge/navigation/TopLevelDestination.kt deleted file mode 100644 index 174d6cae..00000000 --- a/app/src/main/java/com/stackknowledge/navigation/TopLevelDestination.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.stackknowledge.navigation - -enum class TopLevelDestination { - LOGIN, -} \ No newline at end of file From 64f4ae50f59c652925b3e24090dbf976eb5bf4a2 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:51:01 +0900 Subject: [PATCH 53/91] =?UTF-8?q?=F0=9F=90=9B::=20conflict=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/convention/AndroidFeatureConventionPlugin.kt | 4 ---- .../kotlin/com/stackknowledge/di/RepositoryModule.kt | 6 ------ .../component/button/StackKnowledgeButton.kt | 5 ----- .../remote/response/mission/MissionResponseModel.kt | 7 ------- .../kotlin/remote/response/mission/MissionsModel.kt | 6 ------ .../main/kotlin/com/stackknowledge/di/NetworkModule.kt | 10 ---------- .../com/stackknowledge/di/RemoteDataSourceModule.kt | 6 ------ .../kotlin/com/stackknowledge/util/AuthInterceptor.kt | 10 ---------- gradle/libs.versions.toml | 3 --- 9 files changed, 57 deletions(-) diff --git a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt index f1804402..8e37a4d3 100644 --- a/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/java/com/convention/AndroidFeatureConventionPlugin.kt @@ -20,10 +20,6 @@ class AndroidFeatureConventionPlugin : Plugin { add("implementation", project(":core:ui")) add("implementation", project(":core:design-system")) add("implementation", project(":core:domain")) -<<<<<<< HEAD - add("implementation", project(":core:common")) -======= ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b add("implementation", libs.findLibrary("coil.kt").get()) diff --git a/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt b/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt index 7d38f765..fcd84876 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/di/RepositoryModule.kt @@ -1,12 +1,9 @@ package com.stackknowledge.di -<<<<<<< HEAD import com.stackknowledge.repository.auth.AuthRepository import com.stackknowledge.repository.auth.AuthRepositoryImpl -======= import com.stackknowledge.repository.item.ItemRepository import com.stackknowledge.repository.item.ItemRepositoryImpl ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import com.stackknowledge.repository.mission.MissionRepository import com.stackknowledge.repository.mission.MissionRepositoryImpl import com.stackknowledge.repository.order.OrderRepository @@ -41,8 +38,6 @@ abstract class RepositoryModule { ): StudentRepository @Binds -<<<<<<< HEAD -======= abstract fun bindOrderRepository( orderRepositoryImpl: OrderRepositoryImpl ): OrderRepository @@ -58,7 +53,6 @@ abstract class RepositoryModule { ): SolveRepository @Binds ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b abstract fun bindUserRepository( userRepositoryImpl: UserRepositoryImpl ): UserRepository diff --git a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt index 5344aeeb..eb4f1472 100644 --- a/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt +++ b/core/design-system/src/main/java/com/stackknowledge/design_system/component/button/StackKnowledgeButton.kt @@ -18,15 +18,10 @@ fun StackKnowledgeButton( modifier: Modifier = Modifier, onClick: () -> Unit = {}, text: String, - onClick: () -> Unit, ) { StackKnowledgeAndroidTheme { colors, typography -> Button( -<<<<<<< HEAD - onClick = { onClick() }, -======= onClick = onClick, ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b modifier = modifier .fillMaxWidth() .clip(shape = RoundedCornerShape(10.dp)) diff --git a/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt b/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt index 9f806499..a5441003 100644 --- a/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt +++ b/core/model/src/main/kotlin/remote/response/mission/MissionResponseModel.kt @@ -1,13 +1,6 @@ package remote.response.mission -<<<<<<< HEAD -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -======= -import enumdatatype.MissionStatus import remote.user.UserModel -import java.util.UUID ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b data class MissionResponseModel( val id: String, diff --git a/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt b/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt index 42b5a576..9800d859 100644 --- a/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt +++ b/core/model/src/main/kotlin/remote/response/mission/MissionsModel.kt @@ -1,12 +1,6 @@ package remote.response.mission -<<<<<<< HEAD -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass import enumdata.MissionStatus -======= -import enumdatatype.MissionStatus ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import remote.user.UserModel import java.util.UUID diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt index b3cd22ba..4e53bf23 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt @@ -2,21 +2,15 @@ package com.stackknowledge.di import android.util.Log import com.squareup.moshi.Moshi -<<<<<<< HEAD import com.stackknowledge.api.AuthAPI -======= import com.stackknowledge.api.ItemAPI ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import com.stackknowledge.api.MissionAPI import com.stackknowledge.api.OrderAPI import com.stackknowledge.api.SolveAPI import com.stackknowledge.api.StudentAPI import com.stackknowledge.api.UserAPI -<<<<<<< HEAD import com.stackknowledge.network.BuildConfig import com.stackknowledge.util.AuthInterceptor -======= ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -93,9 +87,6 @@ object NetworkModule { @Provides @Singleton -<<<<<<< HEAD - fun provideUserAPI(retrofit: Retrofit): UserAPI = -======= fun providesOrderAPI(retrofit: Retrofit): OrderAPI = retrofit.create(OrderAPI::class.java) @@ -112,6 +103,5 @@ object NetworkModule { @Provides @Singleton fun providesUserAPI(retrofit: Retrofit): UserAPI = ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b retrofit.create(UserAPI::class.java) } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt index db9643d7..7b553e36 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/di/RemoteDataSourceModule.kt @@ -1,12 +1,9 @@ package com.stackknowledge.di -<<<<<<< HEAD import com.stackknowledge.datasource.auth.AuthDataSource import com.stackknowledge.datasource.auth.AuthDataSourceImpl -======= import com.stackknowledge.datasource.item.ItemDataSource import com.stackknowledge.datasource.item.ItemDataSourceImpl ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import com.stackknowledge.datasource.mission.MissionDataSource import com.stackknowledge.datasource.mission.MissionDataSourceImpl import com.stackknowledge.datasource.order.OrderDataSource @@ -46,8 +43,6 @@ abstract class RemoteDataSourceModule { @Binds @Singleton -<<<<<<< HEAD -======= abstract fun bindOrderDataSource( orderDataSourceImpl: OrderDataSourceImpl ): OrderDataSource @@ -66,7 +61,6 @@ abstract class RemoteDataSourceModule { @Binds @Singleton ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b abstract fun bindUserDataSource( userDataSourceImpl: UserDataSourceImpl ): UserDataSource diff --git a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt index 80103f7f..0911f817 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt @@ -1,21 +1,17 @@ package com.stackknowledge.util -<<<<<<< HEAD import com.example.common.exception.NeedLoginException import com.squareup.moshi.Moshi import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.stackknowledge.network.BuildConfig import com.stackknowledge.datastore.LocalAuthDataSource import kotlinx.coroutines.flow.first -======= ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response -import util.ResourceKeys import javax.inject.Inject class AuthInterceptor @Inject constructor( @@ -35,7 +31,6 @@ class AuthInterceptor @Inject constructor( override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request() val builder = request.newBuilder() -<<<<<<< HEAD val currentTime = System.currentTimeMillis().toLocalDateTime() val ignorePath = listOf("/auth") val ignoreMethod = listOf("POST") @@ -89,11 +84,6 @@ class AuthInterceptor @Inject constructor( } val accessToken = dataSource.getAccessToken().first().replace("\"", "") builder.addHeader("Authorization", "Bearer $accessToken") -======= - - runBlocking { - builder.addHeader("Authorization", "${ResourceKeys.BEARER} ") ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b } return chain.proceed(builder.build()) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 93430ebb..f3d17efc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -100,11 +100,8 @@ kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "lint" } moshi = { group = "com.squareup.moshi", name = "moshi", version.ref = "moshi" } -<<<<<<< HEAD moshi-kotlin = { group = "com.squareup.moshi", name = "moshi-kotlin", version.ref = "moshi" } -======= okhttp3 = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp"} ->>>>>>> 7968c9bc41ecc66967c282ccfb3222e458eb598b okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } From f04ddc32ebbe88af4436437ed1fd3b048873e64b Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:54:11 +0900 Subject: [PATCH 54/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=20Authority=20=EC=82=AD=EC=A0=9C=EC=97=90=20=EB=94=B0=EB=A5=B8?= =?UTF-8?q?=20import=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/repository/auth/AuthRepository.kt | 4 ++-- .../stackknowledge/repository/auth/AuthRepositoryImpl.kt | 8 +++++--- .../stackknowledge/usecase/auth/LoginStudentUseCase.kt | 5 +++-- .../stackknowledge/usecase/auth/LoginTeacherUseCase.kt | 4 +++- .../com/stackknowledge/usecase/auth/SaveTokenUseCase.kt | 2 +- .../src/main/kotlin/com/stackknowledge/api/AuthAPI.kt | 6 +++--- .../com/stackknowledge/datasource/auth/AuthDataSource.kt | 6 +++--- .../stackknowledge/datasource/auth/AuthDataSourceImpl.kt | 4 ++-- .../ui/navigation/StackKnowledgeBottomNavigation.kt | 4 +--- .../com/stackknowledge/login/viewmodel/AuthViewModel.kt | 6 ++---- .../main/java/com/stackknowledge/main/MainPageScreen.kt | 2 +- .../java/com/stackknowledge/main/component/RankingList.kt | 3 --- .../com/stackknowledge/main/navigation/MainNavigation.kt | 2 +- .../java/com/stackkowledge/mission/CreateMissionScreen.kt | 3 +-- .../java/com/stackkowledge/mission/EntireMissionScreen.kt | 3 +-- .../com/stackkowledge/mission/ResolveMissionScreen.kt | 4 +--- .../stackkowledge/mission/navigation/MissionNavigation.kt | 2 +- .../main/java/com/stackknowledge/ranking/RankingScreen.kt | 6 +----- .../com/stackknowledge/ranking/TeacherRankingScreen.kt | 4 +--- .../ranking/navigation/RankingNavigation.kt | 2 +- .../stackknowledge/score_mission/GradingAnswerScreen.kt | 5 +---- .../stackknowledge/score_mission/SolvedMissionScreen.kt | 2 -- .../score_mission/navigation/ScoreMissionNavigation.kt | 2 +- .../src/main/java/com/stackknowledge/shop/ShopScreen.kt | 7 +------ .../java/com/stackknowledge/shop/TeacherShopScreen.kt | 7 +------ .../com/stackknowledge/shop/navigation/ShopNavigation.kt | 2 +- 26 files changed, 39 insertions(+), 66 deletions(-) diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt index 9c4c7c51..c991d688 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt @@ -1,8 +1,8 @@ package com.stackknowledge.repository.auth import kotlinx.coroutines.flow.Flow -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse +import remote.request.auth.LoginRequestModel +import remote.response.auth.LoginResponseModel interface AuthRepository { fun loginStudent( diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt index 61faeb47..a9dea9a0 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -1,11 +1,13 @@ package com.stackknowledge.repository.auth -import android.util.Log import com.stackknowledge.datasource.auth.AuthDataSource import com.stackknowledge.datastore.LocalAuthDataSource +import com.stackknowledge.mapper.request.auth.toDto +import com.stackknowledge.mapper.response.auth.toModel import kotlinx.coroutines.flow.Flow -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse +import kotlinx.coroutines.flow.map +import remote.request.auth.LoginRequestModel +import remote.response.auth.LoginResponseModel import javax.inject.Inject class AuthRepositoryImpl @Inject constructor( diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt index 5fd54a21..c3012ab7 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt @@ -1,8 +1,9 @@ package com.stackknowledge.usecase.auth -import android.util.Log import com.stackknowledge.repository.auth.AuthRepository -import remote.request.auth.LoginRequest +import kotlinx.coroutines.flow.Flow +import remote.request.auth.LoginRequestModel +import remote.response.auth.LoginResponseModel import javax.inject.Inject class LoginStudentUseCase @Inject constructor( diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt index 17df1e0e..9089c5e7 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt @@ -1,7 +1,9 @@ package com.stackknowledge.usecase.auth import com.stackknowledge.repository.auth.AuthRepository -import remote.request.auth.LoginRequest +import kotlinx.coroutines.flow.Flow +import remote.request.auth.LoginRequestModel +import remote.response.auth.LoginResponseModel import javax.inject.Inject class LoginTeacherUseCase @Inject constructor( diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt index 425f400f..cc80794a 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt @@ -1,7 +1,7 @@ package com.stackknowledge.usecase.auth import com.stackknowledge.repository.auth.AuthRepository -import remote.response.auth.LoginResponse +import remote.response.auth.LoginResponseModel import javax.inject.Inject class SaveTokenUseCase @Inject constructor( diff --git a/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt b/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt index c26b03d3..9e6b3179 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/api/AuthAPI.kt @@ -1,7 +1,7 @@ package com.stackknowledge.api -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse +import com.stackknowledge.dto.request.auth.LoginRequest +import com.stackknowledge.dto.response.auth.LoginResponse import retrofit2.http.Body import retrofit2.http.DELETE import retrofit2.http.POST @@ -19,4 +19,4 @@ interface AuthAPI { @DELETE("/auth") suspend fun logout() -} +} \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt index b06a5320..efb39c65 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSource.kt @@ -1,11 +1,11 @@ package com.stackknowledge.datasource.auth +import com.stackknowledge.dto.request.auth.LoginRequest +import com.stackknowledge.dto.response.auth.LoginResponse import kotlinx.coroutines.flow.Flow -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse interface AuthDataSource { fun loginStudent(body: LoginRequest): Flow - fun loginTeacher(body: LoginRequest, ): Flow + fun loginTeacher(body: LoginRequest): Flow fun logout(): Flow } \ No newline at end of file diff --git a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt index a98e80b9..38b27f05 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt @@ -2,13 +2,13 @@ package com.stackknowledge.datasource.auth import android.util.Log import com.stackknowledge.api.AuthAPI +import com.stackknowledge.dto.request.auth.LoginRequest +import com.stackknowledge.dto.response.auth.LoginResponse import com.stackknowledge.util.StackKnowledgeApiHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse import javax.inject.Inject class AuthDataSourceImpl @Inject constructor( diff --git a/core/ui/src/main/java/com/minstone/ui/navigation/StackKnowledgeBottomNavigation.kt b/core/ui/src/main/java/com/minstone/ui/navigation/StackKnowledgeBottomNavigation.kt index 37db4f80..79dfb6cd 100644 --- a/core/ui/src/main/java/com/minstone/ui/navigation/StackKnowledgeBottomNavigation.kt +++ b/core/ui/src/main/java/com/minstone/ui/navigation/StackKnowledgeBottomNavigation.kt @@ -1,7 +1,5 @@ package com.minstone.ui.navigation -import android.icu.text.TimeZoneNames.NameType -import androidx.annotation.StringRes import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -20,7 +18,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.stackknowledge.design_system.R import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import enumdatatype.Authority +import enumdata.Authority enum class NavigateType(val value: String) { HOME("home"), diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index f4aff683..85ef3c8e 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -1,9 +1,7 @@ package com.stackknowledge.login.viewmodel import android.util.Log -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.stackknowledge.usecase.auth.SaveTokenUseCase @@ -11,13 +9,13 @@ import com.stackknowledge.usecase.auth.LoginStudentUseCase import com.stackknowledge.usecase.auth.LoginTeacherUseCase import com.stackknowledge.login.viewmodel.util.Event import com.stackknowledge.login.viewmodel.util.errorHandling -import remote.request.auth.LoginRequest -import remote.response.auth.LoginResponse import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch +import remote.request.auth.LoginRequestModel +import remote.response.auth.LoginResponseModel import javax.inject.Inject @HiltViewModel diff --git a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt index 647091a4..d4f03727 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt @@ -33,7 +33,7 @@ import com.stackknowledge.main.component.StackKnowledgePager import com.stackknowledge.main.viewModel.MainViewModel import com.stackknowledge.main.viewModel.uistate.GetMissionUiState import com.stackknowledge.main.viewModel.uistate.GetRankingUiState -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun MainPageRoute( diff --git a/feature/main/src/main/java/com/stackknowledge/main/component/RankingList.kt b/feature/main/src/main/java/com/stackknowledge/main/component/RankingList.kt index 521d9e6c..ee85d867 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/component/RankingList.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/component/RankingList.kt @@ -15,12 +15,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import com.stackknowledge.main.viewModel.uistate.GetMissionUiState import com.stackknowledge.main.viewModel.uistate.GetRankingUiState -import enumdatatype.Authority @Composable fun RankingList( diff --git a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt index 4d48a9f8..899710d9 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt @@ -5,7 +5,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.main.MainPageRoute -import enumdatatype.Authority +import enumdata.Authority const val mainPageRoute = "main_page_route" diff --git a/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt b/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt index 7d100c54..5ca8806e 100644 --- a/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt +++ b/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt @@ -32,10 +32,9 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackkowledge.mission.component.CreateMissionTimer import com.stackkowledge.mission.component.InputMission import com.stackkowledge.mission.component.InputTitle -import com.stackkowledge.mission.viewmodel.uistate.CreateMissionUiState import com.stackkowledge.mission.util.isValidNumber import com.stackkowledge.mission.viewmodel.MissionViewModel -import enumdatatype.Authority +import enumdata.Authority import remote.request.mission.CreateMissionRequestModel @Composable diff --git a/feature/mission/src/main/java/com/stackkowledge/mission/EntireMissionScreen.kt b/feature/mission/src/main/java/com/stackkowledge/mission/EntireMissionScreen.kt index 0e95c310..eb44e757 100644 --- a/feature/mission/src/main/java/com/stackkowledge/mission/EntireMissionScreen.kt +++ b/feature/mission/src/main/java/com/stackkowledge/mission/EntireMissionScreen.kt @@ -23,8 +23,7 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackkowledge.mission.component.EntireMissionList import com.stackkowledge.mission.viewmodel.uistate.GetMissionUiState import com.stackkowledge.mission.viewmodel.MissionViewModel -import enumdatatype.Authority -import java.util.UUID +import enumdata.Authority @Composable internal fun EntireMissionRoute( diff --git a/feature/mission/src/main/java/com/stackkowledge/mission/ResolveMissionScreen.kt b/feature/mission/src/main/java/com/stackkowledge/mission/ResolveMissionScreen.kt index a4b50da5..18e64128 100644 --- a/feature/mission/src/main/java/com/stackkowledge/mission/ResolveMissionScreen.kt +++ b/feature/mission/src/main/java/com/stackkowledge/mission/ResolveMissionScreen.kt @@ -30,7 +30,6 @@ import com.minstone.ui.navigation.StackKnowledgeBottomNavigation import com.stackknowledge.design_system.component.dialog.StackKnowledgeDialog import com.stackknowledge.design_system.component.topbar.StackKnowledgeTopBar import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme -import enumdatatype.Authority import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.dialog.EmptyButtonDialog import com.stackknowledge.design_system.component.toast.SuccessToastMessage @@ -40,9 +39,8 @@ import com.stackkowledge.mission.component.MissionTimer import com.stackkowledge.mission.viewmodel.MissionViewModel import com.stackkowledge.mission.viewmodel.SolveMissionViewModel import com.stackkowledge.mission.viewmodel.uistate.DetailMissionUiState -import com.stackkowledge.mission.viewmodel.uistate.SolveMissionUiState +import enumdata.Authority import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking import remote.request.solve.SolveRequestModel @Composable diff --git a/feature/mission/src/main/java/com/stackkowledge/mission/navigation/MissionNavigation.kt b/feature/mission/src/main/java/com/stackkowledge/mission/navigation/MissionNavigation.kt index 7ed7681f..39bcd841 100644 --- a/feature/mission/src/main/java/com/stackkowledge/mission/navigation/MissionNavigation.kt +++ b/feature/mission/src/main/java/com/stackkowledge/mission/navigation/MissionNavigation.kt @@ -7,7 +7,7 @@ import androidx.navigation.compose.composable import com.stackkowledge.mission.ResolveMissionRoute import com.stackkowledge.mission.CreateMissionRoute import com.stackkowledge.mission.EntireMissionRoute -import enumdatatype.Authority +import enumdata.Authority const val createMissionRoute = "create_mission_route" const val entireMissionRoute = "entire_mission_route" diff --git a/feature/ranking/src/main/java/com/stackknowledge/ranking/RankingScreen.kt b/feature/ranking/src/main/java/com/stackknowledge/ranking/RankingScreen.kt index 80d9716b..7be77f39 100644 --- a/feature/ranking/src/main/java/com/stackknowledge/ranking/RankingScreen.kt +++ b/feature/ranking/src/main/java/com/stackknowledge/ranking/RankingScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -15,10 +14,8 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.ViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.minstone.ui.navigation.StackKnowledgeBottomNavigation import com.stackknowledge.design_system.component.topbar.StackKnowledgeTopBar @@ -28,8 +25,7 @@ import com.stackknowledge.ranking.component.RankingProfile import com.stackknowledge.ranking.viewModel.RankingViewModel import com.stackknowledge.ranking.viewModel.uistate.GetMyInformationUiState import com.stackknowledge.ranking.viewModel.uistate.GetRankingUiState -import dagger.hilt.android.lifecycle.HiltViewModel -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun RankingRoute( diff --git a/feature/ranking/src/main/java/com/stackknowledge/ranking/TeacherRankingScreen.kt b/feature/ranking/src/main/java/com/stackknowledge/ranking/TeacherRankingScreen.kt index bdedb6ff..8703e235 100644 --- a/feature/ranking/src/main/java/com/stackknowledge/ranking/TeacherRankingScreen.kt +++ b/feature/ranking/src/main/java/com/stackknowledge/ranking/TeacherRankingScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -15,7 +14,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -25,7 +23,7 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.ranking.component.RankingList import com.stackknowledge.ranking.viewModel.RankingViewModel import com.stackknowledge.ranking.viewModel.uistate.GetRankingUiState -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun TeacherRankingRoute( diff --git a/feature/ranking/src/main/java/com/stackknowledge/ranking/navigation/RankingNavigation.kt b/feature/ranking/src/main/java/com/stackknowledge/ranking/navigation/RankingNavigation.kt index bd91d7c0..b1e662cb 100644 --- a/feature/ranking/src/main/java/com/stackknowledge/ranking/navigation/RankingNavigation.kt +++ b/feature/ranking/src/main/java/com/stackknowledge/ranking/navigation/RankingNavigation.kt @@ -6,7 +6,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.ranking.RankingRoute import com.stackknowledge.ranking.TeacherRankingRoute -import enumdatatype.Authority +import enumdata.Authority const val rankingRoute = "ranking_route" const val teacherRankingRoute = "teacher_ranking_route" diff --git a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/GradingAnswerScreen.kt b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/GradingAnswerScreen.kt index 5fbab0c7..65d9d6ac 100644 --- a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/GradingAnswerScreen.kt +++ b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/GradingAnswerScreen.kt @@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -19,7 +18,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -35,8 +33,7 @@ import com.stackknowledge.score_mission.component.SolvedMissionAnswer import com.stackknowledge.score_mission.component.SolvedMissionTitle import com.stackknowledge.score_mission.viewmodel.ScoreMissionViewModel import com.stackknowledge.score_mission.viewmodel.uistate.DetailScoreMissionUiState -import com.stackknowledge.score_mission.viewmodel.uistate.ScoreMissionUiState -import enumdatatype.Authority +import enumdata.Authority import remote.request.user.ScoreRequestModel @Composable diff --git a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt index bc14b968..ed108282 100644 --- a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt +++ b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -16,7 +15,6 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.minstone.ui.navigation.StackKnowledgeBottomNavigation diff --git a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/navigation/ScoreMissionNavigation.kt b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/navigation/ScoreMissionNavigation.kt index c77dfb66..7da44b41 100644 --- a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/navigation/ScoreMissionNavigation.kt +++ b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/navigation/ScoreMissionNavigation.kt @@ -6,7 +6,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.score_mission.GradingAnswerRoute import com.stackknowledge.score_mission.SolvedMissionRoute -import enumdatatype.Authority +import enumdata.Authority const val gradingAnswerRoute = "grading_answer_route" const val solvedMissionRoute = "solved_mission_route" diff --git a/feature/shop/src/main/java/com/stackknowledge/shop/ShopScreen.kt b/feature/shop/src/main/java/com/stackknowledge/shop/ShopScreen.kt index da54fcf5..5cc60a15 100644 --- a/feature/shop/src/main/java/com/stackknowledge/shop/ShopScreen.kt +++ b/feature/shop/src/main/java/com/stackknowledge/shop/ShopScreen.kt @@ -6,25 +6,20 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.minstone.ui.navigation.StackKnowledgeBottomNavigation import com.stackknowledge.design_system.component.topbar.StackKnowledgeTopBar import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.shop.component.CurrentMileage import com.stackknowledge.shop.component.GoodsList -import com.stackknowledge.shop.viewmodel.ItemViewModel -import com.stackknowledge.shop.viewmodel.OrderViewModel -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun ShopRoute( diff --git a/feature/shop/src/main/java/com/stackknowledge/shop/TeacherShopScreen.kt b/feature/shop/src/main/java/com/stackknowledge/shop/TeacherShopScreen.kt index d5c306ab..010fe3d3 100644 --- a/feature/shop/src/main/java/com/stackknowledge/shop/TeacherShopScreen.kt +++ b/feature/shop/src/main/java/com/stackknowledge/shop/TeacherShopScreen.kt @@ -3,10 +3,7 @@ package com.stackknowledge.shop import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height -import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -14,13 +11,11 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp import com.minstone.ui.navigation.StackKnowledgeBottomNavigation import com.stackknowledge.design_system.component.topbar.StackKnowledgeTopBar import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.shop.component.OrderedGoodsList -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun TeacherShopRoute( diff --git a/feature/shop/src/main/java/com/stackknowledge/shop/navigation/ShopNavigation.kt b/feature/shop/src/main/java/com/stackknowledge/shop/navigation/ShopNavigation.kt index 49b811d8..158a12db 100644 --- a/feature/shop/src/main/java/com/stackknowledge/shop/navigation/ShopNavigation.kt +++ b/feature/shop/src/main/java/com/stackknowledge/shop/navigation/ShopNavigation.kt @@ -6,7 +6,7 @@ import androidx.navigation.NavOptions import androidx.navigation.compose.composable import com.stackknowledge.shop.ShopRoute import com.stackknowledge.shop.TeacherShopRoute -import enumdatatype.Authority +import enumdata.Authority const val shopRoute = "shop_route" const val teacherShopRoute = "teacher_shop_route" From f176c2c7aded8c7d9b258061e876ab87d4269560 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:54:18 +0900 Subject: [PATCH 55/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=20Authority=20=EC=82=AD=EC=A0=9C=EC=97=90=20=EB=94=B0=EB=A5=B8?= =?UTF-8?q?=20import=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/score_mission/SolvedMissionScreen.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt index ed108282..122f465b 100644 --- a/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt +++ b/feature/score-mission/src/main/java/com/stackknowledge/score_mission/SolvedMissionScreen.kt @@ -23,7 +23,7 @@ import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.score_mission.component.SolvedMissionList import com.stackknowledge.score_mission.viewmodel.ScoreMissionViewModel import com.stackknowledge.score_mission.viewmodel.uistate.GetScoreMissionListUiState -import enumdatatype.Authority +import enumdata.Authority @Composable internal fun SolvedMissionRoute( From b4ca57390192c95c3a1d94256f1dc857d78848fc Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:54:43 +0900 Subject: [PATCH 56/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20SaveTokenUseCase?= =?UTF-8?q?=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20LoginResponseModel?= =?UTF-8?q?=EB=A1=9C=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt index cc80794a..592ec690 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt @@ -7,7 +7,7 @@ import javax.inject.Inject class SaveTokenUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke(token: LoginResponse) = runCatching { + suspend operator fun invoke(token: LoginResponseModel) = runCatching { authRepository.saveToken(token = token) } } \ No newline at end of file From 8e750213cfcdd4abf08bc59b46e6a935b5c35176 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:55:10 +0900 Subject: [PATCH 57/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginTeacherUseCas?= =?UTF-8?q?e=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0,=20=EB=A6=AC=ED=84=B4?= =?UTF-8?q?=20Model=EB=A1=9C=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackknowledge/usecase/auth/LoginTeacherUseCase.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt index 9089c5e7..fabdf4f4 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginTeacherUseCase.kt @@ -9,11 +9,7 @@ import javax.inject.Inject class LoginTeacherUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke( - body: LoginRequest, - ) = runCatching { - authRepository.loginTeacher( - body = body, - ) - } + operator fun invoke(body: LoginRequestModel): Flow = + authRepository.loginTeacher(body = body) + } \ No newline at end of file From 7bfe154389a52e843644a0fbee8f080a44b2a0e3 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:55:22 +0900 Subject: [PATCH 58/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginStudentUseCas?= =?UTF-8?q?e=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0,=20=EB=A6=AC=ED=84=B4?= =?UTF-8?q?=20Model=EB=A1=9C=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackknowledge/usecase/auth/LoginStudentUseCase.kt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt index c3012ab7..cf896537 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LoginStudentUseCase.kt @@ -9,12 +9,6 @@ import javax.inject.Inject class LoginStudentUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke( - body: LoginRequest, - ) = runCatching { - Log.e("useCase loginStudent", "loginStudent") - authRepository.loginStudent( - body = body, - ) - } + operator fun invoke(body: LoginRequestModel): Flow = + authRepository.loginStudent(body = body) } \ No newline at end of file From 25d52a46845945db98d93e29245e33b4bf0602b0 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:55:47 +0900 Subject: [PATCH 59/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginNavigation=20?= =?UTF-8?q?=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B0=8F=20=EB=84=A4=EB=B9=84?= =?UTF-8?q?=EA=B2=8C=EC=9D=B4=EC=85=98=20=EB=8F=99=EC=9E=91=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/navigation/LoginNavigation.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index 644dd925..6e1ece0c 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -14,9 +14,15 @@ fun NavController.navigateToLogin(navOptions: NavOptions? = null) { this.navigate(loginRoute, navOptions) } -fun NavGraphBuilder.loginScreen() { +fun NavGraphBuilder.loginScreen( + onSuccess: () -> Unit = {}, + onLoginButtonClick: () -> Unit = {}, +) { composable(route = loginRoute) { - LoginRoute() + LoginRoute( + onSuccess = onSuccess, + onGoogleLoginButtonClicked = onLoginButtonClick + ) } } @@ -25,10 +31,11 @@ fun NavController.navigateToRoleCheck(navOptions: NavOptions? = null) { } fun NavGraphBuilder.roleCheckScreen( + onRoleButtonClick: () -> Unit, ) { composable(route = roleCheckRoute) { RoleCheckRoute( - + onRoleButtonClick = onRoleButtonClick ) } } \ No newline at end of file From f6f244b841c63b7873748c5fd7c3e048616a2c1c Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:56:17 +0900 Subject: [PATCH 60/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20AuthRepository=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0,=20=EB=A6=AC=ED=84=B4=20dt?= =?UTF-8?q?o=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackknowledge/repository/auth/AuthRepository.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt index c991d688..16cbf5fc 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt @@ -5,15 +5,11 @@ import remote.request.auth.LoginRequestModel import remote.response.auth.LoginResponseModel interface AuthRepository { - fun loginStudent( - body: LoginRequest, - ): Flow + fun loginStudent(body: LoginRequestModel): Flow - fun loginTeacher( - body: LoginRequest, - ): Flow + fun loginTeacher(body: LoginRequestModel): Flow - suspend fun saveToken(token: LoginResponse) + suspend fun saveToken(token: LoginResponseModel) fun logout(): Flow } \ No newline at end of file From cada931f6c19279956e0c3ae2b25bc5ac6462d3b Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:56:19 +0900 Subject: [PATCH 61/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20AuthRepository=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0,=20=EB=A6=AC=ED=84=B4=20dt?= =?UTF-8?q?o=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/auth/AuthRepositoryImpl.kt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt index a9dea9a0..f599741e 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -14,20 +14,15 @@ class AuthRepositoryImpl @Inject constructor( private val authDataSource: AuthDataSource, private val localDataSource: LocalAuthDataSource ): AuthRepository { - override fun loginStudent(body: LoginRequest): Flow { - Log.e("repository loginStudent", "loginStudent") - return authDataSource.loginStudent( - body = body, - ) + override fun loginStudent(body: LoginRequestModel): Flow { + return authDataSource.loginStudent(body = body.toDto()).map { it.toModel() } } - override fun loginTeacher(body: LoginRequest): Flow { - return authDataSource.loginTeacher( - body = body, - ) + override fun loginTeacher(body: LoginRequestModel): Flow { + return authDataSource.loginTeacher(body = body.toDto()).map { it.toModel() } } - override suspend fun saveToken(token: LoginResponse) { + override suspend fun saveToken(token: LoginResponseModel) { token.let { localDataSource.setAccessToken(it.accessToken) localDataSource.setAccessTime(it.expiredAt) From 303323072ae2630bba0d0eb5e7f492a7d0a4d5c4 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:57:11 +0900 Subject: [PATCH 62/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20ViewModel=20Login?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=ED=95=A8=EC=88=98=20app=EB=AA=A8?= =?UTF-8?q?=EB=93=88=20=EB=8B=A8=20=EC=A0=91=EA=B7=BC=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EC=A0=91=EA=B7=BC=EC=A0=9C=EC=96=B4=20=ED=95=B4?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20UiState=20=EC=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/viewmodel/AuthViewModel.kt | 55 +++++++------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index 85ef3c8e..51ee872c 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -36,46 +36,33 @@ class AuthViewModel @Inject constructor( var isStudent = mutableStateOf(false) private set - var showLoginRoute = mutableStateOf(false) - private set - - - internal fun loginStudent( - body: LoginRequest, - ) = viewModelScope.launch { - loginStudentUseCase( - body = body, - ).onSuccess { - Log.e("viewModel loginStudent", "loginStudent") - it.catch { remoteError -> - _loginResponse.value = remoteError.errorHandling() - }.collect { response -> - _loginResponse.value = Event.Success(data = response) + fun loginStudent(body: LoginRequestModel) = viewModelScope.launch { + Log.e("viewModel serverAuthCode", body.code) + loginStudentUseCase(body = body) + .asResult() + .collectLatest { result -> + when (result) { + is Result.Loading -> _loginUiState.value = LoginUiState.Loading + is Result.Success -> _loginUiState.value = LoginUiState.Success(result.data) + is Result.Error -> _loginUiState.value = LoginUiState.Error(result.exception) + } } - }.onFailure { - _loginResponse.value = it.errorHandling() - } } - internal fun loginTeacher( - body: LoginRequest, - ) = viewModelScope.launch { - loginTeacherUseCase( - body = body, - ).onSuccess { - it.catch { remoteError -> - _loginResponse.value = remoteError.errorHandling() - }.collect { response -> - _loginResponse.value = Event.Success(data = response) + fun loginTeacher(body: LoginRequestModel) = viewModelScope.launch { + loginTeacherUseCase(body = body) + .asResult() + .collectLatest { result -> + when (result) { + is Result.Loading -> _loginUiState.value = LoginUiState.Loading + is Result.Success -> _loginUiState.value = LoginUiState.Success(result.data) + is Result.Error -> _loginUiState.value = LoginUiState.Error(result.exception) + } + } - }.onFailure { - _loginResponse.value = it.errorHandling() - } } - internal fun saveToken( - token: LoginResponse, - ) = viewModelScope.launch { + internal fun saveToken(token: LoginResponseModel) = viewModelScope.launch { saveTokenUseCase( token = token ).onSuccess { From 94ec5ef4e557732f1ca8df9c15369e1ef2d2e385 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:57:43 +0900 Subject: [PATCH 63/91] =?UTF-8?q?=F0=9F=94=A5::=20MissionResponse=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/dto/response/mission/MissionResponse.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/MissionResponse.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/MissionResponse.kt index dbdacef4..623ecbb4 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/MissionResponse.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/response/mission/MissionResponse.kt @@ -3,9 +3,6 @@ package com.stackknowledge.dto.response.mission import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import com.stackknowledge.dto.user.User -import enumdatatype.MissionStatus -import remote.user.UserModel -import java.util.UUID @JsonClass(generateAdapter = true) data class MissionResponse( From 65329ef6c934372b76cc4e974b5a35da8aa7b8ac Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:57:54 +0900 Subject: [PATCH 64/91] =?UTF-8?q?=F0=9F=94=A5::=20CreateMissionScreen=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/stackkowledge/mission/CreateMissionScreen.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt b/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt index 5ca8806e..f19c5e5b 100644 --- a/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt +++ b/feature/mission/src/main/java/com/stackkowledge/mission/CreateMissionScreen.kt @@ -1,7 +1,5 @@ package com.stackkowledge.mission -import android.util.Log -import android.widget.Toast import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column From 2365323451eb36283cd95c9961c69bb9dddec90e Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:58:21 +0900 Subject: [PATCH 65/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20ViewModel=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=A0=91=EA=B7=BC=EC=A0=9C=EC=96=B4=20?= =?UTF-8?q?=EB=B0=8F=20UiState=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/login/viewmodel/AuthViewModel.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index 51ee872c..3f3e426b 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -25,10 +25,10 @@ class AuthViewModel @Inject constructor( private val saveTokenUseCase: SaveTokenUseCase, ) : ViewModel() { private val _saveTokenRequest = MutableStateFlow>(Event.Loading) - val saveTokenRequest = _saveTokenRequest.asStateFlow() + internal val saveTokenRequest = _saveTokenRequest.asStateFlow() - private val _loginResponse = MutableStateFlow>(Event.Loading) - val loginResponse = _loginResponse.asStateFlow() + private val _loginUiState = MutableStateFlow(LoginUiState.Loading) + internal val loginUiState = _loginUiState.asStateFlow() var isTeacher = mutableStateOf(false) private set From c7c847d3554a9d1ed6f7f2ff1571e56633957b71 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:58:28 +0900 Subject: [PATCH 66/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20AndroidManifest=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20Google=20API=20Console=EA=B3=BC=EC=9D=98?= =?UTF-8?q?=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4=EB=A6=84=20=EB=8F=99?= =?UTF-8?q?=EA=B8=B0=ED=99=94=20=EB=B0=8F=20LoginActivity=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=ED=95=B4=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 17 +++-------------- .../login/viewmodel/AuthViewModel.kt | 5 ++++- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6edb3e2e..6ce0fe51 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ - - - - - - - - > @@ -41,6 +29,7 @@ + diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index 3f3e426b..fb0aeb1a 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -4,6 +4,9 @@ import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.example.common.result.Result +import com.example.common.result.asResult +import com.stackknowledge.login.viewmodel.uistate.LoginUiState import com.stackknowledge.usecase.auth.SaveTokenUseCase import com.stackknowledge.usecase.auth.LoginStudentUseCase import com.stackknowledge.usecase.auth.LoginTeacherUseCase @@ -12,7 +15,7 @@ import com.stackknowledge.login.viewmodel.util.errorHandling import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import remote.request.auth.LoginRequestModel import remote.response.auth.LoginResponseModel From ae095d52d747638fdbb5980bd77b19d9e199b2b1 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 13:59:49 +0900 Subject: [PATCH 67/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20AndroidApplication?= =?UTF-8?q?ConventionPlugin=20=ED=8C=8C=EC=9D=BC=20Google=20API=20Console?= =?UTF-8?q?=EA=B3=BC=EC=9D=98=20=ED=8C=A8=ED=82=A4=EC=A7=80=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=8F=99=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/convention/AndroidApplicationConventionPlugin.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build-logic/convention/src/main/java/com/convention/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/java/com/convention/AndroidApplicationConventionPlugin.kt index 93e799d1..ae4e535b 100644 --- a/build-logic/convention/src/main/java/com/convention/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/java/com/convention/AndroidApplicationConventionPlugin.kt @@ -8,7 +8,6 @@ import org.gradle.api.Project import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.dependencies - class AndroidApplicationConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { @@ -20,7 +19,7 @@ class AndroidApplicationConventionPlugin : Plugin { extensions.configure { configureKotlinAndroid(this) defaultConfig { - applicationId = "com.stackknowledge_android" + applicationId = "com.kdn.stack_knowledge" minSdk = 26 targetSdk = 34 versionCode = 1 @@ -48,8 +47,6 @@ class AndroidApplicationConventionPlugin : Plugin { add("implementation", libs.findBundle("compose").get()) } } - } - } } \ No newline at end of file From 590b25912422236ce2c433898629f1d9bd1f4d9b Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 14:39:16 +0900 Subject: [PATCH 68/91] =?UTF-8?q?=F0=9F=94=A5::=20build.gradles.kts=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import=EB=AC=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feature/login/build.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/feature/login/build.gradle.kts b/feature/login/build.gradle.kts index 4ecd3bc6..537d78c1 100644 --- a/feature/login/build.gradle.kts +++ b/feature/login/build.gradle.kts @@ -1,6 +1,3 @@ -import java.io.FileInputStream -import java.util.Properties - @Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed plugins { id("stackknowledge.android.feature") From 5f914ee76269f3838c44cf88a5c71572170d6afb Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:15:35 +0900 Subject: [PATCH 69/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20google=20service?= =?UTF-8?q?=20version=20=EC=97=85=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f3d17efc..55ebeea2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -48,7 +48,7 @@ retrofitKotlinxSerializableJson = "1.0.0" room = "2.6.1" org-jetbrains-kotlin-android = "1.8.10" lifecycle-runtime-ktx = "2.6.2" -google-services = "4.4.0" +google-services = "4.4.2" play-services-auth = "20.7.0" moshi = "1.15.0" From 6ed20518d8696a948860ca5acb38615749f9cdbc Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:15:58 +0900 Subject: [PATCH 70/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20=EC=A7=81=EB=A0=AC?= =?UTF-8?q?=ED=99=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=B4=20KotlinJsonAdapterFactory=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/kotlin/com/stackknowledge/di/NetworkModule.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt index 4e53bf23..1ca37f29 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/di/NetworkModule.kt @@ -2,6 +2,7 @@ package com.stackknowledge.di import android.util.Log import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import com.stackknowledge.api.AuthAPI import com.stackknowledge.api.ItemAPI import com.stackknowledge.api.MissionAPI @@ -34,7 +35,7 @@ object NetworkModule { @Singleton fun provideOkhttpClient( httpLoggingInterceptor: HttpLoggingInterceptor, - authInterceptor: AuthInterceptor + authInterceptor: AuthInterceptor, ): OkHttpClient { return OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) @@ -48,7 +49,9 @@ object NetworkModule { @Provides @Singleton fun provideMoshi(): Moshi { - return Moshi.Builder().build() + return Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() } @Provides From fa67ca4f629908f472e15faa9497b5ba623c1bbc Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:16:43 +0900 Subject: [PATCH 71/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20RoleCheckScreen=20?= =?UTF-8?q?isTeacher,=20isStudent=20Boolean=20=EA=B0=92=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=A1=9C=EC=A7=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stackknowledge/login/RoleCheckScreen.kt | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt index 7f96ea6d..5e147d17 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -29,17 +29,21 @@ import com.stackknowledge.login.viewmodel.AuthViewModel @Composable internal fun RoleCheckRoute( - onTeacherButtonClick: (Boolean) -> Unit = {}, - onStudentButtonClick: (Boolean) -> Unit = {}, + onRoleButtonClick: () -> Unit, +authViewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity) ) { - RoleCheckScreen( - onTeacherButtonClick = { isTeacher -> - onTeacherButtonClick(isTeacher) - }, - onStudentButtonClick = { isStudent -> - onStudentButtonClick(isStudent) - } - ) + with(authViewModel) { + RoleCheckScreen( + onTeacherButtonClick = { teacherRoleBoolean -> + onRoleButtonClick() + isTeacher.value = teacherRoleBoolean + }, + onStudentButtonClick = { studentRoleBoolean -> + onRoleButtonClick() + isStudent.value = studentRoleBoolean + } + ) + } } @Composable private fun RoleCheckScreen( From 88436f34cbedb880026544fc2bda441d7e36f0e1 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:16:48 +0900 Subject: [PATCH 72/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20RoleCheckScreen=20?= =?UTF-8?q?isTeacher,=20isStudent=20Boolean=20=EA=B0=92=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=A1=9C=EC=A7=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/stackknowledge/login/RoleCheckScreen.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt index 5e147d17..e3fc49d3 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/RoleCheckScreen.kt @@ -1,6 +1,7 @@ package com.stackknowledge.login +import androidx.activity.ComponentActivity import androidx.compose.foundation.background import com.stackknowledge.design_system.R import androidx.compose.foundation.layout.Box From 82876039b63042d214c39a13fa9998a67eaedecb Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:17:49 +0900 Subject: [PATCH 73/91] =?UTF-8?q?=E2=9C=A8::=20LoginScreen=20GoogleOAuth?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/login/LoginScreen.kt | 70 ++++++++++++------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index c28787af..f26198a2 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -1,5 +1,7 @@ package com.stackknowledge.login +import android.util.Log +import androidx.activity.ComponentActivity import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -12,32 +14,46 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.stackknowledge.design_system.R import com.stackknowledge.design_system.component.button.GoogleButton import com.stackknowledge.design_system.theme.StackKnowledgeAndroidTheme import com.stackknowledge.login.background.LoginBackground import com.stackknowledge.login.viewmodel.AuthViewModel -import com.stackknowledge.login.viewmodel.util.Event +import com.stackknowledge.login.viewmodel.uistate.LoginUiState @Composable internal fun LoginRoute( - onGoogleLoginButtonClicked: () -> Unit = {}, + onSuccess: () -> Unit, + onGoogleLoginButtonClicked: () -> Unit, + viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { + val loginUiState by viewModel.loginUiState.collectAsStateWithLifecycle() + LoginScreen( - onGoogleLoginButtonClicked = {} + onGoogleLoginButtonClicked = onGoogleLoginButtonClicked, + loginUiState = loginUiState, + viewModel = viewModel, + onLoginSuccess = onSuccess ) } @Composable private fun LoginScreen( modifier: Modifier = Modifier, - onGoogleLoginButtonClicked: () -> Unit, + viewModel: AuthViewModel = hiltViewModel(), + onGoogleLoginButtonClicked: () -> Unit = {}, + loginUiState: LoginUiState, + onLoginSuccess: () -> Unit = {}, ) { StackKnowledgeAndroidTheme { colors, typography -> Surface { @@ -46,11 +62,13 @@ private fun LoginScreen( ) { Box { LoginBackground() + Column( modifier = modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(modifier = modifier.height(157.dp)) + Image( painter = painterResource(R.drawable.stack_knowledge_logo), contentDescription = "Stack Knowledge Logo", @@ -58,13 +76,17 @@ private fun LoginScreen( .width(50.dp) .height(50.dp) ) + Spacer(modifier = modifier.height(20.dp)) + Text( text = stringResource(R.string.app_title), style = typography.titleLarge, color = colors.BLACK ) + Spacer(modifier = modifier.height(360.dp)) + Column( modifier = modifier .fillMaxWidth() @@ -73,42 +95,42 @@ private fun LoginScreen( GoogleButton( modifier = modifier.height(60.dp), onClick = { + Log.e("onClick Success", "onClick Success") onGoogleLoginButtonClicked() } ) } } } - } - } - } -} -private suspend fun getLoginData( - viewModel: AuthViewModel, - onSuccess: () -> Unit, - onFailure: () -> Unit, -) { - viewModel.loginResponse.collect { response -> - when (response) { - is Event.Success -> { - viewModel.saveToken(response.data!!) - onSuccess() - } + when(loginUiState) { + is LoginUiState.Success -> { + Log.e("Login Success", "Login Success") + val tokenResponse = loginUiState.loginResponseModel - is Event.BadRequest -> { - onFailure() + viewModel.saveToken(tokenResponse) + onLoginSuccess() + } + is LoginUiState.Error -> { + // Login 실패 처리 (임의) + Log.e("Login Error", "Login Error") + } + LoginUiState.Loading -> { + // Loading 처리 (임의) + Log.e("Login Loading", "Login Loading") + } + } } - - else -> {} } } } + @Preview @Composable fun LoginScreenPre() { LoginScreen( - onGoogleLoginButtonClicked = {} + onGoogleLoginButtonClicked = {}, + loginUiState = LoginUiState.Loading ) } \ No newline at end of file From 5363b1854e592a93561388fc6735723765e98917 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:18:37 +0900 Subject: [PATCH 74/91] =?UTF-8?q?=EF=B8=8F=F0=9F=94=A5::=20AuthDataSourceI?= =?UTF-8?q?mpl=20=EA=B0=9C=ED=96=89=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datasource/auth/AuthDataSourceImpl.kt | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt index 38b27f05..ba24fa16 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/datasource/auth/AuthDataSourceImpl.kt @@ -15,27 +15,17 @@ class AuthDataSourceImpl @Inject constructor( private val authAPI: AuthAPI ) : AuthDataSource { override fun loginStudent(body: LoginRequest): Flow = flow { - Log.e("dataSource loginStudent", "loginStudent") emit( StackKnowledgeApiHandler() - .httpRequest { - authAPI.loginStudent( - body = body, - ) - } + .httpRequest { authAPI.loginStudent(body = body) } .sendRequest() ) - Log.e("dataSource loginStudent", "loginStudent") }.flowOn(Dispatchers.IO) override fun loginTeacher(body: LoginRequest): Flow = flow { emit( StackKnowledgeApiHandler() - .httpRequest { - authAPI.loginTeacher( - body = body, - ) - } + .httpRequest { authAPI.loginTeacher(body = body) } .sendRequest() ) }.flowOn(Dispatchers.IO) From 19c90534af5be5c68a51d87dbb4f973e041b584d Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:19:01 +0900 Subject: [PATCH 75/91] =?UTF-8?q?=E2=9C=A8::=20app=EB=8B=A8=20build.gradle?= =?UTF-8?q?.kts=20google=20service=20dependencies=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7633f067..674bb01b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -27,5 +27,7 @@ dependencies { implementation(project(":feature:score-mission")) implementation(project(":feature:shop")) implementation(libs.junit) + implementation(libs.google.services) + implementation(libs.play.services.auth) androidTestImplementation(libs.androidx.test.ext) } \ No newline at end of file From 432e39070adf56afa1633d36022e9b3f33452f15 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:19:18 +0900 Subject: [PATCH 76/91] =?UTF-8?q?=E2=9C=A8::=20core/data=EB=8B=A8=20build.?= =?UTF-8?q?gradle.kts=20moshi=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/data/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index b957e4a5..d54c565f 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -16,4 +16,5 @@ dependencies { implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.json) implementation(libs.retrofit.moshi.converter) + implementation(libs.retrofit.moshi.codegen) } \ No newline at end of file From e228c08420dd48c88d5d9f52b59572961feb6711 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 16:19:27 +0900 Subject: [PATCH 77/91] =?UTF-8?q?=E2=9C=A8::=20core/network=EB=8B=A8=20bui?= =?UTF-8?q?ld.gradle.kts=20moshi=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/network/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 7c527a13..fb606d39 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -37,6 +37,7 @@ dependencies { implementation(libs.retrofit.moshi.converter) implementation(libs.moshi) implementation(libs.retrofit.moshi.codegen) + implementation(libs.moshi.kotlin) } fun getApiKey(propertyKey: String): String { From 154dd92cd49ac31b412bfba2011055f60916f7de Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 22:38:04 +0900 Subject: [PATCH 78/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20Event,=20errorHand?= =?UTF-8?q?ling=20common=EB=AA=A8=EB=93=88=EB=A1=9C=20import?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/viewmodel/AuthViewModel.kt | 4 +- .../login/viewmodel/util/Event.kt | 59 --------------- .../login/viewmodel/util/errorHandling.kt | 75 ------------------- 3 files changed, 2 insertions(+), 136 deletions(-) delete mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt delete mode 100644 feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index fb0aeb1a..70673cdc 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -6,12 +6,12 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.common.result.Result import com.example.common.result.asResult +import com.example.common.util.Event +import com.example.common.util.errorHandling import com.stackknowledge.login.viewmodel.uistate.LoginUiState import com.stackknowledge.usecase.auth.SaveTokenUseCase import com.stackknowledge.usecase.auth.LoginStudentUseCase import com.stackknowledge.usecase.auth.LoginTeacherUseCase -import com.stackknowledge.login.viewmodel.util.Event -import com.stackknowledge.login.viewmodel.util.errorHandling import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt deleted file mode 100644 index 93bcd407..00000000 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/Event.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.stackknowledge.login.viewmodel.util - -sealed class Event( - val data: T? = null -) { - - object Loading : Event() - - /** - * 성공 - */ - class Success(data: T? = null) : Event(data = data) - - /** - * 400번 요청이 올바르지 않은 경우 - */ - object BadRequest : Event() - - /** - * 401번 비인증 요청 - */ - object Unauthorized : Event() - - /** - * 403번 권한이 없음 - */ - object ForBidden : Event() - - /** - * 404 찾을 수 없는 경우 - */ - object NotFound : Event() - - /** - * 406 맞는 규격이 없는 경우 - */ - object NotAcceptable : Event() - - /** - * 408 요청이 너무 오래 걸리는 경우 - */ - object TimeOut : Event() - - /** - * 409 권한이 없을 때 - */ - object Conflict : Event() - - /** - * 50X 서버에러 - */ - object Server : Event() - - /** - * 예상치 못한 에러 - */ - object UnKnown : Event() - -} \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt deleted file mode 100644 index ae9e40e0..00000000 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/util/errorHandling.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.stackknowledge.login.viewmodel.util - -import android.util.Log -import com.stackknowledge.usecase.exception.BadRequestException -import com.stackknowledge.usecase.exception.ConflictException -import com.stackknowledge.usecase.exception.ForBiddenException -import com.stackknowledge.usecase.exception.NeedLoginException -import com.stackknowledge.usecase.exception.NotAcceptableException -import com.stackknowledge.usecase.exception.NotFoundException -import com.stackknowledge.usecase.exception.ServerException -import com.stackknowledge.usecase.exception.TimeOutException -import com.stackknowledge.usecase.exception.UnauthorizedException - -suspend fun Throwable.errorHandling( - badRequestAction: suspend () -> Unit = {}, - unauthorizedAction: suspend () -> Unit = {}, - forBiddenAction: suspend () -> Unit = {}, - notFoundAction: suspend () -> Unit = {}, - notAcceptableAction: suspend () -> Unit = {}, - timeOutAction: suspend () -> Unit = {}, - conflictAction: suspend () -> Unit = {}, - serverAction: suspend () -> Unit = {}, - unknownAction: suspend () -> Unit = {}, -): Event = - when (this) { - is BadRequestException -> { - errorLog("BadRequestException", message) - badRequestAction() - Event.BadRequest - } - is UnauthorizedException, is NeedLoginException -> { - errorLog("UnauthorizedException", message) - unauthorizedAction() - Event.Unauthorized - } - is ForBiddenException -> { - errorLog("ForBiddenException", message) - forBiddenAction() - Event.ForBidden - } - is NotFoundException -> { - errorLog("NotFoundException", message) - notFoundAction() - Event.NotFound - } - is NotAcceptableException -> { - errorLog("NotAcceptableException", message) - notAcceptableAction() - Event.NotAcceptable - } - is TimeOutException -> { - errorLog("TimeOutException", message) - timeOutAction() - Event.TimeOut - } - is ConflictException -> { - errorLog("ConflictException", message) - conflictAction() - Event.Conflict - } - is ServerException -> { - errorLog("ServerException", message) - serverAction() - Event.Server - } - else -> { - errorLog("UnKnownException", message) - unknownAction() - Event.UnKnown - } - } - -private fun errorLog(tag: String, msg: String?) { - Log.d("ErrorHandling-$tag", msg ?: "알 수 없는 오류") -} \ No newline at end of file From cde5fbd08519d05ae01fbbc94f1607f84dc35d4b Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 22:38:41 +0900 Subject: [PATCH 79/91] =?UTF-8?q?=F0=9F=94=A5::=20MainActivity=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=82=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kdn/stack_knowledge/MainActivity.kt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt index 93bedc55..07473143 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt @@ -107,19 +107,14 @@ class MainActivity : ComponentActivity() { } private fun handleGoogleSignInResult(task: Task) { - try { - val account = task.getResult(ApiException::class.java) - - with(viewModel) { - if (isStudent.value) { - Log.e("serverAuthCode", account.serverAuthCode.toString()) - loginStudent(body = LoginRequestModel(code = account.serverAuthCode.toString())) - } else { - loginTeacher(body = LoginRequestModel(code = account.serverAuthCode.toString())) - } + val account = task.getResult(ApiException::class.java) + + with(viewModel) { + if (isStudent.value) { + loginStudent(body = LoginRequestModel(code = account.serverAuthCode.toString())) + } else { + loginTeacher(body = LoginRequestModel(code = account.serverAuthCode.toString())) } - } catch (e: ApiException) { - Log.e("GoogleSignIn", "Google sign-in failed: ${e.statusCode}", e) } } } \ No newline at end of file From 72de90972bc9d9e6bc1b1100b37021931960d0d7 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 22:38:58 +0900 Subject: [PATCH 80/91] =?UTF-8?q?=F0=9F=94=A5::=20AuthViewModel=20Login=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EB=A1=9C=EA=B7=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/stackknowledge/login/viewmodel/AuthViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index 70673cdc..dc86fa6e 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -1,6 +1,5 @@ package com.stackknowledge.login.viewmodel -import android.util.Log import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -40,7 +39,6 @@ class AuthViewModel @Inject constructor( private set fun loginStudent(body: LoginRequestModel) = viewModelScope.launch { - Log.e("viewModel serverAuthCode", body.code) loginStudentUseCase(body = body) .asResult() .collectLatest { result -> From fdbd9c20df4b4b021ace24cc5d033afdbe2f7f3b Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Thu, 11 Jul 2024 22:49:31 +0900 Subject: [PATCH 81/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20network=20gradle?= =?UTF-8?q?=20getApiKey=20=ED=95=A8=EC=88=98=20null=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/network/build.gradle.kts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index fb606d39..11a84aaf 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -1,4 +1,5 @@ import java.io.FileInputStream +import java.io.FileNotFoundException import java.util.Properties @Suppress("DSL_SCOPE_VIOLATION") @@ -42,7 +43,10 @@ dependencies { fun getApiKey(propertyKey: String): String { val propFile = rootProject.file("./local.properties") + if (!propFile.exists()) { + throw FileNotFoundException("local.properties file not found") + } val properties = Properties() properties.load(FileInputStream(propFile)) - return properties.getProperty(propertyKey) + return properties.getProperty(propertyKey) ?: throw IllegalArgumentException("Property $propertyKey not found in local.properties file") } \ No newline at end of file From 4bad5d7afbb577b94b8d40ab2f072d19d5acd5d6 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:30:21 +0900 Subject: [PATCH 82/91] =?UTF-8?q?=F0=9F=94=A5::=20AndroidManifest=20DEFAUL?= =?UTF-8?q?T,=20BROWSABLE=20category=20=ED=83=9C=EA=B7=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 2 -- core/network/build.gradle.kts | 4 ---- 2 files changed, 6 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6ce0fe51..693f6fc3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,8 +24,6 @@ - - diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 11a84aaf..a3754ee5 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -16,7 +16,6 @@ android { defaultConfig { buildConfigField("String", "BASE_URL", getApiKey("BASE_URL")) buildConfigField("String", "GOOGLE_CLIENT_ID", getApiKey("GOOGLE_CLIENT_ID")) - buildConfigField("String", "REDIRECT_URI", getApiKey("REDIRECT_URI")) buildConfigField("String", "SCOPE", getApiKey("SCOPE")) } @@ -43,9 +42,6 @@ dependencies { fun getApiKey(propertyKey: String): String { val propFile = rootProject.file("./local.properties") - if (!propFile.exists()) { - throw FileNotFoundException("local.properties file not found") - } val properties = Properties() properties.load(FileInputStream(propFile)) return properties.getProperty(propertyKey) ?: throw IllegalArgumentException("Property $propertyKey not found in local.properties file") From b8d98fa1be7c618a74fa0d8416d81c8007f0ff70 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:55:23 +0900 Subject: [PATCH 83/91] =?UTF-8?q?=F0=9F=94=A5::=20GoogleButtonClickEvent?= =?UTF-8?q?=20Log=20=EC=82=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/src/main/java/com/stackknowledge/login/LoginScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index f26198a2..2cf63469 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -95,7 +95,6 @@ private fun LoginScreen( GoogleButton( modifier = modifier.height(60.dp), onClick = { - Log.e("onClick Success", "onClick Success") onGoogleLoginButtonClicked() } ) From d6f85c6f88f7df4f69efac4daa24065ea4d179e0 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:55:48 +0900 Subject: [PATCH 84/91] =?UTF-8?q?=F0=9F=94=A5::=20GoogleLogin=20Success=20?= =?UTF-8?q?Log=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/src/main/java/com/stackknowledge/login/LoginScreen.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 2cf63469..6e18116d 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -104,7 +104,6 @@ private fun LoginScreen( when(loginUiState) { is LoginUiState.Success -> { - Log.e("Login Success", "Login Success") val tokenResponse = loginUiState.loginResponseModel viewModel.saveToken(tokenResponse) From dc5c094f5bcc85b488f2dcaef1016d6e4ea6e960 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:56:16 +0900 Subject: [PATCH 85/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LogoutUseCase=20ko?= =?UTF-8?q?tlin=20=EC=A0=91=EA=B7=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt index 592ec690..5d809ee7 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/SaveTokenUseCase.kt @@ -7,7 +7,7 @@ import javax.inject.Inject class SaveTokenUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke(token: LoginResponseModel) = runCatching { + suspend operator fun invoke(token: LoginResponseModel) = kotlin.runCatching { authRepository.saveToken(token = token) } } \ No newline at end of file From 398a18361e7ab88fb79ec6a9dd39ad2f0a27f4a0 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:56:32 +0900 Subject: [PATCH 86/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LogoutUseCase=20ko?= =?UTF-8?q?tlin=20=EC=A0=91=EA=B7=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt index 00b0ca88..a098b988 100644 --- a/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt +++ b/core/domain/src/main/kotlin/com/stackknowledge/usecase/auth/LogoutUseCase.kt @@ -6,7 +6,7 @@ import javax.inject.Inject class LogoutUseCase @Inject constructor( private val authRepository: AuthRepository ) { - suspend operator fun invoke() = runCatching { + operator fun invoke() = kotlin.runCatching { authRepository.logout() } } \ No newline at end of file From 3d179ab12620f68e138de67e0b0a602e6a073fc1 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:56:48 +0900 Subject: [PATCH 87/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginResponseMappe?= =?UTF-8?q?r=20this=20=EC=A0=91=EA=B7=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapper/response/auth/LoginResponseMapper.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt b/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt index 4c3b614d..75458b0f 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/mapper/response/auth/LoginResponseMapper.kt @@ -4,8 +4,8 @@ import com.stackknowledge.dto.response.auth.LoginResponse import remote.response.auth.LoginResponseModel fun LoginResponse.toModel(): LoginResponseModel = LoginResponseModel( - accessToken = accessToken, - refreshToken = refreshToken, - expiredAt = expiredAt, - authority = authority, + accessToken = this.accessToken, + refreshToken = this.refreshToken, + expiredAt = this.expiredAt, + authority = this.authority, ) \ No newline at end of file From 328c0b2b1539c95c431c3a9e2af5082ca5d399e1 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:57:00 +0900 Subject: [PATCH 88/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginResponse=20?= =?UTF-8?q?=EB=A7=88=EC=A7=80=EB=A7=89=20=ED=95=84=EB=93=9C=20,=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stackknowledge/dto/response/auth/LoginResponse.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt index 1827f577..c3a91ab6 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/response/auth/LoginResponse.kt @@ -9,5 +9,5 @@ data class LoginResponse( @Json(name = "accessToken") val accessToken: String, @Json(name = "refreshToken") val refreshToken: String, @Json(name = "expiredAt") val expiredAt: String, - @Json(name = "authority") val authority: Authority + @Json(name = "authority") val authority: Authority, ) \ No newline at end of file From 0fa43ff19298d5fb9315ee11ba1b2025bad2573d Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:57:06 +0900 Subject: [PATCH 89/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20LoginRequest=20?= =?UTF-8?q?=EB=A7=88=EC=A7=80=EB=A7=89=20=ED=95=84=EB=93=9C=20,=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt b/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt index bdc701b4..f6a75c2f 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/dto/request/auth/LoginRequest.kt @@ -5,5 +5,5 @@ import com.squareup.moshi.JsonClass @JsonClass(generateAdapter = true) data class LoginRequest( - @Json(name = "code") val code: String + @Json(name = "code") val code: String, ) \ No newline at end of file From 8800de7129c194ce14f1b4340a2525a34d6ddde0 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:57:15 +0900 Subject: [PATCH 90/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20Authority=20?= =?UTF-8?q?=EB=A7=88=EC=A7=80=EB=A7=89=20=ED=95=84=EB=93=9C=20,=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/model/src/main/kotlin/enumdata/Authority.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/model/src/main/kotlin/enumdata/Authority.kt b/core/model/src/main/kotlin/enumdata/Authority.kt index 7c8f9761..64c32a62 100644 --- a/core/model/src/main/kotlin/enumdata/Authority.kt +++ b/core/model/src/main/kotlin/enumdata/Authority.kt @@ -2,5 +2,5 @@ package enumdata enum class Authority { ROLE_TEACHER, - ROLE_STUDENT + ROLE_STUDENT, } \ No newline at end of file From 2585147f4afe9333d46ab5db1695976ee4ff9937 Mon Sep 17 00:00:00 2001 From: Chaejongin12 Date: Fri, 12 Jul 2024 09:57:53 +0900 Subject: [PATCH 91/91] =?UTF-8?q?=E2=99=BB=EF=B8=8F::=20MainActivity=20Toa?= =?UTF-8?q?st=20=EC=83=9D=EC=84=B1=20=EC=8B=9C=20makeToast=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=82=AC=EC=9A=A9=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?makeToast=EC=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 674bb01b..a211eae0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -19,6 +19,7 @@ dependencies { implementation(project(":core:design-system")) implementation(project(":core:ui")) implementation(project(":core:model")) + implementation(project(":core:common")) implementation(project(":feature:login")) implementation(project(":feature:main")) diff --git a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt index 07473143..7633a287 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt @@ -12,6 +12,7 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import com.example.common.toast.makeToast import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInAccount import com.google.android.gms.auth.api.signin.GoogleSignInClient @@ -85,7 +86,7 @@ class MainActivity : ComponentActivity() { } else { doubleBackToExitPressedOnce = true backPressedTimestamp = currentTime - Toast.makeText(this, getString(R.string.close_app), Toast.LENGTH_SHORT).show() + makeToast(this, getString(R.string.close_app), Toast.LENGTH_SHORT) } }