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

Feature/#35 timetable component #55

Merged
merged 19 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c508305
chore: design-system core:model ์˜์กด์„ฑ ์ถ”๊ฐ€
jinukeu Dec 6, 2023
735dd4a
chore: `@Stable` ์–ด๋…ธํ…Œ์ด์…˜ ์ถ”๊ฐ€ ๋ฐ startTime, endTime ํƒ€์ž… ๋ณ€๊ฒฝ
jinukeu Dec 6, 2023
2c0775e
design: TimetableCellColor ์ถ”๊ฐ€
jinukeu Dec 6, 2023
173cdac
refactor: Timetable property ํƒ€์ž… ๋ณ€๊ฒฝ
jinukeu Dec 6, 2023
da44d53
design: TimetableCell ์ปดํฌ๋„ŒํŠธ ์ถ”๊ฐ€
jinukeu Dec 6, 2023
a2d0f8f
design: TimetableCell ํ…Œํˆฌ๋ฆฌ ์ถ”๊ฐ€
jinukeu Dec 9, 2023
81f2508
rename: TimetableCell -> TimetableClassCell
jinukeu Dec 9, 2023
338575c
rename: TimetableEmptyCell ์ถ”๊ฐ€
jinukeu Dec 9, 2023
80196d2
feat: TimetableDay ์ถ”๊ฐ€
jinukeu Dec 9, 2023
0702546
feat: TimetableCellColumn ์ถ”๊ฐ€
jinukeu Dec 9, 2023
97c1c7a
refactor: TimetableCellColumn ํ•จ์ˆ˜ ๋ถ„๋ฆฌ
jinukeu Dec 10, 2023
c7ca182
refactor/#35: TimetableCellColumn ๋ฆฌํŒฉํ† ๋ง
jinukeu Dec 10, 2023
07d6e2c
Merge branch 'develop' into feature/timetable-component
jinukeu Dec 13, 2023
65b85dd
design/#35: design system ์ ์šฉ
jinukeu Dec 13, 2023
c212840
feat/#35: Timetable Component ์ถ”๊ฐ€
jinukeu Dec 13, 2023
c4a6011
refactor/#35: Timetable Component ๋ฆฌํŒฉํ† ๋ง
jinukeu Dec 13, 2023
5b98a3c
chore/#35: ktlint Format
jinukeu Dec 13, 2023
a3025ce
refactor/#35: TimetableCellColor.toHex() ๋ฉ”์„œ๋“œ์˜Cyclomatic Complexity 21โ€ฆ
jinukeu Dec 13, 2023
9e39161
docs/#35: Timetable.kt TODO ์ฃผ์„ ์ถ”๊ฐ€
jinukeu Dec 14, 2023
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
1 change: 1 addition & 0 deletions core/designsystem/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ android {
}

