Skip to content

Commit

Permalink
[feat] #1 login activity
Browse files Browse the repository at this point in the history
  • Loading branch information
Sangwook123 committed Apr 10, 2024
1 parent 2475960 commit 610cee8
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
87 changes: 87 additions & 0 deletions feature/main/src/main/java/org/sopt/main/login/LoginActivity.kt
Original file line number Diff line number Diff line change
@@ -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<Intent>
private val viewModel by viewModels<LoginViewModel>()
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 }
}
}
}
}
19 changes: 19 additions & 0 deletions feature/main/src/main/java/org/sopt/main/login/LoginContract.kt
Original file line number Diff line number Diff line change
@@ -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
}
55 changes: 55 additions & 0 deletions feature/main/src/main/java/org/sopt/main/login/LoginViewModel.kt
Original file line number Diff line number Diff line change
@@ -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<LoginState, LoginSideEffect>, ViewModel() {
override val container: Container<LoginState, LoginSideEffect> = 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()
)
}
}
}
86 changes: 86 additions & 0 deletions feature/main/src/main/res/layout/activity_login.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".login.LoginActivity">

<TextView
android:id="@+id/tv_login_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/login_title"
android:textSize="30sp"
android:layout_marginTop="30dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<TextView
android:id="@+id/tv_login_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/login_id"
android:textSize="20sp"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
app:layout_constraintTop_toBottomOf="@id/tv_login_title"
app:layout_constraintStart_toStartOf="parent"/>

<EditText
android:id="@+id/et_login_id"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_login_id" />

<TextView
android:id="@+id/tv_login_pw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/login_pw"
android:textSize="20sp"
android:layout_marginStart="20dp"
android:layout_marginTop="40dp"
app:layout_constraintTop_toBottomOf="@id/et_login_id"
app:layout_constraintStart_toStartOf="parent"/>

<EditText
android:id="@+id/et_login_pw"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:inputType="textPassword"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_login_pw" />

<Button
android:id="@+id/btn_login_login"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/login_login"
android:gravity="center"
android:layout_marginBottom="20dp"
android:layout_marginHorizontal="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/btn_login_signup" />

<Button
android:id="@+id/btn_login_signup"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="@string/login_signup"
android:gravity="center"
android:layout_marginBottom="40dp"
android:layout_marginHorizontal="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
3 changes: 3 additions & 0 deletions feature/main/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<resources>

</resources>

0 comments on commit 610cee8

Please sign in to comment.