Skip to content

Commit 2217d36

Browse files
committed
Feat: HomeScreen 구현
1 parent afecd8f commit 2217d36

2 files changed

Lines changed: 243 additions & 13 deletions

File tree

app/src/main/java/com/threegap/bitnagil/MainNavHost.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import androidx.compose.ui.Modifier
55
import androidx.navigation.compose.NavHost
66
import androidx.navigation.compose.composable
77
import androidx.navigation.toRoute
8-
import com.threegap.bitnagil.presentation.home.HomeScreen
8+
import com.threegap.bitnagil.presentation.home.HomeScreenContainer
99
import com.threegap.bitnagil.presentation.intro.IntroScreenContainer
1010
import com.threegap.bitnagil.presentation.login.LoginScreenContainer
1111
import com.threegap.bitnagil.presentation.splash.SplashScreenContainer
@@ -66,7 +66,7 @@ fun MainNavHost(
6666
}
6767

6868
composable<Route.Home> {
69-
HomeScreen()
69+
HomeScreenContainer()
7070
}
7171

7272
composable<Route.WebView> {
Lines changed: 241 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,264 @@
11
package com.threegap.bitnagil.presentation.home
22

33
import androidx.compose.foundation.background
4-
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.Box
56
import androidx.compose.foundation.layout.Column
7+
import androidx.compose.foundation.layout.Spacer
68
import androidx.compose.foundation.layout.fillMaxSize
7-
import androidx.compose.material3.Text
9+
import androidx.compose.foundation.layout.fillMaxWidth
10+
import androidx.compose.foundation.layout.height
11+
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
13+
import androidx.compose.foundation.lazy.LazyColumn
14+
import androidx.compose.foundation.shape.RoundedCornerShape
15+
import androidx.compose.material.icons.Icons
16+
import androidx.compose.material.icons.filled.Menu
17+
import androidx.compose.material3.Icon
818
import androidx.compose.runtime.Composable
19+
import androidx.compose.runtime.getValue
920
import androidx.compose.ui.Alignment
1021
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.geometry.Offset
23+
import androidx.compose.ui.graphics.Brush
1124
import androidx.compose.ui.graphics.Color
25+
import androidx.compose.ui.input.nestedscroll.nestedScroll
1226
import androidx.compose.ui.tooling.preview.Preview
27+
import androidx.compose.ui.unit.dp
28+
import androidx.compose.ui.zIndex
29+
import androidx.hilt.navigation.compose.hiltViewModel
30+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1331
import com.threegap.bitnagil.designsystem.BitnagilTheme
32+
import com.threegap.bitnagil.presentation.home.component.template.DeleteConfirmDialog
33+
import com.threegap.bitnagil.presentation.home.component.template.CollapsibleHomeHeader
34+
import com.threegap.bitnagil.presentation.home.component.template.RoutineDetailsBottomSheet
35+
import com.threegap.bitnagil.presentation.home.component.template.RoutineEmptyView
36+
import com.threegap.bitnagil.presentation.home.component.template.RoutineSection
37+
import com.threegap.bitnagil.presentation.home.component.template.RoutineSortBottomSheet
38+
import com.threegap.bitnagil.presentation.home.component.template.WeeklyDatePicker
39+
import com.threegap.bitnagil.presentation.home.model.HomeIntent
40+
import com.threegap.bitnagil.presentation.home.model.HomeState
41+
import com.threegap.bitnagil.presentation.home.model.RoutineUiModel
42+
import com.threegap.bitnagil.presentation.home.util.rememberCollapsibleHeaderState
43+
import java.time.LocalDate
1444

1545
@Composable
16-
fun HomeScreen(modifier: Modifier = Modifier) {
17-
Column(
18-
verticalArrangement = Arrangement.Center,
19-
horizontalAlignment = Alignment.CenterHorizontally,
46+
fun HomeScreenContainer(
47+
viewModel: HomeViewModel = hiltViewModel(),
48+
) {
49+
val uiState by viewModel.stateFlow.collectAsStateWithLifecycle()
50+
51+
if (uiState.routineSortBottomSheetVisible) {
52+
RoutineSortBottomSheet(
53+
currentSortType = uiState.currentSortType,
54+
onSortTypeChange = { sortType ->
55+
viewModel.sendIntent(HomeIntent.OnSortTypeChange(sortType))
56+
},
57+
onDismiss = {
58+
viewModel.sendIntent(HomeIntent.HideRoutineSortBottomSheet)
59+
},
60+
)
61+
}
62+
63+
uiState.selectedRoutine?.let { routine ->
64+
if (uiState.routineDetailsBottomSheetVisible) {
65+
RoutineDetailsBottomSheet(
66+
routine = routine,
67+
onDismiss = { viewModel.sendIntent(HomeIntent.HideRoutineDetailsBottomSheet) },
68+
// TODO: 수정 화면으로 네비게이션
69+
onEdit = {},
70+
onDelete = {
71+
if (routine.repeatDay.isEmpty()) {
72+
viewModel.deleteRoutine(routine.routineId)
73+
} else {
74+
viewModel.sendIntent(HomeIntent.ShowDeleteConfirmDialog(routine))
75+
}
76+
},
77+
)
78+
}
79+
}
80+
81+
uiState.deletingRoutine?.let { routine ->
82+
if (uiState.showDeleteConfirmDialog) {
83+
DeleteConfirmDialog(
84+
onDeleteToday = {
85+
viewModel.deleteRoutine(routine.routineId)
86+
viewModel.sendIntent(HomeIntent.HideDeleteConfirmDialog)
87+
},
88+
onDeleteAll = {
89+
viewModel.sendIntent(HomeIntent.HideDeleteConfirmDialog)
90+
},
91+
onDismiss = {
92+
viewModel.sendIntent(HomeIntent.HideDeleteConfirmDialog)
93+
},
94+
)
95+
}
96+
}
97+
98+
HomeScreen(
99+
uiState = uiState,
100+
onDateSelect = { date ->
101+
viewModel.sendIntent(HomeIntent.OnDateSelect(date))
102+
},
103+
onPreviousWeekClick = {
104+
viewModel.sendIntent(HomeIntent.OnPreviousWeekClick)
105+
},
106+
onNextWeekClick = {
107+
viewModel.sendIntent(HomeIntent.OnNextWeekClick)
108+
},
109+
onRoutineCompletionToggle = { routineId, isCompleted ->
110+
viewModel.sendIntent(HomeIntent.OnRoutineCompletionToggle(routineId, isCompleted))
111+
},
112+
onSubRoutineCompletionToggle = { routineId, subRoutineId, isCompleted ->
113+
viewModel.sendIntent(HomeIntent.OnSubRoutineCompletionToggle(routineId, subRoutineId, isCompleted))
114+
},
115+
onShowRoutineSortBottomSheet = {
116+
viewModel.sendIntent(HomeIntent.ShowRoutineSortBottomSheet)
117+
},
118+
onShowRoutineDetailsBottomSheet = { routine ->
119+
viewModel.sendIntent(HomeIntent.ShowRoutineDetailsBottomSheet(routine))
120+
},
121+
)
122+
}
123+
124+
@Composable
125+
private fun HomeScreen(
126+
uiState: HomeState,
127+
onDateSelect: (LocalDate) -> Unit,
128+
onPreviousWeekClick: () -> Unit,
129+
onNextWeekClick: () -> Unit,
130+
onRoutineCompletionToggle: (String, Boolean) -> Unit,
131+
onSubRoutineCompletionToggle: (String, String, Boolean) -> Unit,
132+
onShowRoutineSortBottomSheet: () -> Unit,
133+
onShowRoutineDetailsBottomSheet: (RoutineUiModel) -> Unit,
134+
modifier: Modifier = Modifier,
135+
) {
136+
val collapsibleHeaderState = rememberCollapsibleHeaderState()
137+
138+
Box(
20139
modifier = modifier
21140
.fillMaxSize()
22-
.background(Color.White),
141+
.background(
142+
brush = Brush.linearGradient(
143+
colors = listOf(
144+
Color(0xFFFFEADF),
145+
BitnagilTheme.colors.lightBlue75,
146+
),
147+
start = Offset(0f, 0f),
148+
end = Offset(collapsibleHeaderState.screenHeight.value, collapsibleHeaderState.screenWidth.value * 2),
149+
),
150+
),
23151
) {
24-
Text(text = "여긴 홈 화면")
152+
Column {
153+
Spacer(modifier = Modifier.height(collapsibleHeaderState.currentHeaderHeight))
154+
155+
WeeklyDatePicker(
156+
selectedDate = uiState.selectedDate,
157+
weeklyDates = uiState.currentWeeks,
158+
onDateSelect = onDateSelect,
159+
onPreviousWeekClick = onPreviousWeekClick,
160+
onNextWeekClick = onNextWeekClick,
161+
modifier = Modifier
162+
.background(
163+
color = BitnagilTheme.colors.white,
164+
shape = RoundedCornerShape(
165+
topStart = 20.dp,
166+
topEnd = 20.dp,
167+
),
168+
),
169+
)
170+
171+
LazyColumn(
172+
state = collapsibleHeaderState.lazyListState,
173+
modifier = Modifier
174+
.fillMaxSize()
175+
.background(BitnagilTheme.colors.white)
176+
.nestedScroll(collapsibleHeaderState.nestedScrollConnection),
177+
) {
178+
if (uiState.selectedDateRoutines.isEmpty()) {
179+
item {
180+
RoutineEmptyView(
181+
// todo: 루린 등록 화면으로 네비게이션
182+
onRegisterRoutineClick = {},
183+
modifier = Modifier
184+
.fillMaxSize()
185+
.padding(top = 62.dp),
186+
)
187+
}
188+
} else {
189+
uiState.selectedDateRoutines.forEachIndexed { index, routine ->
190+
item(
191+
key = "${routine.routineId}_${uiState.selectedDate}",
192+
) {
193+
Box(
194+
modifier = Modifier.fillMaxWidth(),
195+
) {
196+
RoutineSection(
197+
routine = routine,
198+
onRoutineToggle = { isCompleted ->
199+
onRoutineCompletionToggle(
200+
routine.routineId,
201+
isCompleted,
202+
)
203+
},
204+
onSubRoutineToggle = { subRoutineId, isCompleted ->
205+
onSubRoutineCompletionToggle(
206+
routine.routineId,
207+
subRoutineId,
208+
isCompleted,
209+
)
210+
},
211+
onMoreClick = {
212+
onShowRoutineDetailsBottomSheet(routine)
213+
},
214+
modifier = Modifier
215+
.padding(top = 23.dp, bottom = 10.dp)
216+
.padding(horizontal = 16.dp),
217+
)
218+
219+
if (index == 0) {
220+
// todo: 아이콘 변경하기
221+
Icon(
222+
imageVector = Icons.Default.Menu,
223+
contentDescription = null,
224+
modifier = Modifier
225+
.align(Alignment.TopEnd)
226+
.padding(end = 4.dp)
227+
.clickable { onShowRoutineSortBottomSheet() }
228+
.padding(8.dp)
229+
.size(24.dp)
230+
.zIndex(1f),
231+
)
232+
}
233+
}
234+
}
235+
}
236+
}
237+
item {
238+
Spacer(modifier = Modifier.height(110.dp))
239+
}
240+
}
241+
}
242+
243+
CollapsibleHomeHeader(
244+
userName = "대현",
245+
collapsibleHeaderState = collapsibleHeaderState,
246+
onEmotionRecordClick = {},
247+
)
25248
}
26249
}
27250

28251
@Preview
29252
@Composable
30253
private fun HomeScreenPreview() {
31-
BitnagilTheme {
32-
HomeScreen()
33-
}
254+
HomeScreen(
255+
uiState = HomeState(),
256+
onDateSelect = {},
257+
onPreviousWeekClick = {},
258+
onNextWeekClick = {},
259+
onRoutineCompletionToggle = { _, _ -> },
260+
onSubRoutineCompletionToggle = { _, _, _ -> },
261+
onShowRoutineSortBottomSheet = {},
262+
onShowRoutineDetailsBottomSheet = {},
263+
)
34264
}

0 commit comments

Comments
 (0)