diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b15d784c..e02e5fcf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -52,6 +52,7 @@ dependencies { projects.feature.main, projects.feature.login, projects.feature.search, + projects.feature.settings, libs.androidx.activity.compose, libs.androidx.startup, diff --git a/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/divider/ReedDivider.kt b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/divider/ReedDivider.kt new file mode 100644 index 00000000..83d07d06 --- /dev/null +++ b/core/designsystem/src/main/kotlin/com/ninecraft/booket/core/designsystem/component/divider/ReedDivider.kt @@ -0,0 +1,29 @@ +package com.ninecraft.booket.core.designsystem.component.divider + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.designsystem.theme.ReedTheme + +@Composable +fun ReedDivider(modifier: Modifier = Modifier) { + Box( + modifier = modifier + .fillMaxWidth() + .height(8.dp) + .background(ReedTheme.colors.dividerMd), + ) +} + +@Preview +@Composable +private fun ReedDividerPreview() { + ReedTheme { + ReedDivider() + } +} diff --git a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt index 1d13e121..b662cfe0 100644 --- a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt +++ b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryPresenter.kt @@ -10,6 +10,7 @@ import com.ninecraft.booket.core.data.api.repository.AuthRepository import com.ninecraft.booket.core.data.api.repository.UserRepository import com.ninecraft.booket.screens.LibraryScreen import com.ninecraft.booket.screens.LoginScreen +import com.ninecraft.booket.screens.SettingsScreen import com.orhanobut.logger.Logger import com.skydoves.compose.effects.RememberedEffect import com.slack.circuit.codegen.annotations.CircuitInject @@ -76,6 +77,10 @@ class LibraryPresenter @AssistedInject constructor( sideEffect = null } + is LibraryUiEvent.OnSettingsClick -> { + navigator.goTo(SettingsScreen) + } + is LibraryUiEvent.OnLogoutButtonClick -> { scope.launch { try { diff --git a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt index 6b2c8bb0..b95434f5 100644 --- a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt +++ b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryScreen.kt @@ -9,11 +9,16 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource import androidx.compose.ui.unit.dp import com.ninecraft.booket.core.designsystem.DevicePreview import com.ninecraft.booket.core.designsystem.component.button.ReedButton @@ -58,6 +63,18 @@ internal fun LibraryContent( verticalArrangement = Arrangement.Center, ) { Box(modifier = modifier.fillMaxSize()) { + IconButton( + modifier = Modifier.align(Alignment.TopEnd), + onClick = { + state.eventSink(LibraryUiEvent.OnSettingsClick) + }, + ) { + Icon( + imageVector = ImageVector.vectorResource(id = com.ninecraft.booket.core.designsystem.R.drawable.ic_settings), + contentDescription = "Settings Icon", + tint = Color.Unspecified, + ) + } Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, diff --git a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt index dd710b04..d90106b7 100644 --- a/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt +++ b/feature/library/src/main/kotlin/com/ninecraft/booket/feature/library/LibraryUiState.kt @@ -17,5 +17,6 @@ sealed interface LibrarySideEffect { sealed interface LibraryUiEvent : CircuitUiEvent { data object InitSideEffect : LibraryUiEvent + data object OnSettingsClick : LibraryUiEvent data object OnLogoutButtonClick : LibraryUiEvent } diff --git a/feature/settings/.gitignore b/feature/settings/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/feature/settings/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts new file mode 100644 index 00000000..0df5174e --- /dev/null +++ b/feature/settings/build.gradle.kts @@ -0,0 +1,21 @@ +@file:Suppress("INLINE_FROM_HIGHER_PLATFORM") + +plugins { + alias(libs.plugins.booket.android.feature) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.kotlin.parcelize) +} + +android { + namespace = "com.ninecraft.booket.feature.settings" +} + +ksp { + arg("circuit.codegen.mode", "hilt") +} + +dependencies { + implementations( + libs.logger, + ) +} diff --git a/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsPresenter.kt b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsPresenter.kt new file mode 100644 index 00000000..bac6a716 --- /dev/null +++ b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsPresenter.kt @@ -0,0 +1,77 @@ +package com.ninecraft.booket.feature.settings + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import com.ninecraft.booket.screens.SettingsScreen +import com.slack.circuit.codegen.annotations.CircuitInject +import com.slack.circuit.retained.rememberRetained +import com.slack.circuit.runtime.Navigator +import com.slack.circuit.runtime.presenter.Presenter +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import dagger.hilt.android.components.ActivityRetainedComponent + +class SettingsPresenter @AssistedInject constructor( + @Assisted val navigator: Navigator, +) : Presenter { + + @Composable + override fun present(): SettingsUiState { + var isLogoutBottomSheetVisible by rememberRetained { mutableStateOf(false) } + var isWithdrawBottomSheetVisible by rememberRetained { mutableStateOf(false) } + var isWithdrawConfirmed by rememberRetained { mutableStateOf(false) } + + fun handleEvent(event: SettingsUiEvent) { + when (event) { + is SettingsUiEvent.OnBackClick -> { + navigator.pop() + } + + is SettingsUiEvent.OnTermDetailClick -> { + // TODO: 웹뷰 화면으로 이동 + } + + is SettingsUiEvent.OnLogoutClick -> { + isLogoutBottomSheetVisible = true + } + + is SettingsUiEvent.OnWithdrawClick -> { + isWithdrawBottomSheetVisible = true + } + + is SettingsUiEvent.OnBottomSheetDismissed -> { + isLogoutBottomSheetVisible = false + isWithdrawBottomSheetVisible = false + isWithdrawConfirmed = false + } + + is SettingsUiEvent.OnWithdrawConfirmationToggled -> { + isWithdrawConfirmed = !isWithdrawConfirmed + } + + is SettingsUiEvent.Logout -> { + // TODO: 로그아웃 처리 -> 성공 시 로그인 화면으로 이동 + } + + is SettingsUiEvent.Withdraw -> { + // TODO: 회원탈퇴 처리 -> 성공 시 로그인 화면으로 이동 + } + } + } + return SettingsUiState( + isLogoutBottomSheetVisible = isLogoutBottomSheetVisible, + isWithdrawBottomSheetVisible = isWithdrawBottomSheetVisible, + isWithdrawConfirmed = isWithdrawConfirmed, + eventSink = ::handleEvent, + ) + } + + @CircuitInject(SettingsScreen::class, ActivityRetainedComponent::class) + @AssistedFactory + fun interface Factory { + fun create(navigator: Navigator): SettingsPresenter + } +} diff --git a/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsScreen.kt new file mode 100644 index 00000000..516f4f90 --- /dev/null +++ b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsScreen.kt @@ -0,0 +1,222 @@ +package com.ninecraft.booket.feature.settings + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +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.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.res.vectorResource +import com.ninecraft.booket.core.common.extensions.clickableSingle +import com.ninecraft.booket.core.designsystem.DevicePreview +import com.ninecraft.booket.core.designsystem.component.appbar.ReedBackTopAppBar +import com.ninecraft.booket.core.designsystem.component.divider.ReedDivider +import com.ninecraft.booket.core.designsystem.theme.ReedTheme +import com.ninecraft.booket.core.designsystem.theme.White +import com.ninecraft.booket.feature.settings.component.LogoutConfirmationBottomSheet +import com.ninecraft.booket.feature.settings.component.WithdrawConfirmationBottomSheet +import com.ninecraft.booket.screens.SettingsScreen +import com.slack.circuit.codegen.annotations.CircuitInject +import dagger.hilt.android.components.ActivityRetainedComponent +import kotlinx.coroutines.launch + +@OptIn(ExperimentalMaterial3Api::class) +@CircuitInject(SettingsScreen::class, ActivityRetainedComponent::class) +@Composable +internal fun Settings( + state: SettingsUiState, + modifier: Modifier = Modifier, +) { + val logoutSheetState = rememberModalBottomSheetState() + val withDrawSheetState = rememberModalBottomSheetState() + val coroutineScope = rememberCoroutineScope() + + val context = LocalContext.current + val appVersion = remember { + runCatching { + context.packageManager.getPackageInfo(context.packageName, 0)?.versionName + }.getOrNull() ?: "Unknown" + } + + Column( + modifier = modifier + .fillMaxSize() + .background(White), + ) { + ReedBackTopAppBar( + title = stringResource(R.string.settings_title), + onNavigateBack = { + state.eventSink(SettingsUiEvent.OnBackClick) + }, + ) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing4)) + + SettingItem( + title = stringResource(R.string.settings_privacy_policy), + onItemClick = { + state.eventSink(SettingsUiEvent.OnTermDetailClick("")) + }, + action = { + Icon( + imageVector = ImageVector.vectorResource(id = com.ninecraft.booket.core.designsystem.R.drawable.ic_chevron_right), + contentDescription = "Right Chevron Icon", + tint = Color.Unspecified, + ) + }, + ) + SettingItem( + title = stringResource(R.string.settings_terms_of_service), + onItemClick = { + state.eventSink(SettingsUiEvent.OnTermDetailClick("")) + }, + action = { + Icon( + imageVector = ImageVector.vectorResource(id = com.ninecraft.booket.core.designsystem.R.drawable.ic_chevron_right), + contentDescription = "Right Chevron Icon", + tint = Color.Unspecified, + ) + }, + ) + SettingItem( + title = stringResource(R.string.settings_open_source_license), + onItemClick = { + state.eventSink(SettingsUiEvent.OnTermDetailClick("")) + }, + action = { + Icon( + imageVector = ImageVector.vectorResource(id = com.ninecraft.booket.core.designsystem.R.drawable.ic_chevron_right), + contentDescription = "Right Chevron Icon", + tint = Color.Unspecified, + ) + }, + ) + SettingItem( + title = stringResource(R.string.settings_app_version), + isClickable = false, + action = { + Text( + text = appVersion, + style = ReedTheme.typography.body1Medium, + color = ReedTheme.colors.contentSecondary, + ) + }, + ) + ReedDivider(modifier = Modifier.padding(vertical = ReedTheme.spacing.spacing4)) + SettingItem( + title = stringResource(R.string.settings_logout), + onItemClick = { + state.eventSink(SettingsUiEvent.OnLogoutClick) + }, + ) + SettingItem( + title = stringResource(R.string.settings_withdraw), + onItemClick = { + state.eventSink(SettingsUiEvent.OnWithdrawClick) + }, + ) + } + + if (state.isLogoutBottomSheetVisible) { + LogoutConfirmationBottomSheet( + onDismissRequest = { + state.eventSink(SettingsUiEvent.OnBottomSheetDismissed) + }, + sheetState = logoutSheetState, + onCancelButtonClick = { + coroutineScope.launch { + logoutSheetState.hide() + state.eventSink(SettingsUiEvent.OnBottomSheetDismissed) + } + }, + onLogoutButtonClick = { + state.eventSink(SettingsUiEvent.Logout) + }, + ) + } + + if (state.isWithdrawBottomSheetVisible) { + WithdrawConfirmationBottomSheet( + onDismissRequest = { + state.eventSink(SettingsUiEvent.OnBottomSheetDismissed) + }, + sheetState = withDrawSheetState, + isCheckBoxChecked = state.isWithdrawConfirmed, + onCheckBoxCheckedChange = { + state.eventSink(SettingsUiEvent.OnWithdrawConfirmationToggled) + }, + onCancelButtonClick = { + coroutineScope.launch { + withDrawSheetState.hide() + state.eventSink(SettingsUiEvent.OnBottomSheetDismissed) + } + }, + onWithdrawButtonClick = { + state.eventSink(SettingsUiEvent.Withdraw) + }, + ) + } +} + +@Composable +private fun SettingItem( + title: String, + modifier: Modifier = Modifier, + isClickable: Boolean = true, + onItemClick: () -> Unit = {}, + action: @Composable () -> Unit = {}, +) { + val combinedModifier = if (isClickable) { + modifier + .fillMaxWidth() + .clickableSingle { onItemClick() } + } else { + modifier.fillMaxWidth() + } + + Row( + modifier = combinedModifier + .padding( + horizontal = ReedTheme.spacing.spacing5, + vertical = ReedTheme.spacing.spacing4, + ), + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + modifier = Modifier.weight(1f), + text = title, + style = ReedTheme.typography.body1Medium, + color = ReedTheme.colors.contentPrimary, + ) + action() + } +} + +@DevicePreview +@Composable +private fun SettingsScreenPreview() { + ReedTheme { + Settings( + state = SettingsUiState( + isLogoutBottomSheetVisible = false, + isWithdrawBottomSheetVisible = false, + isWithdrawConfirmed = false, + eventSink = {}, + ), + ) + } +} diff --git a/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUiState.kt b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUiState.kt new file mode 100644 index 00000000..06dce37b --- /dev/null +++ b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/SettingsUiState.kt @@ -0,0 +1,22 @@ +package com.ninecraft.booket.feature.settings + +import com.slack.circuit.runtime.CircuitUiEvent +import com.slack.circuit.runtime.CircuitUiState + +data class SettingsUiState( + val isLogoutBottomSheetVisible: Boolean, + val isWithdrawBottomSheetVisible: Boolean, + val isWithdrawConfirmed: Boolean, + val eventSink: (SettingsUiEvent) -> Unit, +) : CircuitUiState + +sealed interface SettingsUiEvent : CircuitUiEvent { + data object OnBackClick : SettingsUiEvent + data class OnTermDetailClick(val title: String) : SettingsUiEvent + data object OnLogoutClick : SettingsUiEvent + data object OnWithdrawClick : SettingsUiEvent + data object OnBottomSheetDismissed : SettingsUiEvent + data object OnWithdrawConfirmationToggled : SettingsUiEvent + data object Logout : SettingsUiEvent + data object Withdraw : SettingsUiEvent +} diff --git a/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/LogoutConfirmationBottomSheet.kt b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/LogoutConfirmationBottomSheet.kt new file mode 100644 index 00000000..1f3897b2 --- /dev/null +++ b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/LogoutConfirmationBottomSheet.kt @@ -0,0 +1,106 @@ +package com.ninecraft.booket.feature.settings.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.designsystem.component.bottomsheet.ReedBottomSheet +import com.ninecraft.booket.core.designsystem.component.button.ReedButton +import com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle +import com.ninecraft.booket.core.designsystem.component.button.largeButtonStyle +import com.ninecraft.booket.core.designsystem.theme.ReedTheme +import com.ninecraft.booket.feature.settings.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun LogoutConfirmationBottomSheet( + onDismissRequest: () -> Unit, + sheetState: SheetState, + onCancelButtonClick: () -> Unit, + onLogoutButtonClick: () -> Unit, +) { + ReedBottomSheet( + onDismissRequest = { + onDismissRequest() + }, + sheetState = sheetState, + ) { + Column( + modifier = Modifier + .padding( + start = ReedTheme.spacing.spacing5, + top = ReedTheme.spacing.spacing5, + end = ReedTheme.spacing.spacing5, + ), + ) { + Text( + text = stringResource(R.string.settings_logout_title), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = ReedTheme.spacing.spacing3), + color = ReedTheme.colors.contentPrimary, + textAlign = TextAlign.Center, + style = ReedTheme.typography.heading2SemiBold, + ) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + ReedButton( + onClick = { + onCancelButtonClick() + }, + sizeStyle = largeButtonStyle, + colorStyle = ReedButtonColorStyle.SECONDARY, + modifier = Modifier.weight(1f), + text = stringResource(R.string.settings_cancel), + ) + Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2)) + ReedButton( + onClick = { + onLogoutButtonClick() + }, + sizeStyle = largeButtonStyle, + colorStyle = ReedButtonColorStyle.PRIMARY, + modifier = Modifier.weight(1f), + text = stringResource(R.string.settings_logout), + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview(showBackground = true) +@Composable +private fun LogoutConfirmationBottomSheetPreview() { + val sheetState = SheetState( + skipPartiallyExpanded = true, + initialValue = SheetValue.Expanded, + positionalThreshold = { 0f }, + velocityThreshold = { 0f }, + ) + ReedTheme { + LogoutConfirmationBottomSheet( + onDismissRequest = {}, + sheetState = sheetState, + onCancelButtonClick = {}, + onLogoutButtonClick = {}, + ) + } +} diff --git a/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/WithdrawConfirmationBottomSheet.kt b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/WithdrawConfirmationBottomSheet.kt new file mode 100644 index 00000000..cf220496 --- /dev/null +++ b/feature/settings/src/main/kotlin/com/ninecraft/booket/feature/settings/component/WithdrawConfirmationBottomSheet.kt @@ -0,0 +1,140 @@ +package com.ninecraft.booket.feature.settings.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.SheetState +import androidx.compose.material3.SheetValue +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.ninecraft.booket.core.designsystem.component.bottomsheet.ReedBottomSheet +import com.ninecraft.booket.core.designsystem.component.button.ReedButton +import com.ninecraft.booket.core.designsystem.component.button.ReedButtonColorStyle +import com.ninecraft.booket.core.designsystem.component.button.largeButtonStyle +import com.ninecraft.booket.core.designsystem.component.checkbox.SquareCheckBox +import com.ninecraft.booket.core.designsystem.theme.ReedTheme +import com.ninecraft.booket.feature.settings.R + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun WithdrawConfirmationBottomSheet( + onDismissRequest: () -> Unit, + sheetState: SheetState, + isCheckBoxChecked: Boolean, + onCheckBoxCheckedChange: () -> Unit, + onCancelButtonClick: () -> Unit, + onWithdrawButtonClick: () -> Unit, +) { + ReedBottomSheet( + onDismissRequest = { + onDismissRequest() + }, + sheetState = sheetState, + ) { + Column( + modifier = Modifier + .padding( + start = ReedTheme.spacing.spacing5, + top = ReedTheme.spacing.spacing5, + end = ReedTheme.spacing.spacing5, + ), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = stringResource(R.string.settings_withdraw_title), + modifier = Modifier + .fillMaxWidth() + .padding(top = ReedTheme.spacing.spacing3), + color = ReedTheme.colors.contentPrimary, + textAlign = TextAlign.Center, + style = ReedTheme.typography.heading2SemiBold, + ) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing1)) + Text( + text = stringResource(R.string.settings_withdraw_detail), + modifier = Modifier.fillMaxWidth(), + color = ReedTheme.colors.contentSecondary, + textAlign = TextAlign.Center, + style = ReedTheme.typography.body1Medium, + ) + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing5)) + Row { + SquareCheckBox( + checked = isCheckBoxChecked, + onCheckedChange = { + onCheckBoxCheckedChange() + }, + ) + Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2)) + Text( + text = stringResource(R.string.settings_withdraw_agreement), + color = ReedTheme.colors.contentPrimary, + textAlign = TextAlign.Center, + style = ReedTheme.typography.body1Medium, + ) + } + Spacer(modifier = Modifier.height(ReedTheme.spacing.spacing3)) + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + ReedButton( + onClick = { + onCancelButtonClick() + }, + sizeStyle = largeButtonStyle, + colorStyle = ReedButtonColorStyle.SECONDARY, + modifier = Modifier.weight(1f), + text = stringResource(R.string.settings_cancel), + ) + Spacer(modifier = Modifier.width(ReedTheme.spacing.spacing2)) + ReedButton( + onClick = { + onWithdrawButtonClick() + }, + sizeStyle = largeButtonStyle, + colorStyle = ReedButtonColorStyle.PRIMARY, + modifier = Modifier.weight(1f), + enabled = isCheckBoxChecked, + text = stringResource(R.string.settings_withdraw_action), + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview(showBackground = true) +@Composable +private fun WithdrawConfirmationBottomSheetPreview() { + val sheetState = SheetState( + skipPartiallyExpanded = true, + initialValue = SheetValue.Expanded, + positionalThreshold = { 0f }, + velocityThreshold = { 0f }, + ) + ReedTheme { + WithdrawConfirmationBottomSheet( + onDismissRequest = {}, + sheetState = sheetState, + isCheckBoxChecked = true, + onCheckBoxCheckedChange = {}, + onCancelButtonClick = {}, + onWithdrawButtonClick = {}, + ) + } +} diff --git a/feature/settings/src/main/res/values/strings.xml b/feature/settings/src/main/res/values/strings.xml new file mode 100644 index 00000000..8d894c91 --- /dev/null +++ b/feature/settings/src/main/res/values/strings.xml @@ -0,0 +1,16 @@ + + + 설정 + 개인정보 처리방침 + 이용약관 + 오픈소스 라이선스 + 앱 버전 + 로그아웃 + 회원탈퇴 + 정말 로그아웃 하시겠습니까? + 정말 탈퇴하시겠어요? + 탈퇴 시, 개인 정보와 그동안의 독서기록이\n모두 삭제되며 복구가 어렵습니다. + 확인하였으며 이에 동의합니다. + 취소 + 탈퇴하기 + diff --git a/screens/src/main/kotlin/com/ninecraft/booket/screens/Screens.kt b/screens/src/main/kotlin/com/ninecraft/booket/screens/Screens.kt index 450a391d..9ae28659 100644 --- a/screens/src/main/kotlin/com/ninecraft/booket/screens/Screens.kt +++ b/screens/src/main/kotlin/com/ninecraft/booket/screens/Screens.kt @@ -21,3 +21,6 @@ data object SearchScreen : ReedScreen(name = "Search()") @Parcelize data object TermsAgreementScreen : ReedScreen(name = "TermsAgreement()") + +@Parcelize +data object SettingsScreen : ReedScreen(name = "Settings()") diff --git a/settings.gradle.kts b/settings.gradle.kts index ff8a48c2..0a418e8d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -39,6 +39,7 @@ include( ":feature:login", ":feature:main", ":feature:search", + ":feature:settings", ":screens", )