Skip to content

Commit 83e9a8c

Browse files
committed
#8 [UI] 시간 선택형 타임테이블 구현
1 parent a2e0c29 commit 83e9a8c

File tree

14 files changed

+287
-191
lines changed

14 files changed

+287
-191
lines changed

core/src/main/java/com/sopt/core/designsystem/component/dialog/AppointmentDialog.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ fun AppointmentDialog(
4545
.background(
4646
shape = CircleShape,
4747
color = NoostakTheme.colors.gray200
48-
),
48+
)
4949
)
5050
Spacer(modifier = Modifier.height(16.dp))
5151
Text(
5252
text = description,
5353
color = NoostakTheme.colors.gray900,
5454
style = NoostakTheme.typography.b2Regular,
55-
textAlign = TextAlign.Center,
55+
textAlign = TextAlign.Center
5656
)
5757
Spacer(modifier = Modifier.height(20.dp))
5858
Button(
@@ -62,20 +62,20 @@ fun AppointmentDialog(
6262
),
6363
shape = RoundedCornerShape(6.dp),
6464
onClick = onConfirmButtonClick,
65-
interactionSource = NoRippleInteractionSource,
65+
interactionSource = NoRippleInteractionSource
6666
) {
6767
Text(
6868
text = confirmButtonText,
6969
color = NoostakTheme.colors.white,
70-
textAlign = TextAlign.Center,
70+
textAlign = TextAlign.Center
7171
)
7272
}
7373
Spacer(modifier = Modifier.height(6.5.dp))
7474
Text(
7575
modifier = Modifier.noRippleClickable { onDismissRequest() },
7676
text = dismissText,
7777
color = NoostakTheme.colors.gray700,
78-
style = NoostakTheme.typography.b2Regular,
78+
style = NoostakTheme.typography.b2Regular
7979
)
8080
}
8181
}

core/src/main/java/com/sopt/core/designsystem/component/dialog/BaseDialog.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,14 @@ package com.sopt.core.designsystem.component.dialog
22

33
import androidx.compose.foundation.background
44
import androidx.compose.foundation.layout.Box
5-
import androidx.compose.foundation.layout.padding
65
import androidx.compose.foundation.layout.wrapContentSize
76
import androidx.compose.foundation.shape.RoundedCornerShape
87
import androidx.compose.runtime.Composable
98
import androidx.compose.ui.Modifier
109
import androidx.compose.ui.graphics.Color
11-
import androidx.compose.ui.tooling.preview.Preview
1210
import androidx.compose.ui.unit.Dp
13-
import androidx.compose.ui.unit.dp
1411
import androidx.compose.ui.window.Dialog
1512
import androidx.compose.ui.window.DialogProperties
16-
import com.sopt.core.designsystem.theme.NoostakAndroidTheme
1713

