로그인 UI

- 입력창 크기 및 UI 수정
This commit is contained in:
klaus 2025-03-21 02:11:45 +09:00
parent 7c39d6c53a
commit 9331ba1276
3 changed files with 121 additions and 135 deletions

View File

@ -1,9 +1,16 @@
package kr.co.vividnext.sodalive.user.login package kr.co.vividnext.sodalive.user.login
import android.content.Intent import android.content.Intent
import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.text.InputType import android.transition.TransitionManager
import android.view.inputmethod.EditorInfo
import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.annotation.OptIn
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.media3.common.util.UnstableApi
import com.jakewharton.rxbinding4.widget.textChanges import com.jakewharton.rxbinding4.widget.textChanges
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.schedulers.Schedulers import io.reactivex.rxjava3.schedulers.Schedulers
@ -11,11 +18,13 @@ import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.ActivityLoginBinding import kr.co.vividnext.sodalive.databinding.ActivityLoginBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.main.MainActivity import kr.co.vividnext.sodalive.main.MainActivity
import kr.co.vividnext.sodalive.user.find_password.FindPasswordActivity import kr.co.vividnext.sodalive.user.find_password.FindPasswordActivity
import kr.co.vividnext.sodalive.user.signup.SignUpActivity import kr.co.vividnext.sodalive.user.signup.SignUpActivity
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@OptIn(UnstableApi::class)
class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::inflate) { class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::inflate) {
private val viewModel: LoginViewModel by inject() private val viewModel: LoginViewModel by inject()
@ -24,33 +33,37 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
bindData() bindData()
} }
override fun setupView() { override fun setupView() {
binding.root.viewTreeObserver.addOnGlobalLayoutListener {
val rect = Rect()
binding.root.getWindowVisibleDisplayFrame(rect)
val keypadHeight = screenHeight - rect.bottom
if (keypadHeight > screenHeight * 0.15) {
updateMarginWithAnimation(
binding.llLoginContainer,
-100f.dpToPx().toInt()
)
} else {
updateMarginWithAnimation(binding.llLoginContainer, 0)
}
}
binding.tvToolbar.text = "로그인" binding.tvToolbar.text = "로그인"
loadingDialog = LoadingDialog(this, layoutInflater) loadingDialog = LoadingDialog(this, layoutInflater)
binding.tvLogin.setOnClickListener { binding.etPassword.setOnEditorActionListener { _, actionId, _ ->
viewModel.login { if (actionId == EditorInfo.IME_ACTION_DONE) {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() } login()
finishAffinity() true
val nextIntent = Intent(applicationContext, MainActivity::class.java)
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
?: if (intent.extras != null) {
intent.extras
} else { } else {
null false
}
if (extras != null) {
nextIntent.putExtra(Constants.EXTRA_DATA, extras)
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(nextIntent)
} }
} }
binding.tvLogin.setOnClickListener { login() }
binding.tvSignUp.setOnClickListener { binding.tvSignUp.setOnClickListener {
val nextIntent = Intent(applicationContext, SignUpActivity::class.java) val nextIntent = Intent(applicationContext, SignUpActivity::class.java)
@ -74,8 +87,26 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
) )
) )
} }
}
binding.tvVisiblePassword.setOnClickListener { viewModel.onClickVisiblePassword() } private fun login() {
viewModel.login {
it?.let { Toast.makeText(applicationContext, it, Toast.LENGTH_LONG).show() }
finishAffinity()
val nextIntent = Intent(applicationContext, MainActivity::class.java)
val extras = intent.getBundleExtra(Constants.EXTRA_DATA)
?: if (intent.extras != null) {
intent.extras
} else {
null
}
if (extras != null) {
nextIntent.putExtra(Constants.EXTRA_DATA, extras)
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(nextIntent)
}
} }
private fun bindData() { private fun bindData() {
@ -108,16 +139,24 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>(ActivityLoginBinding::i
loadingDialog.dismiss() loadingDialog.dismiss()
} }
} }
}
viewModel.visiblePasswordLiveData.observe(this) { private fun updateMarginWithAnimation(view: LinearLayout, newMargin: Int) {
binding.tvVisiblePassword.isSelected = it val constraintLayout = view.parent as ConstraintLayout
if (it) { val constraintSet = ConstraintSet()
binding.etPassword.inputType = constraintSet.clone(constraintLayout)
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
} else { // 변경할 Constraint 적용 (margin 변경)
binding.etPassword.inputType = constraintSet.connect(
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD view.id,
} ConstraintSet.TOP,
} ConstraintSet.PARENT_ID,
ConstraintSet.TOP,
newMargin
)
// 애니메이션 적용
TransitionManager.beginDelayedTransition(constraintLayout)
constraintSet.applyTo(constraintLayout)
} }
} }

View File

