Skip to content

Commit a62f22a

Browse files
committed
Feat: 루틴리스트 화면 Ui 구현
1 parent 3d40afd commit a62f22a

6 files changed

Lines changed: 140 additions & 33 deletions

File tree

core/designsystem/src/main/java/com/threegap/bitnagil/designsystem/component/atom/BitnagilTextButton.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ data class BitnagilTextButtonColor(
114114
disabledTextColor = BitnagilTheme.colors.navy500,
115115
)
116116

117+
@Composable
118+
fun delete(): BitnagilTextButtonColor = BitnagilTextButtonColor(
119+
defaultBackgroundColor = BitnagilTheme.colors.error10,
120+
pressedBackgroundColor = BitnagilTheme.colors.error10,
121+
disabledBackgroundColor = BitnagilTheme.colors.error10,
122+
defaultTextColor = BitnagilTheme.colors.white,
123+
pressedTextColor = BitnagilTheme.colors.white,
124+
disabledTextColor = BitnagilTheme.colors.white,
125+
)
126+
117127
@Composable
118128
fun cancel(): BitnagilTextButtonColor = BitnagilTextButtonColor(
119129
defaultBackgroundColor = BitnagilTheme.colors.coolGray97,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24">
6+
<path
7+
android:fillColor="#FFBF00"
8+
android:pathData="M11.054,3.342C11.144,3.092 11.074,2.702 11.254,2.572C11.454,2.432 11.804,2.342 12.044,2.342C12.284,2.342 12.434,2.712 12.634,2.852C12.824,2.982 13.244,2.982 13.334,3.222C13.474,3.592 13.264,3.662 13.404,4.032C13.544,4.402 13.654,4.352 13.784,4.722C13.914,5.092 14.054,5.032 14.194,5.402C14.334,5.772 14.294,5.782 14.424,6.152C14.554,6.522 14.234,6.642 14.374,7.002C14.514,7.362 14.464,7.392 14.594,7.752C14.724,8.112 14.834,8.082 14.974,8.452C15.094,8.772 15.414,9.042 15.734,9.162C16.104,9.302 16.124,9.242 16.484,9.372C16.844,9.502 16.784,9.672 17.154,9.802C17.524,9.932 17.544,9.872 17.904,10.002C18.264,10.132 18.394,9.802 18.764,9.942C19.134,10.082 19.124,10.082 19.494,10.222C19.864,10.362 19.714,10.762 20.084,10.902C20.454,11.042 20.474,10.992 20.834,11.122C21.084,11.212 21.204,11.332 21.334,11.512C21.474,11.712 21.424,11.882 21.424,12.122C21.424,12.362 21.644,12.652 21.504,12.852C21.374,13.042 21.154,13.242 20.904,13.332C20.534,13.472 20.584,13.592 20.224,13.732C19.864,13.872 19.794,13.692 19.434,13.832C19.074,13.972 18.954,13.662 18.594,13.792C18.234,13.922 18.234,13.942 17.864,14.082C17.494,14.222 17.494,14.202 17.124,14.332C16.754,14.462 16.754,14.462 16.384,14.602C16.014,14.742 16.034,14.782 15.664,14.912C15.344,15.032 15.244,15.532 15.124,15.852C14.984,16.222 14.874,16.172 14.734,16.542C14.594,16.912 14.504,16.872 14.364,17.232C14.224,17.592 14.524,17.702 14.394,18.072C14.264,18.442 14.254,18.442 14.124,18.802C13.994,19.162 13.704,19.062 13.564,19.432C13.424,19.802 13.474,19.812 13.334,20.182C13.194,20.552 13.244,20.562 13.104,20.932C13.014,21.182 12.874,21.342 12.684,21.472C12.484,21.612 12.274,21.452 12.034,21.452C11.794,21.452 11.484,21.762 11.274,21.622C11.084,21.492 10.924,21.232 10.824,20.982C10.684,20.612 10.824,20.562 10.694,20.202C10.564,19.842 10.764,19.762 10.624,19.402C10.484,19.042 10.174,19.152 10.034,18.792C9.894,18.432 9.874,18.432 9.734,18.072C9.594,17.712 9.664,17.682 9.524,17.312C9.384,16.942 9.394,16.942 9.254,16.572C9.114,16.202 9.074,16.222 8.944,15.852C8.824,15.532 8.624,15.282 8.304,15.162C7.934,15.022 7.914,15.092 7.554,14.952C7.194,14.812 7.264,14.622 6.894,14.482C6.524,14.342 6.494,14.442 6.134,14.302C5.774,14.162 5.784,14.122 5.414,13.992C5.044,13.862 5.024,13.912 4.664,13.772C4.304,13.632 4.244,13.772 3.874,13.632C3.504,13.492 3.524,13.452 3.154,13.322C2.904,13.232 2.854,12.912 2.724,12.722C2.584,12.522 2.594,12.342 2.594,12.112C2.594,11.882 2.354,11.542 2.494,11.332C2.624,11.142 3.034,11.302 3.274,11.212C3.644,11.072 3.574,10.912 3.944,10.772C4.314,10.632 4.234,10.432 4.604,10.302C4.974,10.172 5.084,10.492 5.454,10.352C5.824,10.212 5.824,10.232 6.194,10.092C6.564,9.952 6.454,9.662 6.814,9.522C7.174,9.382 7.174,9.382 7.544,9.242C7.914,9.102 7.924,9.142 8.294,9.002C8.614,8.882 9.124,8.792 9.244,8.472C9.384,8.102 9.254,8.062 9.394,7.692C9.534,7.322 9.354,7.262 9.494,6.902C9.634,6.542 9.544,6.502 9.684,6.142C9.824,5.782 10.014,5.852 10.154,5.482C10.294,5.112 10.014,5.012 10.154,4.652C10.294,4.292 10.554,4.392 10.734,4.042C10.914,3.692 10.914,3.682 11.054,3.312V3.342Z" />
9+
<path
10+
android:fillColor="#00000000"
11+
android:pathData="M11.054,3.342C11.144,3.092 11.074,2.702 11.254,2.572C11.454,2.432 11.804,2.342 12.044,2.342C12.284,2.342 12.434,2.712 12.634,2.852C12.824,2.982 13.244,2.982 13.334,3.222C13.474,3.592 13.264,3.662 13.404,4.032C13.544,4.402 13.654,4.352 13.784,4.722C13.914,5.092 14.054,5.032 14.194,5.402C14.334,5.772 14.294,5.782 14.424,6.152C14.554,6.522 14.234,6.642 14.374,7.002C14.514,7.362 14.464,7.392 14.594,7.752C14.724,8.112 14.834,8.082 14.974,8.452C15.094,8.772 15.414,9.042 15.734,9.162C16.104,9.302 16.124,9.242 16.484,9.372C16.844,9.502 16.784,9.672 17.154,9.802C17.524,9.932 17.544,9.872 17.904,10.002C18.264,10.132 18.394,9.802 18.764,9.942C19.134,10.082 19.124,10.082 19.494,10.222C19.864,10.362 19.714,10.762 20.084,10.902C20.454,11.042 20.474,10.992 20.834,11.122C21.084,11.212 21.204,11.332 21.334,11.512C21.474,11.712 21.424,11.882 21.424,12.122C21.424,12.362 21.644,12.652 21.504,12.852C21.374,13.042 21.154,13.242 20.904,13.332C20.534,13.472 20.584,13.592 20.224,13.732C19.864,13.872 19.794,13.692 19.434,13.832C19.074,13.972 18.954,13.662 18.594,13.792C18.234,13.922 18.234,13.942 17.864,14.082C17.494,14.222 17.494,14.202 17.124,14.332C16.754,14.462 16.754,14.462 16.384,14.602C16.014,14.742 16.034,14.782 15.664,14.912C15.344,15.032 15.244,15.532 15.124,15.852C14.984,16.222 14.874,16.172 14.734,16.542C14.594,16.912 14.504,16.872 14.364,17.232C14.224,17.592 14.524,17.702 14.394,18.072C14.264,18.442 14.254,18.442 14.124,18.802C13.994,19.162 13.704,19.062 13.564,19.432C13.424,19.802 13.474,19.812 13.334,20.182C13.194,20.552 13.244,20.562 13.104,20.932C13.014,21.182 12.874,21.342 12.684,21.472C12.484,21.612 12.274,21.452 12.034,21.452C11.794,21.452 11.484,21.762 11.274,21.622C11.084,21.492 10.924,21.232 10.824,20.982C10.684,20.612 10.824,20.562 10.694,20.202C10.564,19.842 10.764,19.762 10.624,19.402C10.484,19.042 10.174,19.152 10.034,18.792C9.894,18.432 9.874,18.432 9.734,18.072C9.594,17.712 9.664,17.682 9.524,17.312C9.384,16.942 9.394,16.942 9.254,16.572C9.114,16.202 9.074,16.222 8.944,15.852C8.824,15.532 8.624,15.282 8.304,15.162C7.934,15.022 7.914,15.092 7.554,14.952C7.194,14.812 7.264,14.622 6.894,14.482C6.524,14.342 6.494,14.442 6.134,14.302C5.774,14.162 5.784,14.122 5.414,13.992C5.044,13.862 5.024,13.912 4.664,13.772C4.304,13.632 4.244,13.772 3.874,13.632C3.504,13.492 3.524,13.452 3.154,13.322C2.904,13.232 2.854,12.912 2.724,12.722C2.584,12.522 2.594,12.342 2.594,12.112C2.594,11.882 2.354,11.542 2.494,11.332C2.624,11.142 3.034,11.302 3.274,11.212C3.644,11.072 3.574,10.912 3.944,10.772C4.314,10.632 4.234,10.432 4.604,10.302C4.974,10.172 5.084,10.492 5.454,10.352C5.824,10.212 5.824,10.232 6.194,10.092C6.564,9.952 6.454,9.662 6.814,9.522C7.174,9.382 7.174,9.382 7.544,9.242C7.914,9.102 7.924,9.142 8.294,9.002C8.614,8.882 9.124,8.792 9.244,8.472C9.384,8.102 9.254,8.062 9.394,7.692C9.534,7.322 9.354,7.262 9.494,6.902C9.634,6.542 9.544,6.502 9.684,6.142C9.824,5.782 10.014,5.852 10.154,5.482C10.294,5.112 10.014,5.012 10.154,4.652C10.294,4.292 10.554,4.392 10.734,4.042C10.914,3.692 10.914,3.682 11.054,3.312V3.342Z"
12+
android:strokeWidth="2"
13+
android:strokeColor="#FFBF00"
14+
android:strokeLineJoin="round" />
15+
</vector>

presentation/src/main/java/com/threegap/bitnagil/presentation/routinelist/RoutineListScreen.kt

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.threegap.bitnagil.presentation.routinelist
33
import androidx.compose.foundation.background
44
import androidx.compose.foundation.layout.Arrangement
55
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.PaddingValues
67
import androidx.compose.foundation.layout.Spacer
78
import androidx.compose.foundation.layout.fillMaxSize
89
import androidx.compose.foundation.layout.height
@@ -11,64 +12,99 @@ import androidx.compose.foundation.layout.statusBarsPadding
1112
import androidx.compose.foundation.lazy.LazyColumn
1213
import androidx.compose.runtime.Composable
1314
import androidx.compose.runtime.getValue
14-
import androidx.compose.runtime.mutableStateOf
15-
import androidx.compose.runtime.remember
16-
import androidx.compose.runtime.setValue
1715
import androidx.compose.ui.Alignment
1816
import androidx.compose.ui.Modifier
1917
import androidx.compose.ui.tooling.preview.Preview
2018
import androidx.compose.ui.unit.dp
19+
import androidx.hilt.navigation.compose.hiltViewModel
20+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2121
import com.threegap.bitnagil.designsystem.BitnagilTheme
2222
import com.threegap.bitnagil.designsystem.component.block.BitnagilTopBar
23+
import com.threegap.bitnagil.presentation.common.flow.collectAsEffect
2324
import com.threegap.bitnagil.presentation.home.util.getCurrentWeekDays
25+
import com.threegap.bitnagil.presentation.routinelist.component.template.DeleteConfirmBottomSheet
2426
import com.threegap.bitnagil.presentation.routinelist.component.template.RoutineDetailsCard
2527
import com.threegap.bitnagil.presentation.routinelist.component.template.WeeklyDatePicker
28+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListIntent
29+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListSideEffect
30+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListState
2631
import java.time.LocalDate
2732

2833
@Composable
2934
fun RoutineListScreenContainer(
30-
35+
navigateToBack: () -> Unit,
36+
viewModel: RoutineListViewModel = hiltViewModel(),
3137
) {
32-
RoutineListScreen()
38+
val uiState by viewModel.stateFlow.collectAsStateWithLifecycle()
39+
40+
viewModel.sideEffectFlow.collectAsEffect { sideEffect ->
41+
when (sideEffect) {
42+
is RoutineListSideEffect.NavigateToBack -> navigateToBack()
43+
}
44+
}
45+
46+
if (uiState.deleteConfirmBottomSheetVisible) {
47+
DeleteConfirmBottomSheet(
48+
onDismissRequest = { viewModel.sendIntent(RoutineListIntent.HideDeleteConfirmBottomSheet) },
49+
)
50+
}
51+
52+
RoutineListScreen(
53+
uiState = uiState,
54+
onDateSelect = { selectedDate ->
55+
viewModel.sendIntent(RoutineListIntent.OnDateSelect(selectedDate))
56+
},
57+
onShowDeleteConfirmBottomSheet = {
58+
viewModel.sendIntent(RoutineListIntent.ShowDeleteConfirmBottomSheet)
59+
},
60+
onBackClick = {
61+
viewModel.sendIntent(RoutineListIntent.NavigateToBack)
62+
},
63+
)
3364
}
3465

3566
@Composable
3667
private fun RoutineListScreen(
37-
modifier: Modifier = Modifier
68+
uiState: RoutineListState,
69+
onDateSelect: (LocalDate) -> Unit,
70+
onShowDeleteConfirmBottomSheet: () -> Unit,
71+
onBackClick: () -> Unit,
72+
modifier: Modifier = Modifier,
3873
) {
3974
Column(
4075
modifier = modifier
4176
.fillMaxSize()
4277
.background(BitnagilTheme.colors.coolGray99)
4378
.statusBarsPadding(),
44-
horizontalAlignment = Alignment.CenterHorizontally
79+
horizontalAlignment = Alignment.CenterHorizontally,
4580
) {
4681
BitnagilTopBar(
4782
title = "루틴리스트",
4883
showBackButton = true,
49-
onBackClick = {},
84+
onBackClick = onBackClick,
5085
)
5186

52-
var selectedDate by remember { mutableStateOf<LocalDate>(LocalDate.now()) }
53-
5487
Spacer(modifier = Modifier.height(4.dp))
5588

5689
WeeklyDatePicker(
57-
selectedDate = selectedDate,
58-
onDateSelect = { selectedDate = it },
59-
weeklyDates = selectedDate.getCurrentWeekDays(),
90+
selectedDate = uiState.selectedDate,
91+
onDateSelect = onDateSelect,
92+
weeklyDates = uiState.selectedDate.getCurrentWeekDays(),
6093
modifier = Modifier
61-
.padding(vertical = 10.dp, horizontal = 16.dp)
94+
.padding(vertical = 10.dp, horizontal = 16.dp),
6295
)
6396

6497
LazyColumn(
6598
modifier = Modifier
6699
.fillMaxSize()
67100
.padding(horizontal = 16.dp),
68-
verticalArrangement = Arrangement.spacedBy(12.dp)
101+
verticalArrangement = Arrangement.spacedBy(12.dp),
102+
contentPadding = PaddingValues(bottom = 10.dp),
69103
) {
70-
items(10) {
71-
RoutineDetailsCard()
104+
items(5) {
105+
RoutineDetailsCard(
106+
onDeleteClick = onShowDeleteConfirmBottomSheet,
107+
)
72108
}
73109
}
74110
}
@@ -77,5 +113,10 @@ private fun RoutineListScreen(
77113
@Preview
78114
@Composable
79115
private fun RoutineListScreenPreview() {
80-
RoutineListScreen()
116+
RoutineListScreen(
117+
uiState = RoutineListState(),
118+
onDateSelect = {},
119+
onShowDeleteConfirmBottomSheet = {},
120+
onBackClick = {},
121+
)
81122
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.threegap.bitnagil.presentation.routinelist
2+
3+
import androidx.lifecycle.SavedStateHandle
4+
import com.threegap.bitnagil.domain.routine.usecase.FetchWeeklyRoutinesUseCase
5+
import com.threegap.bitnagil.presentation.common.mviviewmodel.MviViewModel
6+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListIntent
7+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListSideEffect
8+
import com.threegap.bitnagil.presentation.routinelist.model.RoutineListState
9+
import dagger.hilt.android.lifecycle.HiltViewModel
10+
import org.orbitmvi.orbit.syntax.simple.SimpleSyntax
11+
import javax.inject.Inject
12+
13+
@HiltViewModel
14+
class RoutineListViewModel @Inject constructor(
15+
savedStateHandle: SavedStateHandle,
16+
private val fetchWeeklyRoutinesUseCase: FetchWeeklyRoutinesUseCase,
17+
) : MviViewModel<RoutineListState, RoutineListSideEffect, RoutineListIntent>(
18+
savedStateHandle = savedStateHandle,
19+
initState = RoutineListState(),
20+
) {
21+
override suspend fun SimpleSyntax<RoutineListState, RoutineListSideEffect>.reduceState(
22+
intent: RoutineListIntent,
23+
state: RoutineListState,
24+
): RoutineListState? {
25+
val newState = when (intent) {
26+
is RoutineListIntent.OnDateSelect -> state.copy(selectedDate = intent.date)
27+
is RoutineListIntent.ShowDeleteConfirmBottomSheet -> state.copy(deleteConfirmBottomSheetVisible = true)
28+
is RoutineListIntent.HideDeleteConfirmBottomSheet -> state.copy(deleteConfirmBottomSheetVisible = false)
29+
30+
is RoutineListIntent.NavigateToBack -> {
31+
sendSideEffect(RoutineListSideEffect.NavigateToBack)
32+
null
33+
}
34+
}
35+
36+
return newState
37+
}
38+
}

presentation/src/main/java/com/threegap/bitnagil/presentation/routinelist/component/template/RoutineDetailsCard.kt

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import com.threegap.bitnagil.designsystem.component.atom.BitnagilIconButton
2323

2424
@Composable
2525
fun RoutineDetailsCard(
26-
modifier: Modifier = Modifier
26+
onDeleteClick: () -> Unit,
27+
modifier: Modifier = Modifier,
2728
) {
2829
Column(
2930
modifier = modifier
@@ -32,29 +33,29 @@ fun RoutineDetailsCard(
3233
shape = RoundedCornerShape(12.dp),
3334
)
3435
.fillMaxWidth()
35-
.padding(vertical = 14.dp)
36+
.padding(vertical = 14.dp),
3637
) {
3738
Row(
3839
modifier = Modifier
3940
.padding(start = 16.dp, end = 2.dp),
40-
verticalAlignment = Alignment.CenterVertically
41+
verticalAlignment = Alignment.CenterVertically,
4142
) {
4243
BitnagilIcon(
4344
id = R.drawable.ic_wakeup,
4445
tint = null,
4546
modifier = Modifier
4647
.background(
4748
color = BitnagilTheme.colors.orange25,
48-
shape = RoundedCornerShape(4.dp)
49+
shape = RoundedCornerShape(4.dp),
4950
)
50-
.padding(4.dp)
51+
.padding(4.dp),
5152
)
5253

5354
Text(
5455
text = "개운하게 일어나기",
5556
color = BitnagilTheme.colors.coolGray10,
5657
style = BitnagilTheme.typography.body1SemiBold,
57-
modifier = Modifier.padding(start = 10.dp)
58+
modifier = Modifier.padding(start = 10.dp),
5859
)
5960

6061
Spacer(modifier = Modifier.weight(1f))
@@ -63,27 +64,27 @@ fun RoutineDetailsCard(
6364
id = R.drawable.ic_edit,
6465
onClick = { /*TODO*/ },
6566
tint = null,
66-
paddingValues = PaddingValues(12.dp)
67+
paddingValues = PaddingValues(12.dp),
6768
)
6869

6970
BitnagilIconButton(
7071
id = R.drawable.ic_trash,
71-
onClick = { /*TODO*/ },
72+
onClick = onDeleteClick,
7273
tint = null,
73-
paddingValues = PaddingValues(12.dp)
74+
paddingValues = PaddingValues(12.dp),
7475
)
7576
}
7677

7778
HorizontalDivider(
7879
thickness = 1.dp,
7980
color = BitnagilTheme.colors.coolGray97,
80-
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp)
81+
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
8182
)
8283

8384
Column(
8485
modifier = Modifier
8586
.padding(horizontal = 16.dp),
86-
verticalArrangement = Arrangement.spacedBy(2.dp)
87+
verticalArrangement = Arrangement.spacedBy(2.dp),
8788
) {
8889
Text(
8990
text = "세부 루틴",
@@ -110,13 +111,13 @@ fun RoutineDetailsCard(
110111
HorizontalDivider(
111112
thickness = 1.dp,
112113
color = BitnagilTheme.colors.coolGray97,
113-
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp)
114+
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
114115
)
115116

116117
Column(
117118
modifier = Modifier
118119
.padding(horizontal = 16.dp),
119-
verticalArrangement = Arrangement.spacedBy(2.dp)
120+
verticalArrangement = Arrangement.spacedBy(2.dp),
120121
) {
121122
Text(
122123
text = "반복:",
@@ -140,5 +141,7 @@ fun RoutineDetailsCard(
140141
@Preview
141142
@Composable
142143
private fun RoutineDetailsCardPreview() {
143-
RoutineDetailsCard()
144+
RoutineDetailsCard(
145+
onDeleteClick = {},
146+
)
144147
}

presentation/src/main/java/com/threegap/bitnagil/presentation/routinelist/component/template/WeeklyDatePicker.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ fun WeeklyDatePicker(
4545
isSelected = selectedDate == date,
4646
isToday = date == LocalDate.now(),
4747
onDateClick = { onDateSelect(date) },
48-
modifier = Modifier.padding(bottom = 18.dp)
48+
modifier = Modifier.padding(bottom = 18.dp),
4949
)
5050
}
5151
}

0 commit comments

Comments
 (0)