1814
@Composable
1915
fun BaseDialog(
@@ -43,4 +39,3 @@ fun BaseDialog(
4339
}
4440
}
4541
}
46-
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package com.sopt.core.designsystem.component.timetable
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.border
5+
import androidx.compose.foundation.layout.Box
6+
import androidx.compose.foundation.layout.defaultMinSize
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.foundation.lazy.grid.GridCells
9+
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
10+
import androidx.compose.foundation.shape.RoundedCornerShape
11+
import androidx.compose.material3.Text
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.mutableStateListOf
14+
import androidx.compose.runtime.remember
15+
import androidx.compose.ui.Alignment
16+
import androidx.compose.ui.Modifier
17+
import androidx.compose.ui.graphics.Color
18+
import androidx.compose.ui.text.style.TextAlign
19+
import androidx.compose.ui.unit.dp
20+
import com.sopt.core.designsystem.theme.NoostakTheme
21+
import com.sopt.core.extension.noRippleClickable
22+
import com.sopt.domain.entity.AvailableTimeEntity
23+
import com.sopt.domain.entity.TimeEntity
24+
import com.sopt.domain.entity.TimeTableEntity
25+
26+
@Composable
27+
fun NoostakEditableTimeTable(
28+
data: TimeTableEntity,
29+
modifier: Modifier = Modifier,
30+
onSelectionChange: (List<TimeEntity>) -> Unit
31+
) {
32+
val days = data.timeEntity.size
33+
val timeSlots = calculateTimeSlots(data.startTime, data.endTime)
34+
val selectedCells = remember { mutableStateListOf<Pair<Int, Int>>() } // Row, Column 저장
35+
36+
LazyVerticalGrid(
37+
modifier = modifier
38+
.border(
39+
width = 1.dp,
40+
color = NoostakTheme.colors.gray200,
41+
shape = RoundedCornerShape(8.dp)
42+
),
43+
columns = GridCells.Fixed(days + 1)
44+
) {
45+
items((days + 1) * (timeSlots + 1)) { index ->
46+
val rowIndex = index / (days + 1)
47+
val columnIndex = index % (days + 1)
48+
49+
val cellType = determineCellType(rowIndex, columnIndex)
50+
val isSelected = selectedCells.contains(rowIndex to columnIndex)
51+
val backgroundColor =
52+
getEditableBackgroundColor(cellType, rowIndex, columnIndex, isSelected)
53+
val text = getCellText(cellType, rowIndex, columnIndex, data)
54+
55+
NoostakEditableTimeTableBox(
56+
index = index,
57+
days = days,
58+
timeSlots = timeSlots,
59+
backgroundColor = backgroundColor,
60+
text = text,
61+
onClick = {
62+
if (cellType == CellType.Data) {
63+
val cell = rowIndex to columnIndex
64+
if (selectedCells.contains(cell)) {
65+
selectedCells.remove(cell)
66+
} else {
67+
selectedCells.add(cell)
68+
}
69+
onSelectionChange(
70+
selectedCells.toTimeEntities(
71+
data.startTime,
72+
data.timeEntity
73+
)
74+
)
75+
}
76+
}
77+
)
78+
}
79+
}
80+
}
81+
82+
@Composable
83+
fun getEditableBackgroundColor(
84+
cellType: CellType,
85+
rowIndex: Int,
86+
columnIndex: Int,
87+
isSelected: Boolean
88+
): Color {
89+
return when (cellType) {
90+
CellType.Blank, CellType.DateHeader, CellType.TimeHeader -> Color.Transparent
91+
CellType.Data -> if (isSelected) NoostakTheme.colors.blue400 else Color.Transparent
92+
}
93+
}
94+
95+
@Composable
96+
fun NoostakEditableTimeTableBox(
97+
index: Int,
98+
days: Int,
99+
timeSlots: Int,
100+
backgroundColor: Color,
101+
text: String,
102+
onClick: () -> Unit
103+
) {
104+
val shape = when (index) {
105+
0 -> RoundedCornerShape(topStart = 10.dp)
106+
days -> RoundedCornerShape(topEnd = 10.dp)
107+
(days + 1) * timeSlots -> RoundedCornerShape(bottomStart = 10.dp)
108+
(days + 1) * (timeSlots + 1) - 1 -> RoundedCornerShape(bottomEnd = 10.dp)
109+
else -> RoundedCornerShape(0.dp)
110+
}
111+
112+
Box(
113+
modifier = Modifier
114+
.border(
115+
width = 0.5.dp,
116+
color = NoostakTheme.colors.gray200,
117+
shape = shape
118+
)
119+
.background(
120+
color = backgroundColor,
121+
shape = shape
122+
)
123+
.defaultMinSize(minWidth = 42.dp, minHeight = 36.dp)
124+
.noRippleClickable { onClick() },
125+
contentAlignment = Alignment.Center
126+
) {
127+
Text(
128+
modifier = Modifier.padding(horizontal = 5.dp, vertical = 3.dp),
129+
text = text,
130+
color = NoostakTheme.colors.gray600,
131+
style = NoostakTheme.typography.c4Regular,
132+
textAlign = TextAlign.Center,
133+
maxLines = 2
134+
)
135+
}
136+
}
137+
138+
fun List<Pair<Int, Int>>.toTimeEntities(
139+
startTime: String,
140+
timeEntityList: List<TimeEntity>
141+
): List<TimeEntity> {
142+
val startHour = startTime.split(":")[0].toInt()
143+
val groupedByColumn = this.groupBy { it.second }
144+
145+
return groupedByColumn.mapNotNull { (columnIndex, cells) ->
146+
val date = timeEntityList.getOrNull(columnIndex - 1)?.date ?: return@mapNotNull null
147+
val times = cells.map { cell ->
148+
val hour = startHour + (cell.first - 1)
149+
AvailableTimeEntity(
150+
startTime = "${"%02d".format(hour)}:00",
151+
endTime = "${"%02d".format(hour + 1)}:00"
152+
)
153+
}
154+
TimeEntity(date = date, times = times)
155+
}
156+
}

core/src/main/java/com/sopt/core/designsystem/component/timetable/NoostakTimeTableClickable.kt

Lines changed: 0 additions & 145 deletions
This file was deleted.

domain/src/main/java/com/sopt/domain/entity/TimeTableEntity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ data class TimeEntity(
1414
data class AvailableTimeEntity(
1515
val startTime: String,
1616
val endTime: String,
17-
val level: Int
18-
)
17+
val level: Int? = null
18+
)

presentation/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies {
5353
implementation(libs.ui)
5454
implementation(libs.ui.tooling.preview)
5555
implementation(libs.material3.compose)
56+
implementation(libs.constraintlayout.compose)
5657

5758
// Kotlin
5859
implementation(libs.kotlinx.coroutines.android)

presentation/src/main/java/com/sopt/presentation/appointment/AppointmentRoute.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ fun RecommendationHeaderItem(
243243
) {
244244
Text(
245245
modifier = Modifier.padding(bottom = 6.dp),
246-
text = "Best${priority}",
246+
text = "Best$priority",
247247
color = when (selectedItemIndex) {
248248
-1 -> NoostakTheme.colors.black
249249
priority -> NoostakTheme.colors.blue700

0 commit comments

Comments
 (0)