Skip to content

Commit

Permalink
Merge branch 'develop' into feature/mod-mypage-toucharea
Browse files Browse the repository at this point in the history
  • Loading branch information
Sangwook123 committed Aug 27, 2023
2 parents 21879b9 + ce22f08 commit 14eb27a
Show file tree
Hide file tree
Showing 20 changed files with 241 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,86 +5,86 @@ import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import androidx.activity.viewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.android.go.sopt.winey.R
import com.android.go.sopt.winey.databinding.ActivityNicknameBinding
import com.android.go.sopt.winey.domain.repository.DataStoreRepository
import com.android.go.sopt.winey.presentation.main.MainActivity
import com.android.go.sopt.winey.util.binding.BindingActivity
import com.android.go.sopt.winey.util.code.ErrorCode
import com.android.go.sopt.winey.util.context.hideKeyboard
import com.android.go.sopt.winey.util.context.snackBar
import com.android.go.sopt.winey.util.context.stringOf
import com.android.go.sopt.winey.util.view.InputUiState
import com.android.go.sopt.winey.util.view.UiState
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class NicknameActivity : BindingActivity<ActivityNicknameBinding>(R.layout.activity_nickname) {
private val viewModel by viewModels<NicknameViewModel>()
private val prevScreenName by lazy { intent.extras?.getString(EXTRA_KEY, "") }

@Inject
lateinit var dataStoreRepository: DataStoreRepository

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.vm = viewModel
viewModel.updatePrevScreenName(prevScreenName)

switchCloseButtonVisibility()
initRootLayoutClickListener()
initCloseButtonClickListener()
switchTitleText()
switchEditTextHint()

initRootLayoutClickListener()
initEditTextWatcher()
initDuplicateCheckButtonClickListener()
initCompleteButtonClickListener()
initPatchNicknameStateObserver()
}

private fun switchCloseButtonVisibility() {
when (prevScreenName) {
STORY_SCREEN -> binding.ivNicknameClose.visibility = View.GONE
MY_PAGE_SCREEN -> binding.ivNicknameClose.visibility = View.VISIBLE
}
}

private fun initCloseButtonClickListener() {
binding.ivNicknameClose.setOnClickListener {
finish()
}
}

private fun switchTitleText() {
when (prevScreenName) {
STORY_SCREEN ->
binding.tvNicknameTitle.text =
stringOf(R.string.nickname_default_title)

MY_PAGE_SCREEN ->
binding.tvNicknameTitle.text =
stringOf(R.string.nickname_mypage_title)
}
}

private fun initEditTextWatcher() {
var prevText = ""
binding.etNickname.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun afterTextChanged(s: Editable?) {}

// 텍스트가 바뀌면 중복체크 상태 false로 초기화
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val inputText = s.toString()
viewModel.updateTextChangedState(inputText.isNotBlank() && inputText != prevText)
if (inputText.isNotBlank() && inputText != prevText) {
viewModel.updateDuplicateCheckState(false)
}
prevText = inputText
}
})
}

