Skip to content

Commit

Permalink
#29 refactor: 로그인 화면 bottomSheet, checkbox 상태 객체로 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
SeungWoo-Ahn committed May 9, 2024
1 parent 71c30a4 commit 554bd02
Show file tree
Hide file tree
Showing 11 changed files with 102 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.ui.unit.dp
import io.tuttut.data.model.dto.CropsInfo
import io.tuttut.presentation.R
import io.tuttut.presentation.theme.screenHorizontalPadding
import io.tuttut.presentation.ui.screen.login.PolicySheetState
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -291,25 +292,19 @@ fun HarvestBottomSheet(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PolicyBottomSheet(
showSheet: Boolean,
isLoading: Boolean,
policyChecked: Boolean,
personalChecked: Boolean,
onPolicyCheckedChange: (Boolean) -> Unit,
onPersonalCheckedChange: (Boolean) -> Unit,
policySheetState: PolicySheetState,
showPolicy: () -> Unit,
showPersonal: () -> Unit,
onAgreement: () -> Unit,
onDismissRequest: () -> Unit,
) {
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val properties = ModalBottomSheetDefaults.properties(shouldDismissOnBackPress = false)
TutTutBottomSheet(
showSheet = showSheet,
showSheet = policySheetState.showSheet,
sheetState = sheetState,
containerColor = MaterialTheme.colorScheme.background,
properties = properties,
onDismissRequest = onDismissRequest
onDismissRequest = policySheetState::dismiss
) {
Column(
modifier = Modifier
Expand All @@ -323,21 +318,21 @@ fun PolicyBottomSheet(
Spacer(modifier = Modifier.height(20.dp))
PolicyButton(
name = stringResource(id = R.string.service_policy_agreement),
checked = policyChecked,
onCheckedChange = { if (!isLoading) onPolicyCheckedChange(it) },
checked = policySheetState.policyState.checked,
onCheckedChange = { if (!policySheetState.isLoading()) policySheetState.policyState.onCheckedChange(it) },
showPolicy = showPolicy
)
Spacer(modifier = Modifier.height(10.dp))
PolicyButton(
name = stringResource(id = R.string.service_policy_agreement),
checked = personalChecked,
onCheckedChange = { if (!isLoading) onPersonalCheckedChange(it) },
checked = policySheetState.personalState.checked,
onCheckedChange = { if (!policySheetState.isLoading()) policySheetState.personalState.onCheckedChange(it) },
showPolicy = showPersonal
)
Spacer(modifier = Modifier.height(30.dp))
TutTutButton(
text = stringResource(id = R.string.continue_with_agree),
isLoading = isLoading,
isLoading = policySheetState.isLoading(),
onClick = onAgreement
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
Expand All @@ -32,29 +31,21 @@ fun LoginRoute(
onShowSnackBar: suspend (String, String?) -> Boolean,
viewModel: LoginViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState
val policyUiState by viewModel.policyUiState
val context = LocalContext.current
val launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartIntentSenderForResult(),
onResult = { viewModel.handleLoginResult(it, onNext, moveMain, onShowSnackBar) }
)
LoginScreen(
modifier = modifier,
isLoading = uiState == LoginUiState.Loading,
isLoading = viewModel.uiState == LoginUiState.Loading,
onLogin = { viewModel.onLogin(launcher) }
)
PolicyBottomSheet(
showSheet = viewModel.showPolicySheet,
isLoading = policyUiState == PolicyUiState.Loading,
policyChecked = viewModel.policyChecked,
personalChecked = viewModel.personalChecked,
onPolicyCheckedChange = { viewModel.policyChecked = it },
onPersonalCheckedChange = { viewModel.personalChecked = it },
policySheetState = viewModel.policySheetState,
showPolicy = { viewModel.openBrowser(context, SERVICE_POLICY_URL) },
showPersonal = { viewModel.openBrowser(context, PERSONAL_INFO_POLICY_URL) },
onAgreement = { viewModel.join(onShowSnackBar) },
onDismissRequest = { viewModel.showPolicySheet = false }
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package io.tuttut.presentation.ui.screen.login

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import io.tuttut.presentation.ui.state.BottomSheetState
import io.tuttut.presentation.ui.state.CheckBoxState

sealed interface LoginUiState {
data object Loading : LoginUiState
data object Nothing : LoginUiState
Expand All @@ -8,4 +14,28 @@ sealed interface LoginUiState {
sealed interface PolicyUiState {
data object Loading : PolicyUiState
data object Nothing : PolicyUiState
}

class PolicySheetState : BottomSheetState() {
var uiState by mutableStateOf<PolicyUiState>(PolicyUiState.Nothing)
val policyState = CheckBoxState()
val personalState = CheckBoxState()

fun onContinue() {
uiState = PolicyUiState.Loading
policyState.onCheckedChange(true)
personalState.onCheckedChange(true)
}

override fun dismiss() {
super.dismiss()
policyState.onCheckedChange(false)
personalState.onCheckedChange(false)
}

fun toNothing() {
uiState = PolicyUiState.Nothing
}

fun isLoading() = uiState == PolicyUiState.Loading
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import android.os.Build
import androidx.activity.compose.ManagedActivityResultLauncher
import androidx.activity.result.ActivityResult
import androidx.activity.result.IntentSenderRequest
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand All @@ -29,26 +28,12 @@ class LoginViewModel @Inject constructor(
private val prefs: PreferenceUtil,
private val linkUtil: LinkUtil,
) : BaseViewModel() {
private val _uiState = mutableStateOf<LoginUiState>(Nothing)
val uiState: State<LoginUiState> = _uiState

var uiState by mutableStateOf<LoginUiState>(Nothing)
val policySheetState = PolicySheetState()
private val _userData = MutableStateFlow(UserData())

private val _policyUiState = mutableStateOf<PolicyUiState>(PolicyUiState.Nothing)
val policyUiState: State<PolicyUiState> = _policyUiState

var showPolicySheet by mutableStateOf(false)
var policyChecked by mutableStateOf(false)
var personalChecked by mutableStateOf(false)

init {
showPolicySheet = false
policyChecked = false
personalChecked = false
}

fun onLogin(launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>) {
_uiState.value = Loading
uiState = Loading
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.DONUT) return
viewModelScope.launch {
val intentSender = authClient.signIn()
Expand All @@ -66,16 +51,16 @@ class LoginViewModel @Inject constructor(
onShowSnackBar: suspend (String, String?) -> Boolean
) {
if (result.resultCode != RESULT_OK) {
_uiState.value = Nothing
uiState = Nothing
return
}
viewModelScope.launch {
val userData = authClient.signInWithIntent(result.data) ?: return@launch
_userData.value = userData
authRepo.getUserResult(userData.userId).collect {
when(it) {
Result.Loading -> _uiState.value = Loading
Result.NotFound -> { showPolicySheet = true }
Result.Loading -> uiState = Loading
Result.NotFound -> policySheetState.show()
is Result.Error -> onShowSnackBar("회원 확인에 실패했어요", null)
is Result.Success -> {
if (it.data.gardenId.isEmpty()) {
Expand All @@ -89,27 +74,23 @@ class LoginViewModel @Inject constructor(
}
}
}
_uiState.value = Nothing
uiState = Nothing
}
}
}

fun openBrowser(context: Context, url: String) = linkUtil.openBrowser(context, url)

fun join(onShowSnackBar: suspend (String, String?) -> Boolean) {
_policyUiState.value = PolicyUiState.Loading
policyChecked = true
personalChecked = true
policySheetState.onContinue()
viewModelScope.launch {
authRepo.join(_userData.value).collect {
when (it) {
is Result.Error -> onShowSnackBar("가입에 실패했어요", null)
is Result.Success -> {
showPolicySheet = false
}
is Result.Success -> policySheetState.dismiss()
else -> {}
}
_policyUiState.value = PolicyUiState.Nothing
policySheetState.toNothing()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ internal fun ParticipateScreen(
TutTutButton(
text = stringResource(id = R.string.confirm),
isLoading = isLoading,
enabled = (tabState.isNew && nameState.isValidate()) || (!tabState.isNew && codeState.isValidate()),
enabled = nameState.isValidate() && codeState.isValidate(),
onClick = onNext
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,25 @@ class ParticipateDialogState : DialogState() {
}
}

class ParticipateCodeState : EditTextState("", 6) {
class ParticipateNameState(
private val isNew: Boolean,
maxLength: Int
) : EditTextState("", maxLength) {
override fun isValidate(): Boolean {
return if (isNew) super.isValidate()
else true
}
}

class ParticipateCodeState(
private val isNew: Boolean,
private val codeLength: Int
) : EditTextState("", codeLength) {
var supportingText by mutableStateOf("")
var supportingTextType by mutableStateOf(SupportingTextType.NONE)

override fun typeText(text: String) {
if (text.length <= 6) {
if (text.length <= codeLength) {
typedText = text
if (supportingTextType == SupportingTextType.ERROR) {
supportingText = ""
Expand All @@ -60,5 +73,8 @@ class ParticipateCodeState : EditTextState("", 6) {
supportingTextType = SupportingTextType.ERROR
}

override fun isValidate(): Boolean = typedText.trim().length == 6
override fun isValidate(): Boolean {
return if (!isNew) getTrimText().length == codeLength
else true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import io.tuttut.presentation.ui.screen.login.participate.ParticipateUiState.*
import io.tuttut.data.repository.garden.GardenRepository
import io.tuttut.presentation.base.BaseViewModel
import io.tuttut.presentation.model.PreferenceUtil
import io.tuttut.presentation.ui.state.EditTextState
import io.tuttut.presentation.util.getCurrentDate
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand All @@ -23,8 +22,14 @@ class ParticipateViewModel @Inject constructor(
private var _uiState by mutableStateOf<ParticipateUiState>(Nothing)
val uiState = _uiState
val tabState = ParticipateTabState()
val nameState = EditTextState(maxLength = 10)
val codeState = ParticipateCodeState()
val nameState = ParticipateNameState(
isNew = tabState.isNew,
maxLength = 10
)
val codeState = ParticipateCodeState(
isNew = tabState.isNew,
codeLength = 6
)
val dialogState = ParticipateDialogState()

fun onNext(hideKeyboard: () -> Unit, moveNext: () -> Unit, onShowSnackBar: suspend (String, String?) -> Boolean) {
Expand All @@ -37,7 +42,7 @@ class ParticipateViewModel @Inject constructor(

private suspend fun createGarden(moveNext: () -> Unit, onShowSnackBar: suspend (String, String?) -> Boolean) {
val userId = authClient.getSignedInUser()?.userId ?: return
gardenRepo.createGarden(userId, nameState.typedText.trim(), getCurrentDate()).collect {
gardenRepo.createGarden(userId, nameState.getTrimText(), getCurrentDate()).collect {
when (it) {
Result.Loading -> _uiState = Loading
is Result.Error -> onShowSnackBar("텃밭 생성에 실패했어요", null)
Expand All @@ -52,7 +57,7 @@ class ParticipateViewModel @Inject constructor(
}

private suspend fun checkGardenExist(onShowSnackBar: suspend (String, String?) -> Boolean) {
gardenRepo.checkGardenExist(codeState.typedText.trim()).collect {
gardenRepo.checkGardenExist(codeState.getTrimText()).collect {
when (it) {
Result.Loading -> _uiState = Loading
Result.NotFound -> codeState.showNotFoundError()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import io.tuttut.presentation.ui.component.TutTutButton
import io.tuttut.presentation.ui.component.TutTutLabel
import io.tuttut.presentation.ui.component.TutTutTextField
import io.tuttut.presentation.ui.component.TutTutTopBar
import io.tuttut.presentation.ui.state.IEditTextState
import io.tuttut.presentation.util.withScreenPadding

@Composable
Expand All @@ -29,9 +30,7 @@ fun ChangeGardenRoute(
ChangeGardenScreen(
modifier = modifier,
uiState = viewModel.uiState,
typedGardenName = viewModel.nameState.typedText,
typeGardenName = viewModel.nameState::typeText,
resetGardenName = viewModel.nameState::resetText,
nameState = viewModel.nameState,
onSubmit = { viewModel.onSubmit(onBack, onShowSnackBar) },
onBack = onBack
)
Expand All @@ -42,9 +41,7 @@ fun ChangeGardenRoute(
internal fun ChangeGardenScreen(
modifier: Modifier,
uiState: ChangeGardenUiState,
typedGardenName: String,
typeGardenName: (String) -> Unit,
resetGardenName: () -> Unit,
nameState: IEditTextState,
onSubmit: () -> Unit,
onBack: () -> Unit,
) {
Expand All @@ -63,11 +60,11 @@ internal fun ChangeGardenScreen(
title = stringResource(id = R.string.profile_name)
)
TutTutTextField(
value = typedGardenName,
value = nameState.typedText,
placeHolder = stringResource(id = R.string.garden_name_placeholder),
supportingText = stringResource(id = R.string.text_limit),
onValueChange = typeGardenName,
onResetValue = resetGardenName
onValueChange = nameState::typeText,
onResetValue = nameState::resetText
)
}
Box(
Expand All @@ -79,7 +76,7 @@ internal fun ChangeGardenScreen(
TutTutButton(
text = stringResource(id = R.string.change),
isLoading = uiState == ChangeGardenUiState.Loading,
enabled = typedGardenName.trim().length in 1 .. 10,
enabled = nameState.isValidate(),
onClick = onSubmit
)
}
Expand Down
Loading

0 comments on commit 554bd02

Please sign in to comment.