Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

:goal 디자인 시스템 적용 #34

Merged
merged 20 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import com.chipichipi.dobedobe.core.database.fixtures.fakeGoalEntities
import com.chipichipi.dobedobe.core.database.fixtures.fakeGoalEntity
import io.kotest.matchers.booleans.shouldBeTrue
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.matchers.nulls.shouldNotBeNull
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.test.runTest
import kotlinx.datetime.Instant
import org.junit.Before
Expand Down Expand Up @@ -66,7 +68,8 @@ class GoalDaoTest {
goalDao.insertGoal(goal)
goalDao.updateGoal(goal.copy(isCompleted = true, completedAt = Instant.DISTANT_FUTURE))
// then
val retrievedGoal: GoalEntity = goalDao.getGoal(1L).first()
val retrievedGoal: GoalEntity? = goalDao.getGoal(1L).firstOrNull()
retrievedGoal.shouldNotBeNull()
retrievedGoal.isCompleted.shouldBeTrue()
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,49 @@
package com.chipichipi.dobedobe.core.designsystem.component

import androidx.compose.material3.Checkbox
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics
import com.chipichipi.dobedobe.core.designsystem.icon.DobeDobeIcons
import com.chipichipi.dobedobe.core.designsystem.theme.DobeDobeTheme

// TODO: CheckBox 컴포넌트 단순 Wrapper 임시 처리, 각 상태 디자인 정의 필요
@Composable
fun DobeDobeCheckBox(
checked: Boolean,
onCheckedChange: ((Boolean) -> Unit)? = null,
modifier: Modifier = Modifier,
enabled: Boolean = true,
) {
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
IconButton(
onClick = { onCheckedChange?.invoke(!checked) },
modifier = modifier.semantics {
role = Role.Checkbox
},
enabled = enabled,
modifier = modifier,
)
) {
val iconRes = if (checked) DobeDobeIcons.Checked else DobeDobeIcons.Unchecked
Icon(
imageVector = ImageVector.vectorResource(iconRes),
contentDescription = "checked",
tint = Color.Unspecified,
)
}
}

