From ed28e3adb04d95969c7eb64856614fcaecc1febc Mon Sep 17 00:00:00 2001 From: Junhyeok Date: Sat, 15 Feb 2025 01:10:25 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BA=90=EB=A6=AD=ED=84=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(#70)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor : pass modifier * feat : add SelectCharacterDialog * feat : Add character change to settings * refactor : use string resources for button text * refactor : lint * feat : review * feat : contentDesc * refactor : en res --- .../OnboardingSelectCharacterScreen.kt | 13 ++- app/src/main/res/values-en/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../dobedobe/core/ui/SelectCharacterScreen.kt | 15 +-- core/ui/src/main/res/values-en/strings.xml | 1 - core/ui/src/main/res/values/strings.xml | 1 - .../dobedobe/feature/setting/SettingScreen.kt | 29 ++++++ .../feature/setting/SettingUiState.kt | 3 + .../feature/setting/SettingViewModel.kt | 14 ++- .../component/SelectCharacterDialog.kt | 97 +++++++++++++++++++ .../src/main/res/values-en/strings.xml | 2 + .../setting/src/main/res/values/strings.xml | 2 + 12 files changed, 165 insertions(+), 14 deletions(-) create mode 100644 feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/component/SelectCharacterDialog.kt diff --git a/app/src/main/kotlin/com/chipichipi/dobedobe/onboarding/OnboardingSelectCharacterScreen.kt b/app/src/main/kotlin/com/chipichipi/dobedobe/onboarding/OnboardingSelectCharacterScreen.kt index ca8bcbe3..2562afd0 100644 --- a/app/src/main/kotlin/com/chipichipi/dobedobe/onboarding/OnboardingSelectCharacterScreen.kt +++ b/app/src/main/kotlin/com/chipichipi/dobedobe/onboarding/OnboardingSelectCharacterScreen.kt @@ -1,9 +1,13 @@ package com.chipichipi.dobedobe.onboarding +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.chipichipi.dobedobe.R import com.chipichipi.dobedobe.core.ui.SelectCharacterScreen import org.koin.androidx.compose.koinViewModel @@ -15,9 +19,16 @@ internal fun OnboardingSelectCharacterRoute( val selectedCharacter by viewModel.selectedCharacter.collectAsStateWithLifecycle() SelectCharacterScreen( - modifier = modifier, selectedCharacter = selectedCharacter, onCharacterToggled = viewModel::toggleCharacter, onCompleted = viewModel::completeOnboarding, + buttonText = R.string.onboarding_all_completed, + modifier = modifier + .fillMaxSize() + .padding(horizontal = 24.dp) + .padding( + top = 48.dp, + bottom = 32.dp, + ), ) } diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index f8d28921..d4f7778f 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -6,4 +6,5 @@ ex) Read 1 book per day The simpler the goal, the better the focus. Complete + Start \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8f38036b..08bfc032 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,4 +5,5 @@ ex) 1일 1책 읽기 목표가 간결할수록 집중력이 높아져요. 작성 완료 + 시작하기 \ No newline at end of file diff --git a/core/ui/src/main/kotlin/com/chipichipi/dobedobe/core/ui/SelectCharacterScreen.kt b/core/ui/src/main/kotlin/com/chipichipi/dobedobe/core/ui/SelectCharacterScreen.kt index d9708e3e..1ba49541 100644 --- a/core/ui/src/main/kotlin/com/chipichipi/dobedobe/core/ui/SelectCharacterScreen.kt +++ b/core/ui/src/main/kotlin/com/chipichipi/dobedobe/core/ui/SelectCharacterScreen.kt @@ -1,12 +1,11 @@ package com.chipichipi.dobedobe.core.ui +import androidx.annotation.StringRes import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -22,16 +21,11 @@ fun SelectCharacterScreen( selectedCharacter: CharacterType, onCharacterToggled: () -> Unit, onCompleted: () -> Unit, + @StringRes buttonText: Int, modifier: Modifier = Modifier, ) { Column( - modifier = modifier - .fillMaxSize() - .padding(horizontal = 24.dp) - .padding( - top = 48.dp, - bottom = 32.dp, - ), + modifier = modifier, ) { Text( text = stringResource(R.string.select_character_title), @@ -59,7 +53,7 @@ fun SelectCharacterScreen( onClick = onCompleted, ) { Text( - text = stringResource(R.string.all_complete), + text = stringResource(buttonText), style = DobeDobeTheme.typography.heading2, color = DobeDobeTheme.colors.white, ) @@ -75,6 +69,7 @@ private fun SelectCharacterScreenPreview() { selectedCharacter = CharacterType.Rabbit, onCharacterToggled = {}, onCompleted = {}, + buttonText = R.string.select_character_title, ) } } diff --git a/core/ui/src/main/res/values-en/strings.xml b/core/ui/src/main/res/values-en/strings.xml index ad83f168..a91eac67 100644 --- a/core/ui/src/main/res/values-en/strings.xml +++ b/core/ui/src/main/res/values-en/strings.xml @@ -1,7 +1,6 @@ Please select your running mate - Start Nagging Bird Empathetic Lucky Rabbit diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/main/res/values/strings.xml index 9424f02b..28f0f4dd 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/main/res/values/strings.xml @@ -1,7 +1,6 @@ 함께 할 러닝메이트를\n선택해 주세요 - 시작하기 마구 쪼는 잔소리무새 공감 만점 럭키 토끼 \ No newline at end of file diff --git a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingScreen.kt b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingScreen.kt index d2797798..bd341782 100644 --- a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingScreen.kt +++ b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingScreen.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -25,8 +26,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.chipichipi.dobedobe.core.designsystem.component.DobeDobeSwitch import com.chipichipi.dobedobe.core.designsystem.icon.DobeDobeIcons import com.chipichipi.dobedobe.core.designsystem.theme.DobeDobeTheme +import com.chipichipi.dobedobe.core.model.CharacterType import com.chipichipi.dobedobe.core.notifications.NotificationUtil import com.chipichipi.dobedobe.core.notifications.NotificationUtil.areNotificationsEnabled +import com.chipichipi.dobedobe.feature.setting.component.SelectCharacterDialog import com.chipichipi.dobedobe.feature.setting.component.SettingRow import com.chipichipi.dobedobe.feature.setting.component.SettingTopAppBar import com.chipichipi.dobedobe.feature.setting.util.openPlayStore @@ -46,6 +49,7 @@ internal fun SettingRoute( uiState = settingUiState, navigateToBack = navigateToBack, onNotificationToggled = viewModel::setGoalNotificationEnabled, + onCharacterChangeCompleted = viewModel::changeCharacterCompleted, ) } @@ -54,6 +58,7 @@ private fun SettingScreen( uiState: SettingUiState, navigateToBack: () -> Unit, onNotificationToggled: (Boolean) -> Unit, + onCharacterChangeCompleted: (CharacterType) -> Unit, modifier: Modifier = Modifier, ) { Scaffold( @@ -81,6 +86,8 @@ private fun SettingScreen( SettingBody( isGoalNotificationEnabled = uiState.isGoalNotificationEnabled, onNotificationToggled = onNotificationToggled, + characterType = uiState.characterType, + onCharacterChangeCompleted = onCharacterChangeCompleted, ) } } @@ -96,9 +103,12 @@ private fun SettingScreen( private fun SettingBody( isGoalNotificationEnabled: Boolean, onNotificationToggled: (Boolean) -> Unit, + characterType: CharacterType, + onCharacterChangeCompleted: (CharacterType) -> Unit, modifier: Modifier = Modifier, ) { val context = LocalContext.current + var showSelectCharacterDialog by rememberSaveable { mutableStateOf(false) } val handleNotificationToggle: (Boolean) -> Unit = { enabled -> NotificationUtil.handleNotificationToggle( @@ -108,6 +118,14 @@ private fun SettingBody( ) } + if (showSelectCharacterDialog) { + SelectCharacterDialog( + onDismissRequest = { showSelectCharacterDialog = false }, + characterType = characterType, + onCharacterChangeCompleted = onCharacterChangeCompleted, + ) + } + Column( modifier = modifier .fillMaxSize(), @@ -137,6 +155,17 @@ private fun SettingBody( tint = Color.Unspecified, ) } + + SettingRow( + label = stringResource(R.string.feature_setting_change_character), + onClick = { showSelectCharacterDialog = true }, + ) { + Icon( + painter = painterResource(DobeDobeIcons.ArrowForward), + contentDescription = null, + tint = Color.Unspecified, + ) + } } } diff --git a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingUiState.kt b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingUiState.kt index 3183fb71..81463d31 100644 --- a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingUiState.kt +++ b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingUiState.kt @@ -1,9 +1,12 @@ package com.chipichipi.dobedobe.feature.setting +import com.chipichipi.dobedobe.core.model.CharacterType + sealed interface SettingUiState { data object Loading : SettingUiState data class Success( val isGoalNotificationEnabled: Boolean, + val characterType: CharacterType, ) : SettingUiState } diff --git a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingViewModel.kt b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingViewModel.kt index 220f0046..d8e4227b 100644 --- a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingViewModel.kt +++ b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/SettingViewModel.kt @@ -3,6 +3,7 @@ package com.chipichipi.dobedobe.feature.setting import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.chipichipi.dobedobe.core.data.repository.UserRepository +import com.chipichipi.dobedobe.core.model.CharacterType import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn @@ -12,7 +13,12 @@ internal class SettingViewModel( private val userRepository: UserRepository, ) : ViewModel() { val settingUiState = userRepository.userData - .map { SettingUiState.Success(it.isGoalNotificationEnabled) } + .map { user -> + SettingUiState.Success( + isGoalNotificationEnabled = user.isGoalNotificationEnabled, + characterType = user.characterType, + ) + } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5_000), @@ -24,4 +30,10 @@ internal class SettingViewModel( userRepository.setGoalNotificationEnabled(checked) } } + + fun changeCharacterCompleted(type: CharacterType) { + viewModelScope.launch { + userRepository.saveCharacter(type) + } + } } diff --git a/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/component/SelectCharacterDialog.kt b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/component/SelectCharacterDialog.kt new file mode 100644 index 00000000..2dda9c0e --- /dev/null +++ b/feature/setting/src/main/kotlin/com/chipichipi/dobedobe/feature/setting/component/SelectCharacterDialog.kt @@ -0,0 +1,97 @@ +package com.chipichipi.dobedobe.feature.setting.component + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Cancel +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import com.chipichipi.dobedobe.core.designsystem.component.ThemePreviews +import com.chipichipi.dobedobe.core.designsystem.theme.DobeDobeTheme +import com.chipichipi.dobedobe.core.model.CharacterType +import com.chipichipi.dobedobe.core.ui.SelectCharacterScreen +import com.chipichipi.dobedobe.feature.setting.R + +@Composable +internal fun SelectCharacterDialog( + onDismissRequest: () -> Unit, + characterType: CharacterType, + onCharacterChangeCompleted: (CharacterType) -> Unit, +) { + var selectedCharacterType by rememberSaveable { mutableStateOf(characterType) } + + Dialog( + onDismissRequest = onDismissRequest, + properties = DialogProperties( + usePlatformDefaultWidth = false, + ), + ) { + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp), + shape = RoundedCornerShape(16.dp), + color = DobeDobeTheme.colors.white, + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(top = 10.dp, bottom = 32.dp), + ) { + IconButton( + modifier = Modifier.align(Alignment.End), + onClick = onDismissRequest, + ) { + Icon( + imageVector = Icons.Filled.Cancel, + contentDescription = "close", + ) + } + + SelectCharacterScreen( + selectedCharacter = selectedCharacterType, + onCompleted = { + onCharacterChangeCompleted(selectedCharacterType) + onDismissRequest() + }, + onCharacterToggled = { + selectedCharacterType = if (selectedCharacterType == CharacterType.Rabbit) { + CharacterType.Bird + } else { + CharacterType.Rabbit + } + }, + buttonText = R.string.feature_setting_change_character_completed, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp), + ) + } + } + } +} + +@ThemePreviews +@Composable +private fun SelectCharacterDialogPreview() { + DobeDobeTheme { + SelectCharacterDialog( + onDismissRequest = {}, + characterType = CharacterType.Rabbit, + onCharacterChangeCompleted = {}, + ) + } +} diff --git a/feature/setting/src/main/res/values-en/strings.xml b/feature/setting/src/main/res/values-en/strings.xml index a99607a2..14a90cab 100644 --- a/feature/setting/src/main/res/values-en/strings.xml +++ b/feature/setting/src/main/res/values-en/strings.xml @@ -3,4 +3,6 @@ Setting Leave App Feedback Notification + Change Character + Confirm Change \ No newline at end of file diff --git a/feature/setting/src/main/res/values/strings.xml b/feature/setting/src/main/res/values/strings.xml index 2206ae42..2c2a5a52 100644 --- a/feature/setting/src/main/res/values/strings.xml +++ b/feature/setting/src/main/res/values/strings.xml @@ -3,4 +3,6 @@ 설정 앱 피드백 남기기 알림 + 캐릭터 변경하기 + 변경하기 \ No newline at end of file