diff --git a/feature/main/src/main/java/org/sopt/main/login/LoginActivity.kt b/feature/main/src/main/java/org/sopt/main/login/LoginActivity.kt new file mode 100644 index 0000000..f6fc9aa --- /dev/null +++ b/feature/main/src/main/java/org/sopt/main/login/LoginActivity.kt @@ -0,0 +1,87 @@ +package org.sopt.main.login + +import android.content.Intent +import android.os.Bundle +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.appcompat.app.AppCompatActivity +import dagger.hilt.android.AndroidEntryPoint +import org.orbitmvi.orbit.viewmodel.observe +import org.sopt.designsystem.R +import org.sopt.main.const.IntentKey.USER_KEY +import org.sopt.main.databinding.ActivityLoginBinding +import org.sopt.main.main.MainActivity +import org.sopt.main.model.User +import org.sopt.main.signup.SignupActivity +import org.sopt.ui.context.snackBar +import org.sopt.ui.context.stringOf +import org.sopt.ui.intent.getParcelable + +@AndroidEntryPoint +class LoginActivity : AppCompatActivity() { + private lateinit var binding: ActivityLoginBinding + private lateinit var resultLauncher: ActivityResultLauncher + private val viewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + binding = ActivityLoginBinding.inflate(layoutInflater) + setContentView(binding.root) + + initResultLauncher() + initSignupButtonClickListener() + initLoginButtonClickListener() + collectState() + } + + private fun initResultLauncher() { + resultLauncher = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { result -> + if (result.resultCode == RESULT_OK) { + result.data?.getParcelable(USER_KEY, User::class.java).let { user -> + viewModel.signupSuccess(user) + } + } + } + } + + private fun initSignupButtonClickListener() { + binding.btnLoginSignup.setOnClickListener { + viewModel.signup() + } + } + + private fun initLoginButtonClickListener() { + binding.btnLoginLogin.setOnClickListener { + viewModel.login(binding.etLoginId.text.toString(), binding.etLoginPw.text.toString()) + } + } + + private fun collectState() { + viewModel.observe(lifecycleOwner = this, sideEffect = ::handleSideEffect) + } + + private fun handleSideEffect(sideEffect: LoginSideEffect) { + when (sideEffect) { + is LoginSideEffect.NavigateToSignUp -> { + Intent(this, SignupActivity::class.java).apply { + resultLauncher.launch(this) + } + } + + is LoginSideEffect.LoginSuccess -> { + Intent(this, MainActivity::class.java).apply { + putExtra(USER_KEY, sideEffect.user) + startActivity(this) + } + } + LoginSideEffect.SignupSuccess -> { + snackBar(binding.root) { stringOf(R.string.login_signup_success) } + } + is LoginSideEffect.showSnackbar -> { + snackBar(binding.root) { sideEffect.message } + } + } + } +} \ No newline at end of file diff --git a/feature/main/src/main/java/org/sopt/main/login/LoginContract.kt b/feature/main/src/main/java/org/sopt/main/login/LoginContract.kt new file mode 100644 index 0000000..22d09f2 --- /dev/null +++ b/feature/main/src/main/java/org/sopt/main/login/LoginContract.kt @@ -0,0 +1,19 @@ +package org.sopt.main.login + +import org.sopt.main.model.User + +data class LoginState( + val id: String = "", + val password: String = "", + val registeredId: String = "", + val registeredPassword: String = "", + val name: String = "", + val hobby: String = "" +) + +sealed interface LoginSideEffect { + data class showSnackbar(val message: String) : LoginSideEffect + data class LoginSuccess(val user: User) : LoginSideEffect + data object NavigateToSignUp : LoginSideEffect + data object SignupSuccess : LoginSideEffect +} \ No newline at end of file diff --git a/feature/main/src/main/java/org/sopt/main/login/LoginViewModel.kt b/feature/main/src/main/java/org/sopt/main/login/LoginViewModel.kt new file mode 100644 index 0000000..d4432e5 --- /dev/null +++ b/feature/main/src/main/java/org/sopt/main/login/LoginViewModel.kt @@ -0,0 +1,55 @@ +package org.sopt.main.login + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import org.orbitmvi.orbit.Container +import org.orbitmvi.orbit.ContainerHost +import org.orbitmvi.orbit.syntax.simple.intent +import org.orbitmvi.orbit.syntax.simple.postSideEffect +import org.orbitmvi.orbit.syntax.simple.reduce +import org.orbitmvi.orbit.viewmodel.container +import org.sopt.designsystem.R +import org.sopt.main.model.User +import org.sopt.ui.context.ResourceProvider +import javax.inject.Inject + +@HiltViewModel +class LoginViewModel @Inject constructor( + private val resourceProvider: ResourceProvider +) : ContainerHost, ViewModel() { + override val container: Container = container(LoginState()) + + fun signup() = intent { + postSideEffect(LoginSideEffect.NavigateToSignUp) + } + + fun login(id: String, password: String) = intent { + with(state) { + when { + checkRegister() -> postSideEffect(LoginSideEffect.showSnackbar(getString(R.string.login_not_registered))) + matchesUserInfo(id, password) -> postSideEffect(LoginSideEffect.LoginSuccess(createUser())) + else -> postSideEffect(LoginSideEffect.showSnackbar(getString(R.string.login_login_fail))) + } + } + } + private fun LoginState.checkRegister() = registeredId.isBlank() || registeredPassword.isBlank() + + private fun LoginState.matchesUserInfo(id: String, password: String) = registeredId == id && registeredPassword == password + + private fun LoginState.createUser() = User(registeredId, registeredPassword, name, hobby) + + private fun getString(resId: Int) = resourceProvider.getString(resId) + + fun signupSuccess(user: User?) = intent { + postSideEffect(LoginSideEffect.SignupSuccess) + + reduce { + state.copy( + registeredId = user?.id.orEmpty(), + registeredPassword = user?.pw.orEmpty(), + name = user?.name.orEmpty(), + hobby = user?.hobby.orEmpty() + ) + } + } +} \ No newline at end of file diff --git a/feature/main/src/main/res/layout/activity_login.xml b/feature/main/src/main/res/layout/activity_login.xml new file mode 100644 index 0000000..bbe2d38 --- /dev/null +++ b/feature/main/src/main/res/layout/activity_login.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + +