diff --git a/data/src/main/java/com/d83t/bpm/data/datastore/DataStoreManager.kt b/data/src/main/java/com/d83t/bpm/data/datastore/DataStoreManager.kt index 0f97549..29c92f8 100644 --- a/data/src/main/java/com/d83t/bpm/data/datastore/DataStoreManager.kt +++ b/data/src/main/java/com/d83t/bpm/data/datastore/DataStoreManager.kt @@ -3,18 +3,28 @@ package com.d83t.bpm.data.datastore import android.content.Context import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.stringPreferencesKey import androidx.datastore.preferences.preferencesDataStore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject +import kotlinx.coroutines.flow.flow class DataStoreManager @Inject constructor(private val context: Context) { private val Context.instance: DataStore by preferencesDataStore(name = "bpm") - fun getKakaoId(): Flow { + fun getKakaoId(): Flow { return context.instance.data.map { preferences -> - preferences[stringPreferencesKey(name = "kakaoId")] ?: "null" + preferences[stringPreferencesKey(name = "kakaoId")] + } + } + + suspend fun setKakaoUserId(kakaoId : String) : Flow { + return flow { + context.instance.edit { preferences -> + preferences[stringPreferencesKey(name = "kakaoId")] = kakaoId + } } } } \ No newline at end of file diff --git a/data/src/main/java/com/d83t/bpm/data/repositoryImpl/SplashRepositoryImpl.kt b/data/src/main/java/com/d83t/bpm/data/repositoryImpl/SplashRepositoryImpl.kt index f438497..bcbf581 100644 --- a/data/src/main/java/com/d83t/bpm/data/repositoryImpl/SplashRepositoryImpl.kt +++ b/data/src/main/java/com/d83t/bpm/data/repositoryImpl/SplashRepositoryImpl.kt @@ -9,7 +9,11 @@ class SplashRepositoryImpl @Inject constructor( private val dataStoreManager: DataStoreManager ) : SplashRepository { - override fun getStoredId(): Flow { + override fun getKakaoUserId(): Flow { return dataStoreManager.getKakaoId() } + + override suspend fun setKakaoUserId(kakaoId : String): Flow { + return dataStoreManager.setKakaoUserId(kakaoId) + } } \ No newline at end of file diff --git a/domain/src/main/java/com/d83t/bpm/domain/repository/SplashRepository.kt b/domain/src/main/java/com/d83t/bpm/domain/repository/SplashRepository.kt index da8368f..b1d6c4b 100644 --- a/domain/src/main/java/com/d83t/bpm/domain/repository/SplashRepository.kt +++ b/domain/src/main/java/com/d83t/bpm/domain/repository/SplashRepository.kt @@ -4,5 +4,7 @@ import kotlinx.coroutines.flow.Flow interface SplashRepository { - fun getStoredId(): Flow + fun getKakaoUserId(): Flow + + suspend fun setKakaoUserId(kakaoId : String): Flow } \ No newline at end of file diff --git a/domain/src/main/java/com/d83t/bpm/domain/usecase/GetStoredIdUseCase.kt b/domain/src/main/java/com/d83t/bpm/domain/usecase/GetStoredIdUseCase.kt deleted file mode 100644 index 6076bfa..0000000 --- a/domain/src/main/java/com/d83t/bpm/domain/usecase/GetStoredIdUseCase.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.d83t.bpm.domain.usecase - -import com.d83t.bpm.domain.repository.SplashRepository -import kotlinx.coroutines.flow.Flow -import javax.inject.Inject - -class GetStoredIdUseCase @Inject constructor( - private val splashRepository: SplashRepository -) { - operator fun invoke(): Flow { - return splashRepository.getStoredId() - } -} \ No newline at end of file diff --git a/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/GetKakaoUserIdUseCase.kt b/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/GetKakaoUserIdUseCase.kt new file mode 100644 index 0000000..4842fa3 --- /dev/null +++ b/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/GetKakaoUserIdUseCase.kt @@ -0,0 +1,13 @@ +package com.d83t.bpm.domain.usecase.splash + +import com.d83t.bpm.domain.repository.SplashRepository +import kotlinx.coroutines.flow.Flow +import javax.inject.Inject + +class GetKakaoUserIdUseCase @Inject constructor( + private val splashRepository: SplashRepository +) { + operator fun invoke(): Flow { + return splashRepository.getKakaoUserId() + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/SetKakaoUserIdUseCase.kt b/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/SetKakaoUserIdUseCase.kt new file mode 100644 index 0000000..bf460ad --- /dev/null +++ b/domain/src/main/java/com/d83t/bpm/domain/usecase/splash/SetKakaoUserIdUseCase.kt @@ -0,0 +1,13 @@ +package com.d83t.bpm.domain.usecase.splash + +import com.d83t.bpm.domain.repository.SplashRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +class SetKakaoUserIdUseCase @Inject constructor( + private val splashRepository: SplashRepository +) { + suspend operator fun invoke(kakaoId: String): Flow { + return splashRepository.setKakaoUserId(kakaoId) + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/di/UseCaseModule.kt b/presentation/src/main/java/com/d83t/bpm/presentation/di/UseCaseModule.kt index 26a2980..19499bb 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/di/UseCaseModule.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/di/UseCaseModule.kt @@ -3,7 +3,8 @@ package com.d83t.bpm.presentation.di import com.d83t.bpm.domain.repository.MainRepository import com.d83t.bpm.domain.repository.SplashRepository import com.d83t.bpm.domain.usecase.GetSampleTextUseCase -import com.d83t.bpm.domain.usecase.GetStoredIdUseCase +import com.d83t.bpm.domain.usecase.splash.GetKakaoUserIdUseCase +import com.d83t.bpm.domain.usecase.splash.SetKakaoUserIdUseCase import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -22,7 +23,13 @@ object UseCaseModule { @Provides @ViewModelScoped - fun provideGetStoredIdUseCase(splashRepository: SplashRepository): GetStoredIdUseCase { - return GetStoredIdUseCase(splashRepository) + fun provideGetKakaoUserIdUseCase(splashRepository: SplashRepository): GetKakaoUserIdUseCase { + return GetKakaoUserIdUseCase(splashRepository) + } + + @Provides + @ViewModelScoped + fun provideSetKakaoUserIdUseCase(splashRepository: SplashRepository): SetKakaoUserIdUseCase { + return SetKakaoUserIdUseCase(splashRepository) } } \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/ui/main/MainActivity.kt b/presentation/src/main/java/com/d83t/bpm/presentation/ui/main/MainActivity.kt index b7a8fc0..d8e6f04 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/ui/main/MainActivity.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/ui/main/MainActivity.kt @@ -1,5 +1,7 @@ package com.d83t.bpm.presentation.ui.main +import android.content.Context +import android.content.Intent import androidx.activity.viewModels import com.d83t.bpm.presentation.base.BaseActivity import com.d83t.bpm.presentation.databinding.ActivityMainBinding @@ -34,4 +36,12 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl } } + + companion object { + + fun newIntent(context: Context): Intent { + return Intent(context, MainActivity::class.java) + } + + } } \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashActivity.kt b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashActivity.kt index 5beda97..6ba0e76 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashActivity.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashActivity.kt @@ -29,8 +29,15 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.d83t.bpm.presentation.R import com.d83t.bpm.presentation.base.BaseComponentActivity +import com.d83t.bpm.presentation.compose.theme.BPMShapes +import com.d83t.bpm.presentation.compose.theme.BPMTheme +import com.d83t.bpm.presentation.compose.theme.BPMTypography +import com.d83t.bpm.presentation.ui.main.MainActivity import com.d83t.bpm.presentation.compose.theme.* import com.d83t.bpm.presentation.util.repeatCallDefaultOnStarted +import com.d83t.bpm.presentation.util.showDebugToast +import com.d83t.bpm.presentation.util.showToast +import com.kakao.sdk.user.UserApiClient import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.MainScope import kotlinx.coroutines.delay @@ -40,15 +47,22 @@ import kotlinx.coroutines.launch @SuppressLint("CustomSplashScreen") @AndroidEntryPoint class SplashActivity : BaseComponentActivity() { + override val viewModel: SplashViewModel by viewModels() + private val startButtonVisibilityState = mutableStateOf(false) + + private val kakaoLoginInstance: UserApiClient by lazy { + UserApiClient.instance + } + override fun initUi() { setContent { BPMTheme { SplashActivityContent( startButtonVisibilityState = startButtonVisibilityState, onClickStartButton = { - // TODO : SignUp With Kakao + setupLogin() } ) } @@ -65,17 +79,47 @@ class SplashActivity : BaseComponentActivity() { viewModel.getStoredId() } } - is SplashState.KakaoId -> { - if (state.id == "null") { + is SplashState.SignUp -> { + if (state.id == "null" || state.id.isNullOrEmpty()) { startButtonVisibilityState.value = true } else { - // TODO : SignIn + viewModel.setFinish() } } + SplashState.SignIn -> { + viewModel.setFinish() + } + SplashState.Finish -> { + goToMainActivity() + } } } } } + + private fun setupLogin() { + // 카카오톡으로 로그인 + if (kakaoLoginInstance.isKakaoTalkLoginAvailable(this)) { + kakaoLoginInstance.loginWithKakaoTalk(this) { loginInfo, error -> + if (error != null) { + // 로그인 실패 + showDebugToast("login failed! cause : ${error.message}") + showToast("로그인에 실패하였습니다. 다시 시도해 주세요.") + } else if (loginInfo != null) { + // 로그인 성공 + viewModel.setLoginId(loginInfo.idToken ?: "") + showDebugToast("login succeed. user token : ${loginInfo.idToken}") + } + } + } else { + showToast("로그인에 실패하였습니다. 다시 시도해 주세요.") + } + } + + private fun goToMainActivity() { + startActivity(MainActivity.newIntent(this)) + finish() + } } @Composable diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashState.kt b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashState.kt index 1a706cd..91017e5 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashState.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashState.kt @@ -4,5 +4,8 @@ import com.d83t.bpm.presentation.util.ComposeUiState sealed interface SplashState : ComposeUiState { object Init : SplashState - data class KakaoId(val id: String) : SplashState + data class SignUp(val id: String?) : SplashState + + object SignIn : SplashState + object Finish : SplashState } \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewEvent.kt b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewEvent.kt index e84b6e3..6e62b98 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewEvent.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewEvent.kt @@ -1,5 +1,3 @@ package com.d83t.bpm.presentation.ui.splash -interface SplashViewEvent { - object Click : SplashViewEvent -} \ No newline at end of file +sealed interface SplashViewEvent \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewModel.kt b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewModel.kt index 37815fb..df05c34 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewModel.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/ui/splash/SplashViewModel.kt @@ -1,20 +1,28 @@ package com.d83t.bpm.presentation.ui.splash import androidx.lifecycle.viewModelScope -import com.d83t.bpm.domain.usecase.GetStoredIdUseCase +import com.d83t.bpm.domain.usecase.splash.GetKakaoUserIdUseCase +import com.d83t.bpm.domain.usecase.splash.SetKakaoUserIdUseCase import com.d83t.bpm.presentation.base.BaseViewModel import com.d83t.bpm.presentation.di.IoDispatcher import com.d83t.bpm.presentation.di.MainDispatcher import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import javax.inject.Inject @HiltViewModel class SplashViewModel @Inject constructor( - private val getStoredIdUseCase: GetStoredIdUseCase, + private val getKakaoUserIdUseCase: GetKakaoUserIdUseCase, + private val setKakaoUserIdUseCase: SetKakaoUserIdUseCase, @MainDispatcher private val mainDispatcher: CoroutineDispatcher, @IoDispatcher private val ioDispatcher: CoroutineDispatcher ) : BaseViewModel() { @@ -27,12 +35,43 @@ class SplashViewModel @Inject constructor( val state: StateFlow get() = _state + private val exceptionHandler: CoroutineExceptionHandler by lazy { + CoroutineExceptionHandler { coroutineContext, throwable -> + when (state.value) { + SplashState.SignIn -> { + // TODO : Exception Handling + } + else -> { + // TODO : Exception Handling + } + } + + } + } + fun getStoredId() { viewModelScope.launch(ioDispatcher) { - val kakaoId = getStoredIdUseCase().first() - withContext(mainDispatcher) { - _state.emit(SplashState.KakaoId(kakaoId)) - } + getKakaoUserIdUseCase().onEach { + withContext(mainDispatcher) { + _state.emit(SplashState.SignUp(it)) + } + }.launchIn(viewModelScope) + } + } + + fun setLoginId(kakaoId: String) { + viewModelScope.launch(ioDispatcher + exceptionHandler) { + setKakaoUserIdUseCase(kakaoId).onEach { + withContext(mainDispatcher) { + _state.emit(SplashState.SignUp(it)) + } + }.launchIn(viewModelScope) + } + } + + fun setFinish() { + viewModelScope.launch { + _state.emit(SplashState.Finish) } } } \ No newline at end of file diff --git a/presentation/src/main/java/com/d83t/bpm/presentation/util/ToastUtils.kt b/presentation/src/main/java/com/d83t/bpm/presentation/util/ToastUtils.kt index ce07b4c..2db6f78 100644 --- a/presentation/src/main/java/com/d83t/bpm/presentation/util/ToastUtils.kt +++ b/presentation/src/main/java/com/d83t/bpm/presentation/util/ToastUtils.kt @@ -5,4 +5,8 @@ import android.widget.Toast fun Context.showToast(text: String) { Toast.makeText(this, text, Toast.LENGTH_SHORT).show() +} + +fun Context.showDebugToast(text: String) { + Toast.makeText(this, "Debug Mode! $text", Toast.LENGTH_SHORT).show() } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4fb5f46..cd261a4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,6 +10,8 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + + maven { url 'https://devrepo.kakao.com/nexus/content/groups/public/' } } } rootProject.name = "BPM"