Skip to content

Commit

Permalink
Merge pull request #14 from Team-Going/ui/#13-onboarding-profile-setting
Browse files Browse the repository at this point in the history
[UI/#13] onboarding profile setting
  • Loading branch information
chattymin authored Jan 1, 2024
2 parents 82df2cc + 32fc59f commit f4ad7ab
Show file tree
Hide file tree
Showing 12 changed files with 399 additions and 4 deletions.
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
</intent-filter>
</activity>

<activity
android:name="com.going.presentation.onboarding.OnboardingProfileSettingActivity"
android:exported="true" />

</application>

</manifest>
3 changes: 2 additions & 1 deletion core-ui/src/main/java/com/going/ui/extension/ContextExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ fun Context.drawableOf(@DrawableRes resId: Int) = ContextCompat.getDrawable(this
fun Context.hideKeyboard(view: View) {
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
view.clearFocus()
}
5 changes: 5 additions & 0 deletions domain/src/main/kotlin/com/going/domain/entity/NameState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.going.domain.entity

enum class NameState {
Empty, Success, Blank
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.going.presentation.onboarding

import android.os.Bundle
import android.view.inputmethod.EditorInfo
import androidx.activity.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.going.domain.entity.NameState
import com.going.presentation.R
import com.going.presentation.databinding.ActivityOnboardingProfileSettingBinding
import com.going.ui.base.BaseActivity
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach

class OnboardingProfileSettingActivity :
BaseActivity<ActivityOnboardingProfileSettingBinding>(R.layout.activity_onboarding_profile_setting) {
private val viewModel by viewModels<OnboardingProfileSettingViewModel>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initBindingViewModel()
initOnLineInfoEditorActionListener()
initSetOnFucusChangeListener()
observeIsProfileAvailable()
observeTextLength()
observeIsNameAvailable()
}

private fun initBindingViewModel() {
binding.viewModel = viewModel
}

private fun initOnLineInfoEditorActionListener() {
binding.etOnboardingProfileSettingInfo.setOnEditorActionListener { view, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) view.clearFocus()
false
}
}

private fun initSetOnFucusChangeListener() {
binding.etOnboardingProfileSettingName.setOnFocusChangeListener { _, hasFocus ->
judgeCounterColorWithFocus(hasFocus)
}

binding.etOnboardingProfileSettingInfo.setOnFocusChangeListener { _, hasFocus ->
judgeCounterColorWithFocus(hasFocus)
}
}

private fun judgeCounterColorWithFocus(hasFocus: Boolean) {
if (hasFocus) {
setNameCounterColor(R.color.gray_700)
} else {
setNameCounterColor(R.color.gray_200)
}
if (viewModel.isNameAvailable.value == NameState.Blank) {
setNameCounterColor(R.color.red_400)
}
}

private fun setNameCounterColor(color: Int) {
binding.tvNameCounter.setTextColor(getColor(color))
}

private fun observeIsProfileAvailable() {
viewModel.isMoveScreenAvailable.flowWithLifecycle(lifecycle).onEach { isEnd ->
if (isEnd) moveSplash()
}.launchIn(lifecycleScope)
}

// 커스텀 글자수 제한 함수
private fun observeTextLength() {
viewModel.nowNameLength.observe(this) { length ->
val maxNameLength = viewModel.getMaxNameLen()

if (length > maxNameLength) {
binding.etOnboardingProfileSettingName.apply {
setText(text?.subSequence(0, maxNameLength))
setSelection(maxNameLength)
}
}
}

viewModel.nowInfoLength.observe(this) { length ->
val maxInfoLength = viewModel.getMaxInfoLen()

if (length > maxInfoLength) {
binding.etOnboardingProfileSettingInfo.apply {
setText(text?.subSequence(0, maxInfoLength))
setSelection(maxInfoLength)
}
}
}
}

private fun observeIsNameAvailable() {
viewModel.isNameAvailable.observe(this) { state ->
when (state) {
NameState.Blank -> binding.tvNameCounter.setTextColor(getColor(R.color.red_400))
else -> binding.tvNameCounter.setTextColor(getColor(R.color.gray_700))
}
}
}

private fun moveSplash() {
// 스플래시로 이동
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.going.presentation.onboarding

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.going.domain.entity.NameState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import java.text.BreakIterator

class OnboardingProfileSettingViewModel : ViewModel() {
val name = MutableLiveData(String())
val nowNameLength = MutableLiveData(0)
val info = MutableLiveData(String())
val nowInfoLength = MutableLiveData(0)

val isNameAvailable = MutableLiveData(NameState.Empty)
val isProfileAvailable = MutableLiveData(false)

private val _isMoveScreenAvailable = MutableStateFlow(false)
val isMoveScreenAvailable: StateFlow<Boolean> = _isMoveScreenAvailable

fun getMaxNameLen() = MAX_NAME_LEN
fun getMaxInfoLen() = MAX_INFO_LEN

fun checkProfileAvailable() {
nowNameLength.value = getGraphemeLength(name.value)
nowInfoLength.value = getGraphemeLength(info.value)

isNameAvailable.value = when {
nowNameLength.value == 0 -> NameState.Empty
name.value.isNullOrBlank() -> NameState.Blank
else -> NameState.Success
}

val isInfoAvailable = getGraphemeLength(info.value) in 1..MAX_INFO_LEN

isProfileAvailable.value =
(isNameAvailable.value == NameState.Success) && isInfoAvailable
}

// 이모지 포함 글자 수 세는 함수
private fun getGraphemeLength(value: String?): Int {
BREAK_ITERATOR.setText(value)

var count = 0
while (BREAK_ITERATOR.next() != BreakIterator.DONE) {
count++
}

return count
}

fun setIsMoveScreenAvailable() {
_isMoveScreenAvailable.value = true
}

companion object {
val BREAK_ITERATOR: BreakIterator = BreakIterator.getCharacterInstance()

const val MAX_NAME_LEN = 3
const val MAX_INFO_LEN = 20
}
}
19 changes: 19 additions & 0 deletions presentation/src/main/res/drawable/sel_rounded_corner_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false">
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/gray_200" />
</shape>
</item>

<!-- State Enabled -->
<item android:state_enabled="true">
<shape>
<corners android:radius="4dp" />
<solid android:color="@color/gray_500" />
</shape>
</item>

</selector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false">
<shape>
<stroke android:width="2dp"/>
<stroke android:color="@color/gray_200"/>
<corners android:radius="4dp" />
</shape>
</item>
<item android:state_focused="true">
<shape>
<stroke android:width="2dp"/>
<stroke android:color="@color/gray_700"/>
<corners android:radius="4dp" />
</shape>
</item>
</selector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false">
<shape>
<stroke android:width="2dp"/>
<stroke android:color="@color/red_400"/>
<corners android:radius="4dp" />
</shape>
</item>
</selector>
4 changes: 2 additions & 2 deletions presentation/src/main/res/layout/activity_login.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
android:gravity="center"
android:lineHeight="42dp"
android:text="@string/sign_in_tv_title"
android:textColor="@color/white"
android:textColor="@color/white_000"
app:layout_constraintBottom_toTopOf="@id/iv_sign_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
Expand Down Expand Up @@ -58,7 +58,7 @@
android:gravity="center"
android:lineHeight="42dp"
android:text="@string/sign_in_tv_terms"
android:textColor="@color/white"
android:textColor="@color/white_000"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_sign_in" />
Expand Down
Loading

0 comments on commit f4ad7ab

Please sign in to comment.