dependencies {
implementation(projects.core.model)
implementation(projects.core.ui)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.suwiki.core.designsystem.component.timetable

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.suwiki.core.designsystem.R
import com.suwiki.core.model.timetable.TimetableDay

internal val timetableHeightPerHour = 48.dp

internal val timetableBorderWidth = 0.5.dp

const val MINUTE60 = 60
const val MINUTE10 = 10

@Composable
internal fun TimetableDay.toText(): String {
return when (this) {
TimetableDay.MON -> stringResource(R.string.word_mon)
TimetableDay.TUE -> stringResource(R.string.word_tue)
TimetableDay.WED -> stringResource(R.string.word_wed)
TimetableDay.THU -> stringResource(R.string.word_thu)
TimetableDay.FRI -> stringResource(R.string.word_fri)
TimetableDay.SAT -> stringResource(R.string.word_sat)
TimetableDay.E_LEARNING -> stringResource(R.string.word_elearning)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
package com.suwiki.core.designsystem.component.timetable

import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.suwiki.core.designsystem.R
import com.suwiki.core.designsystem.component.timetable.cell.ELearningCell
import com.suwiki.core.designsystem.component.timetable.cell.TimetableCellType
import com.suwiki.core.designsystem.component.timetable.column.ClassColumn
import com.suwiki.core.designsystem.component.timetable.column.TimeColumn
import com.suwiki.core.designsystem.theme.Black
import com.suwiki.core.designsystem.theme.Gray95
import com.suwiki.core.designsystem.theme.GrayF6
import com.suwiki.core.designsystem.theme.SuwikiTheme
import com.suwiki.core.model.timetable.Timetable
import com.suwiki.core.model.timetable.TimetableCell
import com.suwiki.core.model.timetable.TimetableCellColor
import com.suwiki.core.model.timetable.TimetableDay
import com.suwiki.core.ui.extension.suwikiClickable
import kotlin.math.max

private const val MIN_MAX_PERIOD = 8

internal fun List<TimetableCell>.maxPeriod(): Int {
return max((maxOfOrNull { it.endPeriod }?.plus(1)) ?: MIN_MAX_PERIOD, MIN_MAX_PERIOD)
}

@Composable
fun Timetable(
modifier: Modifier = Modifier,
type: TimetableCellType = TimetableCellType.CLASSNAME_PROFESSOR_LOCATION,
timetable: Timetable,
onClickAdd: () -> Unit = {},
onClickHamburger: () -> Unit = {},
onClickSetting: () -> Unit = {},
onClickClassCell: (TimetableCell) -> Unit = { _ -> },
) {
val scrollState = rememberScrollState()
val maxPeriod by remember {
derivedStateOf { timetable.cellList.maxPeriod() }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

derivedStateOf ์‚ฌ์šฉํ•˜์‹  ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timetable.cellList์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ maxPeriod์˜ ๊ฐ’์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด์„œ derivedStateOf๋ฅผ ์‚ฌ์šฉํ–ˆ์–ด์š”~! derivedStateOf๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด timetable.cellList.maxPeriod์˜ ๊ฐ’์ด ์‹ค์ œ๋กœ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ์—๋งŒ val maxPeriod์˜ ๊ฐ’์ด ๋ฐ”๋€”๊ฑฐ๋ผ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค ์•„์ง ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณธ๊ฑด ์•„๋‹ˆ๋ผ์„œ ... ์ง€๊ธˆ์€ TODO ์ฃผ์„๋งŒ ๋‹ฌ์•„๋†“๊ณ  ๋ฐ”๋กœ ๋‹ค์Œ Refactor ์ž‘์—… ๋•Œ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์•„ํ•˜ ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค~!

}

// TODO ๋ฆฌ์ปดํฌ์ง€์…˜ ์ตœ์ ํ™” ํ•„์š”
val cellGroupedByDay = timetable.cellList.groupBy { it.day }

Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Header(
name = timetable.name,
onClickAdd = onClickAdd,
onClickHamburger = onClickHamburger,
onClickSetting = onClickSetting,
)

Body(
scrollState = scrollState,
type = type,
maxPeriod = maxPeriod,
cellGroupedByDay = cellGroupedByDay,
onClickClassCell = onClickClassCell,
)
}
}

@Composable
private fun Header(
modifier: Modifier = Modifier,
name: String,
onClickAdd: () -> Unit = {},
onClickHamburger: () -> Unit = {},
onClickSetting: () -> Unit = {},
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(start = 24.dp, end = 20.dp),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.spacedBy(18.dp),
) {
Text(
modifier = Modifier.weight(1f),
overflow = TextOverflow.Ellipsis,
text = name,
style = SuwikiTheme.typography.header1,
color = Black,
maxLines = 1,
)

Icon(
modifier = Modifier.suwikiClickable(onClick = onClickHamburger),
painter = painterResource(id = R.drawable.ic_timetable_add),
contentDescription = "",
tint = Gray95,
)

Icon(
modifier = Modifier.suwikiClickable(onClick = onClickAdd),
painter = painterResource(id = R.drawable.ic_timetable_hamburger),
contentDescription = "",
tint = Gray95,
)

Icon(
modifier = Modifier.suwikiClickable(onClick = onClickSetting),
painter = painterResource(id = R.drawable.ic_timetable_setting),
contentDescription = "",
tint = Gray95,
)
}
}

@Composable
private fun Body(
modifier: Modifier = Modifier,
type: TimetableCellType = TimetableCellType.CLASSNAME_PROFESSOR_LOCATION,
scrollState: ScrollState,
maxPeriod: Int,
cellGroupedByDay: Map<TimetableDay, List<TimetableCell>>,
onClickClassCell: (TimetableCell) -> Unit,
) {
Column(
modifier = modifier
.fillMaxWidth()
.border(width = timetableBorderWidth, color = GrayF6)
.verticalScroll(scrollState),
) {
Row {
TimeColumn(
modifier = Modifier.weight(1f),
maxPeriod = maxPeriod,
)

TimetableDay.entries
.sortedBy { it.idx }
.filter { it !in listOf(TimetableDay.SAT, TimetableDay.E_LEARNING) }
.forEach { day ->
ClassColumn(
modifier = Modifier.weight(1f),
type = type,
day = day,
cellList = cellGroupedByDay[day] ?: emptyList(),
lastPeriod = maxPeriod,
onClickClassCell = onClickClassCell,
)
}
}

cellGroupedByDay
.filter { it.key in listOf(TimetableDay.SAT, TimetableDay.E_LEARNING) }
.flatMap { it.value }
.forEach { cell ->
ELearningCell(
onClickClassCell = onClickClassCell,
cell = cell,
)
}
}
}

@Preview(showSystemUi = true)
@Composable
fun TimetablePreview() {
SuwikiTheme {
Timetable(
timetable = Timetable(
createTime = 0L,
year = "",
semester = "",
name = "ํ”„๋ฆฌ๋ทฐ์ž…๋‹ˆ๋‹ค ํ”„๋ฆฌ๋ทฐ์ž…๋‹ˆ๋‹ค ํ”„๋ฆฌ๋ทฐ์ž…๋‹ˆ๋‹ค",
cellList = listOf(
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.E_LEARNING,
startPeriod = 7,
endPeriod = 8,
color = TimetableCellColor.GREEN,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.SAT,
startPeriod = 7,
endPeriod = 8,
color = TimetableCellColor.GREEN,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.E_LEARNING,
startPeriod = 0,
endPeriod = 0,
color = TimetableCellColor.GREEN,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.MON,
startPeriod = 7,
endPeriod = 8,
color = TimetableCellColor.GREEN,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.FRI,
startPeriod = 1,
endPeriod = 2,
color = TimetableCellColor.GREEN,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.FRI,
startPeriod = 3,
endPeriod = 4,
color = TimetableCellColor.PINK,
),
TimetableCell(
name = "๋„์ „๊ณผ ์ฐฝ์กฐ",
professor = "๊น€์ˆ˜๋ฏธ",
location = "๋ฏธ๋ž˜ํ˜์‹ ๊ด€B202",
day = TimetableDay.FRI,
startPeriod = 6,
endPeriod = 6,
color = TimetableCellColor.BROWN,
),
),
),
)
}
}
Loading