@ -14,10 +14,6 @@ class LoginViewModel(private val repository: UserRepository) : BaseViewModel() {
var email = "" var email = ""
var password = "" var password = ""
private val _visiblePasswordLiveData = MutableLiveData(false)
val visiblePasswordLiveData: LiveData<Boolean>
get() = _visiblePasswordLiveData
private val _toastLiveData = MutableLiveData<String?>() private val _toastLiveData = MutableLiveData<String?>()
val toastLiveData: LiveData<String?> val toastLiveData: LiveData<String?>
get() = _toastLiveData get() = _toastLiveData
@ -71,8 +67,4 @@ class LoginViewModel(private val repository: UserRepository) : BaseViewModel() {
) )
) )
} }
fun onClickVisiblePassword() {
_visiblePasswordLiveData.postValue(!_visiblePasswordLiveData.value!!)
}
} }

View File

@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="@color/black"> android:background="@color/black">
<TextView <TextView
@ -22,99 +23,68 @@
tools:text="바로, 상담 가능한 크리에이터" /> tools:text="바로, 상담 가능한 크리에이터" />
<LinearLayout <LinearLayout
android:id="@+id/ll_login_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<LinearLayout <com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="26.7dp" android:layout_marginHorizontal="13.3dp"
android:orientation="vertical"> android:hint="이메일"
app:boxBackgroundColor="@color/color_cc333333"
app:boxBackgroundMode="filled"
app:boxCornerRadiusBottomEnd="6.7dp"
app:boxCornerRadiusBottomStart="6.7dp"
app:boxCornerRadiusTopEnd="6.7dp"
app:boxCornerRadiusTopStart="6.7dp"
app:boxStrokeColor="@color/color_cc333333">
<TextView <com.google.android.material.textfield.TextInputEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="이메일"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<EditText
android:id="@+id/et_email" android:id="@+id/et_email"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/edittext_underline"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:hint="이메일 주소를 입력하세요"
android:importantForAutofill="no" android:importantForAutofill="no"
android:inputType="textWebEmailAddress" android:inputType="textEmailAddress"
android:paddingHorizontal="6.7dp" android:paddingVertical="16dp"
android:paddingTop="12dp"
android:paddingBottom="8dp"
android:textColor="@color/color_eeeeee" android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777" android:textSize="15sp" />
android:textCursorDrawable="@drawable/edit_text_cursor" </com.google.android.material.textfield.TextInputLayout>
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
</LinearLayout> <com.google.android.material.textfield.TextInputLayout
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="26.7dp" android:layout_marginHorizontal="13.3dp"
android:layout_marginTop="33.3dp" android:layout_marginTop="16dp"
android:orientation="vertical"> android:hint="비밀번호"
app:boxBackgroundColor="@color/color_cc333333"
app:boxBackgroundMode="filled"
app:boxCornerRadiusBottomEnd="6.7dp"
app:boxCornerRadiusBottomStart="6.7dp"
app:boxCornerRadiusTopEnd="6.7dp"
app:boxCornerRadiusTopStart="6.7dp"
app:boxStrokeColor="@color/color_cc333333"
app:endIconMode="password_toggle">
<TextView <com.google.android.material.textfield.TextInputEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="6.7dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="비밀번호"
android:textColor="@color/color_eeeeee"
android:textSize="12sp" />
<EditText
android:id="@+id/et_password" android:id="@+id/et_password"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/edittext_underline"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:hint="비밀번호를 입력하세요" android:imeOptions="actionDone"
android:importantForAutofill="no" android:inputType="textPassword"
android:inputType="textWebPassword" android:paddingVertical="16dp"
android:paddingHorizontal="6.7dp"
android:paddingTop="12dp"
android:paddingBottom="8dp"
android:textColor="@color/color_eeeeee" android:textColor="@color/color_eeeeee"
android:textColorHint="@color/color_777777" android:textSize="15sp" />
android:textCursorDrawable="@drawable/edit_text_cursor" </com.google.android.material.textfield.TextInputLayout>
android:textSize="13.3sp"
android:theme="@style/EditTextStyle"
tools:ignore="LabelFor" />
<TextView
android:id="@+id/tv_visible_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:drawablePadding="13.3dp"
android:fontFamily="@font/gmarket_sans_medium"
android:gravity="center_vertical"
android:text="비밀번호 표시"
android:textColor="@color/color_eeeeee"
android:textSize="13.3sp"
app:drawableStartCompat="@drawable/ic_select" />
</LinearLayout>
<TextView <TextView
android:id="@+id/tv_login" android:id="@+id/tv_login"
@ -130,28 +100,13 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="15sp" /> android:textSize="15sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="40dp"
android:orientation="horizontal">
<TextView <TextView
android:id="@+id/tv_forgot_password" android:id="@+id/tv_forgot_password"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:text="비밀번호 재설정" android:text="비밀번호를 잊으셨나요?"
android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4dp"
android:fontFamily="@font/gmarket_sans_medium"
android:text="|"
android:textColor="@color/color_bbbbbb" android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" /> android:textSize="13.3sp" />
@ -159,10 +114,10 @@
android:id="@+id/tv_sign_up" android:id="@+id/tv_sign_up"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:fontFamily="@font/gmarket_sans_medium" android:fontFamily="@font/gmarket_sans_medium"
android:text="회원가입" android:text="보이스온 회원이 아닌가요? 지금 가입하세요."
android:textColor="@color/color_bbbbbb" android:textColor="@color/color_bbbbbb"
android:textSize="13.3sp" /> android:textSize="13.3sp" />
</LinearLayout> </LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>