private fun initDuplicateCheckButtonClickListener() {
binding.btnNicknameDuplicateCheck.setOnClickListener {
if (viewModel.isTextChanged.value) {
viewModel.apply {
updateDuplicateCheckButtonState(true)
getNicknameDuplicateCheck()
}
viewModel.getNicknameDuplicateCheck()
}
}

private fun initCompleteButtonClickListener() {
binding.btnNicknameComplete.setOnClickListener {
// 중복체크를 하지 않은 상태에서 완료 버튼을 클릭하면 에러 표시
if (!viewModel.isDuplicateChecked.value) {
viewModel.updateInputUiState(
InputUiState.Failure(ErrorCode.CODE_UNCHECKED_DUPLICATION)
)
return@setOnClickListener
}

// 서버통신 결과 중복되지 않은 닉네임인 경우에만 PATCH 서버통신 진행
if (viewModel.isValidNickname.value) {
viewModel.patchNickname()
}
}
}
Expand All @@ -111,6 +111,24 @@ class NicknameActivity : BindingActivity<ActivityNicknameBinding>(R.layout.activ
binding.btnNicknameComplete.isClickable = false
}

private fun switchEditTextHint() {
lifecycleScope.launch {
when (prevScreenName) {
STORY_SCREEN -> binding.etNickname.hint = stringOf(R.string.nickname_default_hint)
MY_PAGE_SCREEN -> {
val user = dataStoreRepository.getUserInfo().first() ?: return@launch
binding.etNickname.hint = user.nickname
}
}
}
}

private fun initCloseButtonClickListener() {
binding.ivNicknameClose.setOnClickListener {
finish()
}
}

private fun initRootLayoutClickListener() {
binding.root.setOnClickListener {
hideKeyboard(binding.root)
Expand All @@ -127,7 +145,7 @@ class NicknameActivity : BindingActivity<ActivityNicknameBinding>(R.layout.activ

companion object {
private const val EXTRA_KEY = "PREV_SCREEN_NAME"
private const val MY_PAGE_SCREEN = "MyPageFragment"
private const val STORY_SCREEN = "StoryActivity"
const val MY_PAGE_SCREEN = "MyPageFragment"
const val STORY_SCREEN = "StoryActivity"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import com.android.go.sopt.winey.domain.repository.AuthRepository
import com.android.go.sopt.winey.util.code.ErrorCode.CODE_DUPLICATE
import com.android.go.sopt.winey.util.code.ErrorCode.CODE_INVALID_LENGTH
import com.android.go.sopt.winey.util.code.ErrorCode.CODE_SPACE_SPECIAL_CHAR
import com.android.go.sopt.winey.util.code.ErrorCode.CODE_UNCHECKED_DUPLICATION
import com.android.go.sopt.winey.util.view.InputUiState
import com.android.go.sopt.winey.util.view.UiState
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -32,12 +31,11 @@ class NicknameViewModel @Inject constructor(
val nickname: String get() = _nickname.value

private val _inputUiState: MutableStateFlow<InputUiState> =
_nickname.map { updateInputUiState(it) }
_nickname.map { checkInputUiState(it) }
.mutableStateIn(
initialValue = InputUiState.Empty,
scope = viewModelScope
)

val inputUiState: StateFlow<InputUiState> = _inputUiState.asStateFlow()

val isValidNickname: StateFlow<Boolean> = _inputUiState.map { validateNickname(it) }
Expand All @@ -46,19 +44,29 @@ class NicknameViewModel @Inject constructor(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(PRODUCE_STOP_TIMEOUT)
)
private fun validateNickname(state: InputUiState) = state == InputUiState.Success

private val _isTextChanged = MutableStateFlow(false)
val isTextChanged: StateFlow<Boolean> = _isTextChanged.asStateFlow()
private val _isDuplicateChecked = MutableStateFlow(false)
val isDuplicateChecked: StateFlow<Boolean> = _isDuplicateChecked.asStateFlow()

private val _isCheckBtnClicked = MutableStateFlow(false)
val isCheckBtnClicked: StateFlow<Boolean> = _isCheckBtnClicked.asStateFlow()
private val _patchNicknameState = MutableStateFlow<UiState<Unit>>(UiState.Empty)
val patchNicknameState: StateFlow<UiState<Unit>> = _patchNicknameState.asStateFlow()

private var prevCheckResult: Pair<String, Boolean>? = null

private val _patchNicknameState = MutableStateFlow<UiState<Unit>>(UiState.Empty)
val patchNicknameState: StateFlow<UiState<Unit>> = _patchNicknameState.asStateFlow()
var prevScreenName: String? = null

private fun validateNickname(state: InputUiState) = state == InputUiState.Success
fun updatePrevScreenName(name: String?) {
prevScreenName = name
}

fun updateInputUiState(inputUiState: InputUiState) {
_inputUiState.value = inputUiState
}

fun updateDuplicateCheckState(checked: Boolean) {
_isDuplicateChecked.value = checked
}

fun patchNickname() {
viewModelScope.launch {
Expand Down Expand Up @@ -87,89 +95,43 @@ class NicknameViewModel @Inject constructor(
if (response == null) return@onSuccess

response.isDuplicated.let {
Timber.d("SUCCESS GET DUPLICATION CHECK: $it")
updateDuplicateCheckState(it)
saveDuplicateCheckState(it)
showDuplicateCheckResult(it)
saveDuplicateCheckResult(it)
}
updateDuplicateCheckState(true)
}
.onFailure { t ->
Timber.e("${t.message}")
}
}
}

private fun updateDuplicateCheckState(isDuplicated: Boolean) {
private fun showDuplicateCheckResult(isDuplicated: Boolean) {
_inputUiState.value = if (isDuplicated) {
InputUiState.Failure(CODE_DUPLICATE)
} else {
InputUiState.Success
}
}

// 서버통신 할 때마다 현재 닉네임과 중복여부를 저장한다.
private fun saveDuplicateCheckState(isDuplicated: Boolean) {
private fun saveDuplicateCheckResult(isDuplicated: Boolean) {
prevCheckResult = Pair(nickname, isDuplicated)
}

private fun updateInputUiState(nickname: String): InputUiState {
private fun checkInputUiState(nickname: String): InputUiState {
if (nickname.isEmpty()) return InputUiState.Empty
if (!checkLength(nickname)) return InputUiState.Failure(CODE_INVALID_LENGTH)
if (containsSpaceOrSpecialChar(nickname)) {
return InputUiState.Failure(
CODE_SPACE_SPECIAL_CHAR
)
}

// 텍스트가 바뀌었는데 중복체크 버튼을 누르지 않은 경우
if (isTextChanged.value && !isCheckBtnClicked.value) {
return comparePrevCheckResult()
return InputUiState.Failure(CODE_SPACE_SPECIAL_CHAR)
}

return InputUiState.Empty
}

private fun comparePrevCheckResult(): InputUiState {
// 이전에 서버통신 한 결과가 없는 경우
if (prevCheckResult == null) {
Timber.d("CASE 1")
return InputUiState.Failure(CODE_UNCHECKED_DUPLICATION)
}

// 현재 입력값이 이전에 서버통신 했던 닉네임과 일치하는 경우
if (nickname == prevCheckResult?.first) {
// 그때 당시의 서버통신 결과 그대로 반환
if (prevCheckResult?.second == true) {
Timber.d("CASE 2")
return InputUiState.Failure(CODE_DUPLICATE)
}

Timber.d("CASE 3")
return InputUiState.Success
}

// 이전에 서버통신한 결과가 있지만, 입력값이 다른 경우
Timber.d("CASE 4")
return InputUiState.Failure(CODE_UNCHECKED_DUPLICATION)
}

private fun checkLength(nickname: String) = nickname.length in MIN_LENGTH..MAX_LENGTH

private fun containsSpaceOrSpecialChar(nickname: String) =
!Regex(REGEX_PATTERN).matches(nickname)

fun updateTextChangedState(state: Boolean) { // updated in Activity
_isTextChanged.value = state
}

fun updateDuplicateCheckButtonState(state: Boolean) { // updated in Activity
_isCheckBtnClicked.value = state
initDuplicateCheckButtonState()
}

private fun initDuplicateCheckButtonState() {
_isCheckBtnClicked.value = false
}

// _nickname.map{} Flow -> MutableStateFlow 변환을 위한 확장 함수
private fun <T> Flow<T>.mutableStateIn(
initialValue: T,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class GuideActivity : BindingActivity<ActivityGuideBinding>(R.layout.activity_gu
super.onCreate(savedInstanceState)

initViewPagerAdapter()
preventDefaultSwipe()
observePageChange()
initNextButtonClickListener()
}
Expand All @@ -25,10 +24,6 @@ class GuideActivity : BindingActivity<ActivityGuideBinding>(R.layout.activity_gu
binding.vpGuide.adapter = GuideFragmentStateAdapter(this)
}

private fun preventDefaultSwipe() {
binding.vpGuide.isUserInputEnabled = false
}

private fun observePageChange() {
binding.vpGuide.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ class FirstStoryFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

bringSpeechBubbleToFront()
bringTextToFront()
}

private fun bringSpeechBubbleToFront() {
binding.tvStoryWineyCountrySpeechBubble.bringToFront()
private fun bringTextToFront() {
with(binding) {
tvStorySaverSpeechBubble.bringToFront()
tvStoryWineyCountryName.bringToFront()
tvStoryWineyCountrySpeechBubble.bringToFront()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ class SecondStoryFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

bringSpeechBubbleToFront()
bringTextToFront()
}

private fun bringSpeechBubbleToFront() {
binding.tvStoryWineyCountrySpeechBubble.bringToFront()
private fun bringTextToFront() {
with(binding) {
tvStorySaverSpeechBubble.bringToFront()
tvStoryWineyCountryName.bringToFront()
tvStoryWineyCountrySpeechBubble.bringToFront()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ class StoryActivity : BindingActivity<ActivityStoryBinding>(R.layout.activity_st
setUpDefaultNavigationText()
setUpDefaultFragment(savedInstanceState)
initNextButtonClickListener()
initSkipButtonClickListener()
}

private fun initSkipButtonClickListener() {
binding.tvStorySkip.setOnClickListener {
navigateToNicknameScreen()
}
}

private fun initNextButtonClickListener() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ class ThirdStoryFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

bringSpeechBubbleToFront()
bringTextToFront()
}

private fun bringSpeechBubbleToFront() {
binding.tvStoryWineyCountrySpeechBubble.bringToFront()
private fun bringTextToFront() {
with(binding) {
tvStorySaverSpeechBubble.bringToFront()
tvStoryWineyCountryName.bringToFront()
tvStoryWineyCountrySpeechBubble.bringToFront()
}
}
}
Loading

0 comments on commit 14eb27a

Please sign in to comment.