@ThemePreviews
@Composable
private fun DobeDobeCheckBoxPreview() {
DobeDobeTheme {
Column {
DobeDobeCheckBox(checked = true, enabled = true)
DobeDobeCheckBox(checked = false, enabled = true)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ fun DobeDobeSnackbar(
modifier: Modifier = Modifier,
actionOnNewLine: Boolean = false,
shape: Shape = SnackbarDefaults.shape,
containerColor: Color = SnackbarDefaults.color,
contentColor: Color = SnackbarDefaults.contentColor,
containerColor: Color = DobeDobeTheme.colors.gray800,
contentColor: Color = DobeDobeTheme.colors.white,
actionColor: Color = SnackbarDefaults.actionColor,
actionContentColor: Color = SnackbarDefaults.actionContentColor,
dismissActionContentColor: Color = SnackbarDefaults.dismissActionContentColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,12 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.chipichipi.dobedobe.core.designsystem.theme.DobeDobeTheme

private val DefaultDobeDobeTextStyle: TextStyle = TextStyle(
fontSize = 28.sp,
lineHeight = 42.sp,
lineHeightStyle = LineHeightStyle(
alignment = LineHeightStyle.Alignment.Proportional,
trim = LineHeightStyle.Trim.None,
),
)

/**
* TODO : TextField 컴포넌트 단순 Wrapper 임시 처리, 각 상태 디자인 정의 필요
*/
@Composable
fun DobeDobeTextField(
state: TextFieldState,
Expand All @@ -45,7 +29,9 @@ fun DobeDobeTextField(
errorMessage: String? = null,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = DefaultDobeDobeTextStyle,
textStyle: TextStyle = DobeDobeTheme.typography.title1.copy(
color = DobeDobeTheme.colors.gray900,
),
) {
BasicTextField(
state = state,
Expand All @@ -54,19 +40,15 @@ fun DobeDobeTextField(
textStyle = textStyle,
decorator = { innerTextField ->
Column(
modifier =
Modifier
.fillMaxWidth(),
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Box {
if (state.text.isEmpty()) {
Text(
text = hint,
// TODO : Color Scheme 적용 필요
color = Color(0xFFE5E7EB),
color = DobeDobeTheme.colors.gray200,
style = textStyle,
fontWeight = FontWeight.SemiBold,
)
}
innerTextField()
Expand All @@ -91,20 +73,18 @@ private fun SupportMessage(
supportMessage: String,
errorMessage: String? = null,
) {
// TODO : colorScheme 적용 필요
if (errorMessage == null) {
if (errorMessage == null && supportMessage.isNotBlank()) {
Text(
text = supportMessage,
fontSize = 14.sp,
lineHeight = 21.sp,
color = Color(0xFF7A828C),
style = DobeDobeTheme.typography.body3,
color = DobeDobeTheme.colors.gray500,
)
} else {
}
if (errorMessage != null) {
Text(
text = errorMessage,
fontSize = 14.sp,
lineHeight = 21.sp,
color = Color(0xFFFF354D),
style = DobeDobeTheme.typography.body3,
color = DobeDobeTheme.colors.red,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ object DobeDobeIcons {
val EditMode = R.drawable.ic_edit_mode
val Setting = R.drawable.ic_setting_24
val ArrowForward = R.drawable.ic_arrow_forward_24
val Tap = R.drawable.ic_tap_24
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class DobeDobeColors(isDarkTheme: Boolean = false) {
val gray50 = Color(0xFFF9FAFB)
val gray100 = Color(0xFFF3F4F6)
val gray200 = Color(0xFFE5E7EB)
val gray300 = Color(0xFFF0F5FC)
val gray300 = Color(0xFFC0C4CA)
val gray400 = Color(0xFF9CA3AF)
val gray500 = Color(0xFF7A828C)
val gray600 = Color(0xFF5F6875)
Expand Down
21 changes: 21 additions & 0 deletions core/designsystem/src/main/res/drawable/ic_tap_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M10,7L15,12L10,17"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#F0F5FC"
android:strokeLineCap="round"/>
<path
android:pathData="M10,7L15,12L10,17"
android:strokeAlpha="0.2"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#000000"
android:strokeLineCap="round"/>
</vector>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.chipichipi.dobedobe.feature.goal

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
Expand All @@ -10,6 +11,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LocalLifecycleOwner
Expand All @@ -36,6 +38,9 @@ fun AddGoalRoute(
focusManager.clearFocus()
navigateToBack()
}
val errorMessage =
goalValidResult.errorMessage()
?.let { stringResource(id = it) }

LaunchedEffect(Unit) {
viewModel.navigateToBackEvent
Expand All @@ -52,7 +57,7 @@ fun AddGoalRoute(
focusManager.clearFocus()
}
},
errorMessage = goalValidResult.errorMessage(),
errorMessage = errorMessage,
onShowSnackbar = onShowSnackbar,
navigateToBack = onBack,
onChangeGoalName = viewModel::changeGoalTitle,
Expand Down Expand Up @@ -80,12 +85,13 @@ private fun AddGoalScreen(
) { innerPadding ->
GoalEditor(
modifier = Modifier
.fillMaxSize()
.background(DobeDobeTheme.colors.white)
.padding(innerPadding)
.padding(horizontal = 24.dp)
.padding(top = 24.dp),
title = "",
// TODO: stringResource 적용
header = "어떤 목표를 이루고 싶나요?",
header = stringResource(id = R.string.feature_detail_goal_todo_editor_header),
errorMessage = errorMessage,
onChangeTitle = onChangeGoalName,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import kotlinx.coroutines.launch
class AddGoalViewModel(
private val goalRepository: GoalRepository,
) : ViewModel() {
// TODO: 추후 복잡해지면 UI State를 따로 빼서 관리하는 방식으로 변경
private val goalTitle: MutableStateFlow<String> = MutableStateFlow("")
val goalValidResult: StateFlow<GoalTitleValidResult> =
goalTitle
Expand Down
Loading