diff --git a/README/README_seminar_7.md b/README/README_seminar_7.md new file mode 100644 index 0000000..d08f14d --- /dev/null +++ b/README/README_seminar_7.md @@ -0,0 +1 @@ +7주차 README입니다 - https://velog.io/@gxstxdgxs/THE-SOPT-Android-7차-세미나-과제 diff --git a/app/build.gradle b/app/build.gradle index 60d9245..632d224 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,10 +47,10 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.4.1' - implementation 'com.google.android.material:material:1.6.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.3' + implementation 'androidx.core:core-ktx:1.8.0' + implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.legacy:legacy-support-v4:1.0.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' @@ -61,8 +61,8 @@ dependencies { kapt 'androidx.room:room-compiler:2.4.2' // Hilt - implementation "com.google.dagger:hilt-android:2.40" - kapt "com.google.dagger:hilt-android-compiler:2.40" + implementation "com.google.dagger:hilt-android:2.41" + kapt "com.google.dagger:hilt-android-compiler:2.41" // ktx implementation 'androidx.activity:activity-ktx:1.4.0' @@ -90,5 +90,11 @@ dependencies { // OkHttp3 implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2' - implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' + implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' + + // Coroutines + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' + + // lifecycle + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8fe9acb..d6784ce 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,6 +14,15 @@ android:supportsRtl="true" android:theme="@style/Theme.SOPT_Seminar_30th" android:usesCleartextTraffic="true"> + + + + + + + @@ -27,13 +36,7 @@ - - - - - - + android:windowSoftInputMode="adjustResize" /> \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/data/database/AppDatabase.kt b/app/src/main/java/co/kr/sopt_seminar_30th/data/database/AppDatabase.kt index 91003b3..41007c5 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/data/database/AppDatabase.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/data/database/AppDatabase.kt @@ -4,18 +4,21 @@ import android.content.Context import androidx.room.Database import androidx.room.Room import androidx.room.RoomDatabase +import co.kr.sopt_seminar_30th.data.datasource.local.AuthorizationDao import co.kr.sopt_seminar_30th.data.datasource.local.FollowerDao import co.kr.sopt_seminar_30th.data.datasource.local.RepositoryDao import co.kr.sopt_seminar_30th.data.datasource.local.UserDao +import co.kr.sopt_seminar_30th.data.model.dto.AuthorizationDto import co.kr.sopt_seminar_30th.data.model.dto.FollowerDto import co.kr.sopt_seminar_30th.data.model.dto.RepositoryDto import co.kr.sopt_seminar_30th.data.model.dto.UserDto -@Database(entities = [UserDto::class, FollowerDto::class, RepositoryDto::class], version = 1) +@Database(entities = [UserDto::class, FollowerDto::class, RepositoryDto::class, AuthorizationDto::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao abstract fun followerDao(): FollowerDao abstract fun repositoryDao(): RepositoryDao + abstract fun authorizationDao(): AuthorizationDao companion object { fun getInstance(context: Context): AppDatabase = Room diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/AuthorizationDao.kt b/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/AuthorizationDao.kt new file mode 100644 index 0000000..b4ca3ea --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/AuthorizationDao.kt @@ -0,0 +1,16 @@ +package co.kr.sopt_seminar_30th.data.datasource.local + +import androidx.room.* +import co.kr.sopt_seminar_30th.data.model.dto.AuthorizationDto + +@Dao +interface AuthorizationDao { + @Insert + suspend fun insertAuthorization(authorizationDto: AuthorizationDto) + + @Delete + suspend fun deleteAuthorization(authorizationDto: AuthorizationDto) + + @Query("SELECT * FROM Authorization WHERE userId = :id") + suspend fun getAuthorization(id: String): AuthorizationDto +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/SopthubDataStore.kt b/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/SopthubDataStore.kt index 98a6abe..31633ba 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/SopthubDataStore.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/data/datasource/local/SopthubDataStore.kt @@ -33,4 +33,8 @@ class SopthubDataStore @Inject constructor( var autoLogin: Boolean set(value) = dataStore.edit { putBoolean("AUTO_LOGIN", value) } get() = dataStore.getBoolean("AUTO_LOGIN", false) + + var onBoardingEnabled: Boolean + set(value) = dataStore.edit { putBoolean("ON_BOARDING_ENABLED", value) } + get() = dataStore.getBoolean("ON_BOARDING_ENABLED", false) } \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/data/model/dto/AuthorizationDto.kt b/app/src/main/java/co/kr/sopt_seminar_30th/data/model/dto/AuthorizationDto.kt new file mode 100644 index 0000000..cd85811 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/data/model/dto/AuthorizationDto.kt @@ -0,0 +1,11 @@ +package co.kr.sopt_seminar_30th.data.model.dto + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "Authorization") +data class AuthorizationDto( + @PrimaryKey val userId: String, + @ColumnInfo(name = "autoLogin") val autoLogin: Boolean +) diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/data/repositoryimpl/local/AuthorizationRepositoryImpl.kt b/app/src/main/java/co/kr/sopt_seminar_30th/data/repositoryimpl/local/AuthorizationRepositoryImpl.kt new file mode 100644 index 0000000..d074cf8 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/data/repositoryimpl/local/AuthorizationRepositoryImpl.kt @@ -0,0 +1,28 @@ +package co.kr.sopt_seminar_30th.data.repositoryimpl.local + +import co.kr.sopt_seminar_30th.data.datasource.local.AuthorizationDao +import co.kr.sopt_seminar_30th.data.model.dto.AuthorizationDto +import co.kr.sopt_seminar_30th.domain.repository.local.AuthorizationRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import javax.inject.Inject + +class AuthorizationRepositoryImpl @Inject constructor( + private val dao: AuthorizationDao, + private val coroutineDispatcher: CoroutineDispatcher +) : AuthorizationRepository { + override suspend fun insertAuthorization(userId: String, autoLogin: Boolean) = + withContext(coroutineDispatcher) { + dao.insertAuthorization(AuthorizationDto(userId, autoLogin)) + } + + override suspend fun deleteAuthorization(userId: String, autoLogin: Boolean) = + withContext(coroutineDispatcher) { + dao.deleteAuthorization(AuthorizationDto(userId, autoLogin)) + } + + override suspend fun getAuthorization(userId: String): Boolean = + withContext(coroutineDispatcher) { + dao.getAuthorization(userId).autoLogin + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/di/DbModule.kt b/app/src/main/java/co/kr/sopt_seminar_30th/di/DbModule.kt index 419c58c..c213d61 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/di/DbModule.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/di/DbModule.kt @@ -2,6 +2,7 @@ package co.kr.sopt_seminar_30th.di import android.content.Context import co.kr.sopt_seminar_30th.data.database.AppDatabase +import co.kr.sopt_seminar_30th.data.datasource.local.AuthorizationDao import co.kr.sopt_seminar_30th.data.datasource.local.FollowerDao import co.kr.sopt_seminar_30th.data.datasource.local.RepositoryDao import co.kr.sopt_seminar_30th.data.datasource.local.UserDao @@ -33,4 +34,8 @@ object DbModule { @Singleton @Provides fun provideRepositoryDao(appDatabase: AppDatabase): RepositoryDao = appDatabase.repositoryDao() + + @Singleton + @Provides + fun provideAuthorizationDao(appDatabase: AppDatabase): AuthorizationDao = appDatabase.authorizationDao() } \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/di/RepositoryModule.kt b/app/src/main/java/co/kr/sopt_seminar_30th/di/RepositoryModule.kt index 73c621f..7a17bdd 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/di/RepositoryModule.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/di/RepositoryModule.kt @@ -1,9 +1,7 @@ package co.kr.sopt_seminar_30th.di -import co.kr.sopt_seminar_30th.data.datasource.local.FollowerDao -import co.kr.sopt_seminar_30th.data.datasource.local.RepositoryDao -import co.kr.sopt_seminar_30th.data.datasource.local.SopthubDataStore -import co.kr.sopt_seminar_30th.data.datasource.local.UserDao +import co.kr.sopt_seminar_30th.data.datasource.local.* +import co.kr.sopt_seminar_30th.data.repositoryimpl.local.AuthorizationRepositoryImpl import co.kr.sopt_seminar_30th.data.repositoryimpl.local.FollowerRepositoryImpl import co.kr.sopt_seminar_30th.data.repositoryimpl.local.RepositoryRepositoryImpl import co.kr.sopt_seminar_30th.data.repositoryimpl.local.UserRepositoryImpl @@ -13,6 +11,7 @@ import co.kr.sopt_seminar_30th.data.repositoryimpl.remote.SignUpRepositoryImpl import co.kr.sopt_seminar_30th.data.service.auth.SignInService import co.kr.sopt_seminar_30th.data.service.auth.SignUpService import co.kr.sopt_seminar_30th.data.service.home.HomeService +import co.kr.sopt_seminar_30th.domain.repository.local.AuthorizationRepository import co.kr.sopt_seminar_30th.domain.repository.local.FollowerRepository import co.kr.sopt_seminar_30th.domain.repository.local.RepositoryRepository import co.kr.sopt_seminar_30th.domain.repository.local.UserRepository @@ -68,4 +67,12 @@ object RepositoryModule { homeService: HomeService, @IoDispatcher coroutineDispatcher: CoroutineDispatcher ): HomeRepository = HomeRepositoryImpl(homeService, coroutineDispatcher) + + @Singleton + @Provides + fun provideAuthorizationRepository( + authorizationDao: AuthorizationDao, + @IoDispatcher coroutineDispatcher: CoroutineDispatcher + ): AuthorizationRepository = + AuthorizationRepositoryImpl(authorizationDao, coroutineDispatcher) } \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/domain/repository/local/AuthorizationRepository.kt b/app/src/main/java/co/kr/sopt_seminar_30th/domain/repository/local/AuthorizationRepository.kt new file mode 100644 index 0000000..5f7cdb8 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/domain/repository/local/AuthorizationRepository.kt @@ -0,0 +1,7 @@ +package co.kr.sopt_seminar_30th.domain.repository.local + +interface AuthorizationRepository { + suspend fun insertAuthorization(userId: String, autoLogin: Boolean) + suspend fun deleteAuthorization(userId: String, autoLogin: Boolean) + suspend fun getAuthorization(userId: String): Boolean +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/auth/SignInActivity.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/auth/SignInActivity.kt index 85d8243..8bb59a7 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/auth/SignInActivity.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/auth/SignInActivity.kt @@ -5,12 +5,18 @@ import android.os.Bundle import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope import co.kr.sopt_seminar_30th.R +import co.kr.sopt_seminar_30th.data.datasource.local.SopthubDataStore import co.kr.sopt_seminar_30th.databinding.ActivitySignInBinding import co.kr.sopt_seminar_30th.presentation.ui.base.BaseActivity import co.kr.sopt_seminar_30th.presentation.ui.home.HomeActivity import co.kr.sopt_seminar_30th.presentation.viewmodel.SignInViewModel import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject @AndroidEntryPoint class SignInActivity : BaseActivity() { @@ -19,6 +25,9 @@ class SignInActivity : BaseActivity() { private val signInViewModel by viewModels() + @Inject + lateinit var dataStore: SopthubDataStore + private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == RESULT_OK) { @@ -34,11 +43,18 @@ class SignInActivity : BaseActivity() { binding.viewmodel = signInViewModel binding.lifecycleOwner = this + loginWithAutoLogin() signUp() login() observeLogin() } + private fun loginWithAutoLogin() { + if (dataStore.autoLogin) { + signInViewModel.checkAuthorization(dataStore.userId) + } + } + private fun signUp() { binding.btnSignUp.setOnClickListener { val intent = Intent(this, SignUpActivity::class.java) @@ -65,34 +81,30 @@ class SignInActivity : BaseActivity() { } } } - signInViewModel.isEmailIncorrect.observe(this) { - if(it) { + if (it) { Toast.makeText(this, "존재하지 않는 계정입니다", Toast.LENGTH_SHORT).show() binding.etUserPassword.text.clear() } } - signInViewModel.isPasswordIncorrect.observe(this) { - if(it) { + if (it) { Toast.makeText(this, "비밀번호가 일치하지 않습니다", Toast.LENGTH_SHORT).show() binding.etUserPassword.text.clear() } } - signInViewModel.isEmpty.observe(this) { if (it) { Toast.makeText(this, "아이디/비밀번호를 확인해주세요", Toast.LENGTH_SHORT).show() } } - - signInViewModel.autoLogin.observe(this) { - if (it) { - Toast.makeText(this, "자동로그인 성공", Toast.LENGTH_SHORT).show() - val intent = Intent(this, HomeActivity::class.java) - startActivity(intent) - finish() - } - } + signInViewModel.autoLoginState + .flowWithLifecycle(this.lifecycle) + .onEach { + if(it) { + startActivity(Intent(this, HomeActivity::class.java)) + finish() + } + }.launchIn(this.lifecycleScope) } } \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingActivity.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingActivity.kt new file mode 100644 index 0000000..e687c28 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingActivity.kt @@ -0,0 +1,62 @@ +package co.kr.sopt_seminar_30th.presentation.ui.onboarding + +import android.content.Intent +import android.os.Bundle +import androidx.activity.viewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import co.kr.sopt_seminar_30th.R +import co.kr.sopt_seminar_30th.data.datasource.local.SopthubDataStore +import co.kr.sopt_seminar_30th.databinding.ActivityOnBoardingBinding +import co.kr.sopt_seminar_30th.presentation.ui.auth.SignInActivity +import co.kr.sopt_seminar_30th.presentation.ui.base.BaseActivity +import co.kr.sopt_seminar_30th.presentation.ui.home.HomeActivity +import co.kr.sopt_seminar_30th.presentation.viewmodel.OnBoardingViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import javax.inject.Inject + +@AndroidEntryPoint +class OnBoardingActivity : BaseActivity() { + override val layoutRes: Int + get() = R.layout.activity_on_boarding + + private val viewModel by viewModels() + + @Inject + lateinit var dataStore: SopthubDataStore + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + checkAutoLoginEnabled() + checkOnBoardingEnabled() + observeData() + } + + private fun checkAutoLoginEnabled() { + if (dataStore.autoLogin) { + viewModel.checkAuthorization(dataStore.userId) + } + } + + private fun checkOnBoardingEnabled() { + if (dataStore.onBoardingEnabled) { + if (!isFinishing) { + startActivity(Intent(this, SignInActivity::class.java)) + finish() + } + } + } + + private fun observeData() { + viewModel.autoLoginState + .flowWithLifecycle(this.lifecycle) + .onEach { + if (it) { + startActivity(Intent(this, HomeActivity::class.java)) + finish() + } + }.launchIn(this.lifecycleScope) + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingFirstFragment.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingFirstFragment.kt new file mode 100644 index 0000000..6b63384 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingFirstFragment.kt @@ -0,0 +1,30 @@ +package co.kr.sopt_seminar_30th.presentation.ui.onboarding + +import android.os.Bundle +import android.view.View +import androidx.navigation.fragment.findNavController +import co.kr.sopt_seminar_30th.R +import co.kr.sopt_seminar_30th.data.datasource.local.SopthubDataStore +import co.kr.sopt_seminar_30th.databinding.FragmentOnBoardingFirstBinding +import co.kr.sopt_seminar_30th.presentation.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class OnBoardingFirstFragment : BaseFragment() { + override val TAG: String + get() = OnBoardingFirstFragment::class.java.simpleName + override val layoutRes: Int + get() = R.layout.fragment_on_boarding_first + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setOnBtnNextClickListener() + } + + private fun setOnBtnNextClickListener() { + binding.btnOnBoardingNext.setOnClickListener { + findNavController().navigate(R.id.action_fragment_on_boarding_first_to_fragment_on_boarding_second) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingSecondFragment.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingSecondFragment.kt new file mode 100644 index 0000000..97d3f48 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingSecondFragment.kt @@ -0,0 +1,28 @@ +package co.kr.sopt_seminar_30th.presentation.ui.onboarding + +import android.os.Bundle +import android.view.View +import androidx.navigation.fragment.findNavController +import co.kr.sopt_seminar_30th.R +import co.kr.sopt_seminar_30th.databinding.FragmentOnBoardingSecondBinding +import co.kr.sopt_seminar_30th.presentation.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint + +@AndroidEntryPoint +class OnBoardingSecondFragment : BaseFragment() { + override val TAG: String + get() = OnBoardingSecondFragment::class.java.simpleName + override val layoutRes: Int + get() = R.layout.fragment_on_boarding_second + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setOnBtnNextClickListener() + } + + private fun setOnBtnNextClickListener() { + binding.btnOnBoardingNext.setOnClickListener { + findNavController().navigate(R.id.action_fragment_on_boarding_second_to_fragment_on_boarding_third) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingThirdFragment.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingThirdFragment.kt new file mode 100644 index 0000000..7587d06 --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/ui/onboarding/OnBoardingThirdFragment.kt @@ -0,0 +1,35 @@ +package co.kr.sopt_seminar_30th.presentation.ui.onboarding + +import android.os.Bundle +import android.view.View +import androidx.navigation.fragment.findNavController +import co.kr.sopt_seminar_30th.R +import co.kr.sopt_seminar_30th.data.datasource.local.SopthubDataStore +import co.kr.sopt_seminar_30th.databinding.FragmentOnBoardingThirdBinding +import co.kr.sopt_seminar_30th.presentation.ui.base.BaseFragment +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject + +@AndroidEntryPoint +class OnBoardingThirdFragment : BaseFragment() { + override val TAG: String + get() = OnBoardingThirdFragment::class.java.simpleName + override val layoutRes: Int + get() = R.layout.fragment_on_boarding_third + + @Inject + lateinit var dataStore: SopthubDataStore + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setOnBtnStartClickListener() + } + + private fun setOnBtnStartClickListener() { + binding.btnOnBoardingStart.setOnClickListener { + dataStore.onBoardingEnabled = true + findNavController().navigate(R.id.action_fragment_on_boarding_third_to_activity_sign_in) + requireActivity().finish() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/HomeViewModel.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/HomeViewModel.kt index ad20b95..8d35734 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/HomeViewModel.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/HomeViewModel.kt @@ -9,6 +9,7 @@ import androidx.lifecycle.viewModelScope import co.kr.sopt_seminar_30th.domain.entity.home.UserFollow import co.kr.sopt_seminar_30th.domain.entity.home.UserProfile import co.kr.sopt_seminar_30th.domain.entity.home.UserRepository +import co.kr.sopt_seminar_30th.domain.repository.local.AuthorizationRepository import co.kr.sopt_seminar_30th.domain.repository.remote.HomeRepository import co.kr.sopt_seminar_30th.domain.usecase.user.GetUserIdUseCase import co.kr.sopt_seminar_30th.domain.usecase.user.TurnOffAutoLoginUseCase @@ -23,7 +24,8 @@ import javax.inject.Inject class HomeViewModel @Inject constructor( private val getUserIdUseCase: GetUserIdUseCase, private val turnOffAutoLoginUseCase: TurnOffAutoLoginUseCase, - private val homeRepository: HomeRepository + private val homeRepository: HomeRepository, + private val authorizationRepository: AuthorizationRepository ) : ViewModel() { private var id: String = "" @@ -216,10 +218,14 @@ class HomeViewModel @Inject constructor( fun turnOffAutoLogin() { viewModelScope.launch { - kotlin.runCatching { + runCatching { turnOffAutoLoginUseCase() }.onSuccess { - _turnOffSuccess.value = true + runCatching { + authorizationRepository.deleteAuthorization(id, true) + }.onSuccess { + _turnOffSuccess.value = true + } } } } diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/OnBoardingViewModel.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/OnBoardingViewModel.kt new file mode 100644 index 0000000..644a37e --- /dev/null +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/OnBoardingViewModel.kt @@ -0,0 +1,32 @@ +package co.kr.sopt_seminar_30th.presentation.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import co.kr.sopt_seminar_30th.domain.repository.local.AuthorizationRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import timber.log.Timber +import javax.inject.Inject + +@HiltViewModel +class OnBoardingViewModel @Inject constructor( + private val authorizationRepository: AuthorizationRepository +): ViewModel() { + private val _autoLoginState = MutableStateFlow(false) + val autoLoginState = _autoLoginState.asStateFlow() + + fun checkAuthorization(userId: String) { + viewModelScope.launch { + runCatching { + authorizationRepository.getAuthorization(userId) + }.onSuccess { + _autoLoginState.emit(true) + }.onFailure { + _autoLoginState.emit(false) + Timber.e(it) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/SignInViewModel.kt b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/SignInViewModel.kt index f2a03b6..6684f1f 100644 --- a/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/SignInViewModel.kt +++ b/app/src/main/java/co/kr/sopt_seminar_30th/presentation/viewmodel/SignInViewModel.kt @@ -5,12 +5,15 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import co.kr.sopt_seminar_30th.domain.repository.local.AuthorizationRepository import co.kr.sopt_seminar_30th.domain.repository.remote.SignInRepository import co.kr.sopt_seminar_30th.domain.usecase.user.GetAutoLoginUseCase import co.kr.sopt_seminar_30th.domain.usecase.user.GetUserIdUseCase import co.kr.sopt_seminar_30th.domain.usecase.user.LoginUseCase import co.kr.sopt_seminar_30th.util.SingleLiveEvent import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import retrofit2.HttpException import timber.log.Timber @@ -22,25 +25,21 @@ class SignInViewModel @Inject constructor( private val getUserIdUseCase: GetUserIdUseCase, private val loginUseCase: LoginUseCase, private val getAutoLoginUseCase: GetAutoLoginUseCase, - private val signInRepository: SignInRepository + private val signInRepository: SignInRepository, + private val authorizationRepository: AuthorizationRepository ) : ViewModel() { var userId = MutableLiveData() var userPassword = MutableLiveData() - - private var _autoLogin = MutableLiveData(false) - val autoLogin: LiveData get() = _autoLogin - private var _isSuccess = SingleLiveEvent() val isSuccess: LiveData get() = _isSuccess - private var _isEmpty = SingleLiveEvent() val isEmpty: LiveData get() = _isEmpty - private var _isEmailIncorrect = SingleLiveEvent() val isEmailIncorrect: LiveData get() = _isEmailIncorrect - private var _isPasswordIncorrect = SingleLiveEvent() val isPasswordIncorrect: LiveData get() = _isPasswordIncorrect + private val _autoLoginState = MutableStateFlow(false) + val autoLoginState = _autoLoginState.asStateFlow() fun login() { if (!userId.value.isNullOrBlank() && !userPassword.value.isNullOrBlank()) { @@ -53,6 +52,9 @@ class SignInViewModel @Inject constructor( .onSuccess { _isSuccess.value = true loginUseCase(email, password) + runCatching { + authorizationRepository.insertAuthorization(email, true) + }.onFailure { Timber.e(it) } } .onFailure { exception -> when ((exception as HttpException).code()) { @@ -67,4 +69,17 @@ class SignInViewModel @Inject constructor( _isEmpty.value = true } } + + fun checkAuthorization(userId: String) { + viewModelScope.launch { + runCatching { + authorizationRepository.getAuthorization(userId) + }.onSuccess { + _autoLoginState.emit(true) + }.onFailure { + _autoLoginState.emit(false) + Timber.e(it) + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_on_boarding.xml b/app/src/main/res/layout/activity_on_boarding.xml new file mode 100644 index 0000000..d282c90 --- /dev/null +++ b/app/src/main/res/layout/activity_on_boarding.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_on_boarding_first.xml b/app/src/main/res/layout/fragment_on_boarding_first.xml new file mode 100644 index 0000000..2c175fa --- /dev/null +++ b/app/src/main/res/layout/fragment_on_boarding_first.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + +