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] 시간표 3차 구현 #473

Merged
merged 40 commits into from
Nov 14, 2024
Merged
Changes from 1 commit
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8096949
[del] hour formatter 삭제
Jokwanhee Nov 7, 2024
35937ae
[fix] 변수명 변경
Jokwanhee Nov 7, 2024
fa44832
[fix] range 구하는 로직 수정
Jokwanhee Nov 7, 2024
6ed214f
[add] 마지막 활성화 radius round 추가
Jokwanhee Nov 7, 2024
774b497
[add] 클릭 활성화 radius 추가 및 시간표 확장
Jokwanhee Nov 7, 2024
f7a3d61
[fix] 테스트 코드 수정
Jokwanhee Nov 7, 2024
2a32c28
[fix] 강의 시간 분할 로직 변경
Jokwanhee Nov 7, 2024
2b57c29
[del] 주석 제거
Jokwanhee Nov 7, 2024
61aca0a
[fix] bottom end round 설정 로직 함수화
Jokwanhee Nov 7, 2024
06cdd0d
[fix] 함수명 변경 적용
Jokwanhee Nov 7, 2024
365b039
[fix] 강의 활성화 블록 시간 확장 기능 추가
Jokwanhee Nov 7, 2024
3709697
[add] 테스트 코드 추가
Jokwanhee Nov 7, 2024
d3fbb24
[add] 동일 과목 활성화 구현
Jokwanhee Nov 8, 2024
9392a64
[fix] 시간표 색상 변경
Jokwanhee Nov 8, 2024
ae40eee
[add] sideEffect 추가 및 바텀 시트 모드 콜백 추가
Jokwanhee Nov 8, 2024
b24e5e1
[add] koin 모ㄹ compose bom 종속성 추가
Jokwanhee Nov 12, 2024
3813e2e
[add] resources 추가
Jokwanhee Nov 12, 2024
4e5d3f9
[add] CustomSnackBarHost 구현
Jokwanhee Nov 13, 2024
fb4f1a8
[fix] 커스텀 스낵바 속성 추가
Jokwanhee Nov 13, 2024
24decd4
[add] Retrofit 널 반환 허용
Jokwanhee Nov 13, 2024
253de28
[fix] DTO 수정 및 연산 추가
Jokwanhee Nov 13, 2024
9bc85d7
[add] 요일 컴포넌트 추가
Jokwanhee Nov 13, 2024
ccbc10e
[fix] 학부 필터링 모달 수정
Jokwanhee Nov 13, 2024
42d2172
[add] TimeEditBox 수정
Jokwanhee Nov 13, 2024
dcffc78
[add] 상태 데이터 클래스 추가
Jokwanhee Nov 13, 2024
d844061
[fix] 다이어로그 수정
Jokwanhee Nov 13, 2024
0e8bcb8
[add] BitmapUtils 추가
Jokwanhee Nov 13, 2024
7494fec
[add] 코드 수정 및 추가
Jokwanhee Nov 13, 2024
ab35761
[add] 시간표 바텀시트 수정 및 추가
Jokwanhee Nov 13, 2024
3ef94b8
[add] string 리소스 추가
Jokwanhee Nov 13, 2024
563768f
[fix] 뷰모델 로직 수정 및 추가
Jokwanhee Nov 13, 2024
4695d8a
[add] KoinPicker 구현
Jokwanhee Nov 13, 2024
6cd2ed6
[fix] 시간표 액티비티 코드 수정 및 추가
Jokwanhee Nov 13, 2024
c9ead66
[fix] TimetableLecture 테스트 코드 수정
Jokwanhee Nov 13, 2024
80d7d6e
[fix] 익명 여부 false 수정
Jokwanhee Nov 13, 2024
cd8facc
Merge remote-tracking branch 'origin/develop' into feature/timetable_…
Jokwanhee Nov 13, 2024
73f4f54
[fix] KoinPicker 변경 및 gradient 추가
Jokwanhee Nov 13, 2024
437e911
[fix] KoinPicker 수정
Jokwanhee Nov 13, 2024
73a44a9
[add] TimetableSemesterActivity 연결
Jokwanhee Nov 13, 2024
f55322a
[add] dialog 흰색 배경 추가
Jokwanhee Nov 13, 2024
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
Prev Previous commit
Next Next commit
[add] 동일 과목 활성화 구현
  • Loading branch information
Jokwanhee committed Nov 8, 2024
commit d3fbb247a0e99cb72ae5e73e1f1a5c85657ceffc
Original file line number Diff line number Diff line change
@@ -5,7 +5,18 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.PathEffect
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

/**
* 리플 효과 없는 Clickable
@@ -24,4 +35,44 @@ fun Modifier.noRippleClickable(
role = role,
onClick = onClick
)
}

/**
* 점선(-) 테두리
*/
fun Modifier.dashedBorder(
color: Color,
shape: Shape,
strokeWidth: Dp = 1.dp,
dashLength: Dp = 3.dp,
gapLength: Dp = 3.dp,
cap: StrokeCap = StrokeCap.Round
) = dashedBorder(brush = SolidColor(color), shape, strokeWidth, dashLength, gapLength, cap)

private fun Modifier.dashedBorder(
brush: Brush,
shape: Shape,
strokeWidth: Dp,
dashLength: Dp,
gapLength: Dp,
cap: StrokeCap = StrokeCap.Round
) = this.drawWithContent {

val outline = shape.createOutline(size, layoutDirection, density = this)

val dashedStroke = Stroke(
cap = cap,
width = strokeWidth.toPx(),
pathEffect = PathEffect.dashPathEffect(
intervals = floatArrayOf(dashLength.toPx(), gapLength.toPx())
)
)

drawContent()

drawOutline(
outline = outline,
style = dashedStroke,
brush = brush
)
}
Original file line number Diff line number Diff line change
@@ -19,13 +19,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import `in`.koreatech.koin.core.designsystem.dashedBorder
import `in`.koreatech.koin.core.designsystem.theme.KoinTheme
import `in`.koreatech.koin.feature.timetable.model.TimetableEvent
import `in`.koreatech.koin.feature.timetable.model.dummyEvent
import java.time.DayOfWeek

enum class TimetableEventType {
BASIC, SELECTED
BASIC, SELECTED, ETC_SELECTED
}

@Composable
@@ -53,6 +54,12 @@ fun TimetableEventTime(
bottom = (0.65).dp
)
)

TimetableEventType.ETC_SELECTED -> TimetableEtcSelectedEventTime(
range = range,
event = event,
modifier = modifier.padding(1.dp)
)
}
}

@@ -92,7 +99,6 @@ private fun TimetableSelectedEventTime(
event: TimetableEvent,
modifier: Modifier = Modifier,
) {

Box(
modifier = modifier
.fillMaxSize()
@@ -103,16 +109,37 @@ private fun TimetableSelectedEventTime(
color = KoinTheme.colors.neutral500,
width = 1.dp,
shape = RoundedCornerShape(
bottomEnd = timetableSelectedEventTimeBottomEndRound(
range,
event
)
bottomEnd = timetableSelectedEventTimeBottomEndRound(range, event)
)
)
)
}

fun timetableSelectedEventTimeBottomEndRound(
@Composable
private fun TimetableEtcSelectedEventTime(
range: Int,
event: TimetableEvent,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.fillMaxSize()
.background(
color = Color.Transparent,
)
.dashedBorder(
color = KoinTheme.colors.neutral500,
shape = RoundedCornerShape(
topStart = 0.dp,
topEnd = 0.dp,
bottomStart = 0.dp,
bottomEnd = timetableSelectedEventTimeBottomEndRound(range, event)
)
)
)
}

private fun timetableSelectedEventTimeBottomEndRound(
range: Int,
event: TimetableEvent
): Dp {
@@ -124,7 +151,6 @@ fun timetableSelectedEventTimeBottomEndRound(
}
if (range == timeRange) {
return 10.dp
true
}
}
return 0.dp
@@ -153,4 +179,17 @@ private fun TimetableEventTimePreview_Selected() {
.padding(10.dp),
eventType = TimetableEventType.SELECTED
)
}

@Preview(showBackground = true)
@Composable
private fun TimetableEventTimePreview_Etc_Selected() {
TimetableEventTime(
range = 9,
event = dummyEvent,
modifier = Modifier
.sizeIn(maxHeight = 64.dp)
.padding(10.dp),
eventType = TimetableEventType.ETC_SELECTED
)
}
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ import `in`.koreatech.koin.feature.timetable.component.TimetableEventType
import `in`.koreatech.koin.feature.timetable.model.TimetableConstants
import `in`.koreatech.koin.feature.timetable.model.TimetableEvent
import `in`.koreatech.koin.feature.timetable.model.dummyEvent
import java.sql.Time
import java.time.DayOfWeek
import java.time.LocalTime
import java.time.format.DateTimeFormatter
@@ -46,6 +47,7 @@ fun TimetableContent(
dayCount: Int = TimetableConstants.days.size,
height: Dp = (TimetableConstants.eventHeight).dp,
clickEvent: List<TimetableEvent> = emptyList(),
etcClickEvent: List<TimetableEvent> = emptyList(),
content: @Composable (event: TimetableEvent, eventType: TimetableEventType, onEventTimeClick: (TimetableEvent) -> Unit) -> Unit = { event, eventType, onClick ->
TimetableEventTime(
range = range,
@@ -95,10 +97,17 @@ fun TimetableContent(
content(event, TimetableEventType.BASIC, onEventClick)
}
}
if (etcClickEvent.isNotEmpty()) {
etcClickEvent.sortedBy(TimetableEvent::start).forEach { event ->
Box(modifier = Modifier.eventData(event)) {
content(event, TimetableEventType.ETC_SELECTED, {})
}
}
}
if (clickEvent.isNotEmpty()) {
clickEvent.sortedBy(TimetableEvent::start).forEach { event ->
Box(modifier = Modifier.eventData(event)) {
content(event, TimetableEventType.SELECTED, onEventClick)
content(event, TimetableEventType.SELECTED, {})
}
}
}
@@ -243,7 +252,7 @@ fun TimetableContent(
else -> -1
}
val eventX = eventOffsetDays * innerWidth + timeWidth.roundToPx()
if (index == placeablesWithEvents.size - 1) {
if(event in clickEvent) {
onEventY(eventY)
}
placeable.place(eventX, eventY)
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ fun Timetable(
events: List<TimetableEvent>,
modifier: Modifier = Modifier,
clickEvent: List<TimetableEvent> = emptyList(),
etcClickEvent: List<TimetableEvent> = emptyList(),
content: @Composable
(event: TimetableEvent, eventType: TimetableEventType, onEventTimeClick: (TimetableEvent) -> Unit) -> Unit = { event, eventType, onEventTimeClick ->
TimetableEventTime(
@@ -60,6 +61,7 @@ fun Timetable(
horizontalPadding = 48.dp,
events = events,
clickEvent = clickEvent,
etcClickEvent = etcClickEvent,
content = content,
onEventClick = onEventClick,
onEventY = { y ->
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@ fun TimetableScreen(
modifier: Modifier = Modifier,
timetableEvents: List<TimetableEvent> = emptyList(),
clickedTimetableEvents: List<TimetableEvent> = emptyList(),
etcClickedTimetableEvents: List<TimetableEvent> = emptyList(),
onSearchTextChange: (text: String) -> Unit = {},
onClickTimetableSchedule: () -> Unit = {},
onClickDownloadTimetable: () -> Unit = {},
@@ -116,6 +117,7 @@ fun TimetableScreen(
modifier = Modifier,
events = timetableEvents,
clickEvent = clickedTimetableEvents,
etcClickEvent = etcClickedTimetableEvents,
onEventClick = onClickTimetableEvent
)
}
@@ -124,7 +126,6 @@ fun TimetableScreen(
}



@OptIn(ExperimentalMaterialApi::class)
private fun Modifier.dynamicPadding(
sheetState: BottomSheetState,
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.koreatech.koin.domain.model.timetable.response.Lecture
import `in`.koreatech.koin.domain.model.timetable.response.TimetableFrame
import `in`.koreatech.koin.domain.model.timetable.response.TimetableLecture
import `in`.koreatech.koin.domain.model.timetable.response.TimetableLectures
import `in`.koreatech.koin.domain.repository.TimetableRepository
import `in`.koreatech.koin.domain.usecase.timetable.AddTimetableLectureUseCase
@@ -16,6 +17,7 @@ import `in`.koreatech.koin.domain.usecase.timetable.GetTimetableFramesUseCase
import `in`.koreatech.koin.feature.timetable.model.TimetableEvent
import `in`.koreatech.koin.feature.timetable.utils.formatTimeRange
import `in`.koreatech.koin.feature.timetable.utils.getTimetableEvents
import `in`.koreatech.koin.feature.timetable.utils.toTimetableEvents
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -184,15 +186,44 @@ class TimetableViewModel @Inject constructor(
if (timetableEvents.isEmpty()) {
_uiState.value = _uiState.value.copy(
clickedTimetableEvents = emptyList(),
etcClickedTimetableEvents = emptyList(),
range = uiState.value.timetableLectures.formatTimeRange()
)
} else {
val range = timetableEvents.formatTimeRange()
val events =
lectures.value.filter { it.name == timetableEvents.firstOrNull()?.name.orEmpty() }
.flatMap { timetableLecture ->
timetableLecture.toTimetableEvents()
}

val adaptRange = uiState.value.timetableLectures.formatTimeRange()
val eventRange = events.formatTimeRange()

val etcClickedTimetableEvents = events.toMutableList()
events.forEach { etcTimetableEvent ->
timetableEvents.forEach { timetableEvent ->
if (etcTimetableEvent.start == timetableEvent.start && etcTimetableEvent.end == timetableEvent.end) {
etcClickedTimetableEvents.remove(etcTimetableEvent)
}
}
}

_uiState.value = _uiState.value.copy(
clickedTimetableEvents = timetableEvents,
range = if (range < 9) {
9
} else range
etcClickedTimetableEvents = etcClickedTimetableEvents,
range = if (eventRange > 9) {
if (adaptRange > eventRange) {
adaptRange
} else {
eventRange
}
} else {
if (adaptRange > 9) {
adaptRange
} else {
9
}
}
)
}
}
@@ -308,6 +339,7 @@ class TimetableViewModel @Inject constructor(
timetableLectures = timetableLectures,
timetableEvents = timetableLectures.getTimetableEvents(),
clickedTimetableEvents = emptyList(),
etcClickedTimetableEvents = emptyList(),
isLectureDuplicationDialogVisible = false,
selectedLecture = null,
loading = false
@@ -349,6 +381,9 @@ class TimetableViewModel @Inject constructor(
range = timetableLectures.formatTimeRange(),
frameId = timetableLectures.timetableFrameId,
timetableEvents = timetableLectures.getTimetableEvents(),
clickedTimetableEvents = emptyList(),
etcClickedTimetableEvents = emptyList(),
selectedLecture = null,
timetableLectures = timetableLectures,
)
}.onFailure {
@@ -410,6 +445,7 @@ data class TimetableUiState(
val currentSemester: String = "",
val timetableEvents: List<TimetableEvent> = emptyList(),
val clickedTimetableEvents: List<TimetableEvent> = emptyList(),
val etcClickedTimetableEvents: List<TimetableEvent> = emptyList(),
val selectedLecture: Lecture? = null,
val timetableLectures: TimetableLectures = TimetableLectures(0, emptyList(), 0, 0),
val loading: Boolean = false,