Skip to content

Commit

Permalink
Attendance screen configuration (#985)
Browse files Browse the repository at this point in the history
* chore: rename AttendanceType -> AttendanceSession

* chore: delete state for components

* chore: use immutable collection

* chore: remove mock

* feat: add AttendanceDayType.kt

* feat: implement AttendanceScreen

* feat: adjust layout

* chore: move background setting to component

* chore: merge state class into UiState class

* chore: move package

* chore: keep convention

* chore: separate AttendanceGradientBox

* chore: rename ProgressBarState to AttendanceProgressBarPreviewParameter

* chore: keep convention
  • Loading branch information
giovannijunseokim committed Jan 4, 2025
1 parent 04d414d commit d2b9c0d
Show file tree
Hide file tree
Showing 22 changed files with 454 additions and 220 deletions.
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
package org.sopt.official.feature.attendance

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.sopt.official.domain.repository.attendance.AttendanceRepository
import org.sopt.official.feature.attendance.model.AttendanceUiState
import javax.inject.Inject

@HiltViewModel
class NewAttendanceViewModel @Inject constructor(
private val attendanceRepository: AttendanceRepository
private val attendanceRepository: AttendanceRepository,
) : ViewModel() {

init {
fetchData()
}

private val _uiState: MutableStateFlow<AttendanceUiState> = MutableStateFlow(AttendanceUiState.Loading)
private val _uiState: MutableStateFlow<AttendanceUiState> =
MutableStateFlow(AttendanceUiState.Loading)
val uiState: StateFlow<AttendanceUiState> = _uiState

private var fakeTitle: String = ""

fun updateUiState() {
viewModelScope.launch {
_uiState.emit(AttendanceUiState.Success(fakeTitle))
}
}

fun fetchData() {
fetchSoptEvent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -56,6 +54,6 @@ fun AttendanceRoute(onClickBackIcon: () -> Unit) {
@Composable
fun NewAttendanceViewModel.rememberAttendanceActions(): AttendanceAction = remember(this) {
AttendanceAction(
onFakeClick = this::updateUiState
onFakeClick = {}
)
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,209 @@
package org.sopt.official.feature.attendance.compose

import androidx.compose.foundation.layout.Arrangement

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import org.sopt.official.R
import org.sopt.official.designsystem.Black40
import org.sopt.official.designsystem.Gray60
import org.sopt.official.designsystem.SoptTheme
import org.sopt.official.feature.attendance.compose.component.AttendanceGradientBox
import org.sopt.official.feature.attendance.compose.component.AttendanceHistoryCard
import org.sopt.official.feature.attendance.compose.component.AttendanceTopAppBar
import org.sopt.official.feature.attendance.compose.component.TodayAttendanceCard
import org.sopt.official.feature.attendance.compose.component.TodayNoAttendanceCard
import org.sopt.official.feature.attendance.compose.component.TodayNoScheduleCard
import org.sopt.official.feature.attendance.model.AttendanceAction
import org.sopt.official.feature.attendance.model.AttendanceUiState
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceDayType
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceDayType.AttendanceDay.FinalAttendance
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceDayType.AttendanceDay.MidtermAttendance
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceHistory
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceResultType

@Composable
fun AttendanceScreen(state: AttendanceUiState.Success, action: AttendanceAction) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
val scrollState = rememberScrollState()
Box(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 20.dp),
contentAlignment = Alignment.BottomCenter
) {
// TODO
Column(
modifier = Modifier.fillMaxHeight(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Spacer(Modifier.height(16.dp))
when (state.attendanceDayType) {
is AttendanceDayType.AttendanceDay -> {
TodayAttendanceCard(
modifier = Modifier.fillMaxWidth(),
eventDate = state.attendanceDayType.eventDate,
eventLocation = state.attendanceDayType.eventLocation,
eventName = state.attendanceDayType.eventName,
firstAttendance = state.attendanceDayType.firstAttendance,
secondAttendance = state.attendanceDayType.secondAttendance,
finalAttendance = state.attendanceDayType.finalAttendance,
)
}

is AttendanceDayType.Event -> {
TodayNoAttendanceCard(
modifier = Modifier.fillMaxWidth(),
eventDate = state.attendanceDayType.eventDate,
eventLocation = state.attendanceDayType.eventLocation,
eventName = state.attendanceDayType.eventLocation,
)
}

AttendanceDayType.None -> {
TodayNoScheduleCard(
modifier = Modifier.fillMaxWidth()
)
}
}
Spacer(Modifier.height(20.dp))
AttendanceHistoryCard(
userTitle = state.userTitle,
attendanceScore = state.attendanceScore,
totalAttendanceResult = state.totalAttendanceResult,
attendanceHistoryList = state.attendanceHistoryList,
scrollState = scrollState,
)
Spacer(Modifier.height(36.dp))
}
AttendanceGradientBox()
TextButton(
onClick = { /*TODO*/ },
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 9.dp),
shape = RoundedCornerShape(size = 6.dp),
colors = ButtonColors(
containerColor = SoptTheme.colors.onSurface10,
contentColor = SoptTheme.colors.onSurface950,
disabledContainerColor = Black40,
disabledContentColor = Gray60,
),
contentPadding = PaddingValues(vertical = 16.dp)
) {
Text(
text = stringResource(R.string.attendance_dialog_button),
style = SoptTheme.typography.label18SB,
)
}
}
}

@Preview
@Composable
private fun AttendanceScreenPreview(@PreviewParameter(AttendanceScreenPreviewParameterProvider::class) parameter: AttendanceScreenPreviewParameter) {
SoptTheme {
Scaffold(
topBar = {
AttendanceTopAppBar(
onClickBackIcon = { },
onClickRefreshIcon = { }
)
}
) { innerPaddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.background(color = SoptTheme.colors.background)
.padding(innerPaddingValues)
) {
AttendanceScreen(
state = AttendanceUiState.Success(
attendanceDayType = parameter.attendanceDayType,
userTitle = "32기 디자인파트 김솝트",
attendanceScore = 1,
totalAttendanceResult = persistentMapOf(
Pair(AttendanceResultType.ALL, 16),
Pair(AttendanceResultType.PRESENT, 10),
Pair(AttendanceResultType.LATE, 4),
Pair(AttendanceResultType.ABSENT, 2)
),
attendanceHistoryList = persistentListOf(
AttendanceHistory(
status = "출석", eventName = "1차 세미나", date = "00월 00일"
),
AttendanceHistory(
status = "출석", eventName = "2차 세미나", date = "00월 00일"
),
AttendanceHistory(
status = "출석", eventName = "3차 세미나", date = "00월 00일"
),
AttendanceHistory(
status = "출석", eventName = "4차 세미나", date = "00월 00일"
),
AttendanceHistory(
status = "출석", eventName = "5차 세미나", date = "00월 00일"
),
AttendanceHistory(
status = "출석", eventName = "6차 세미나", date = "00월 00일"
),
),
),
action = AttendanceAction(onFakeClick = {})
)
}
}
}
}

data class AttendanceScreenPreviewParameter(
val attendanceDayType: AttendanceDayType,
)


class AttendanceScreenPreviewParameterProvider() :
PreviewParameterProvider<AttendanceScreenPreviewParameter> {

override val values: Sequence<AttendanceScreenPreviewParameter> = sequenceOf(
AttendanceScreenPreviewParameter(
attendanceDayType = AttendanceDayType.AttendanceDay(
eventDate = "3월 23일 토요일 14:00 - 18:00",
eventLocation = "건국대학교 꽥꽥오리관",
eventName = "2차 세미나",
firstAttendance = MidtermAttendance.Present(attendanceAt = "14:00"),
secondAttendance = MidtermAttendance.Absent,
finalAttendance = FinalAttendance.LATE,
)
), AttendanceScreenPreviewParameter(
attendanceDayType = AttendanceDayType.Event(
eventDate = "3월 23일 토요일 14:00 - 18:00",
eventLocation = "건국대학교 꽥꽥오리관",
eventName = "2차 세미나",
)
),
AttendanceScreenPreviewParameter(
attendanceDayType = AttendanceDayType.None
)
)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.sopt.official.feature.attendance.compose
package org.sopt.official.feature.attendance.compose.component

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
Expand Down Expand Up @@ -28,14 +28,13 @@ import org.sopt.official.R
import org.sopt.official.designsystem.Black40
import org.sopt.official.designsystem.Gray60
import org.sopt.official.designsystem.SoptTheme
import org.sopt.official.feature.attendance.compose.component.AttendanceCodeCardList
import org.sopt.official.feature.attendance.model.AttendanceType
import org.sopt.official.feature.attendance.model.AttendanceUiState.Success.AttendanceDayType.AttendanceDay.MidtermAttendance.NotYet.AttendanceSession

@Composable
fun AttendanceCodeDialog(
codes: ImmutableList<String>,
inputCodes: ImmutableList<String?>,
attendanceType: AttendanceType,
attendanceSession: AttendanceSession,
onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -58,7 +57,7 @@ fun AttendanceCodeDialog(
.clickable(onClick = onDismissRequest)
)
Text(
text = stringResource(R.string.attendance_do, attendanceType.type),
text = stringResource(R.string.attendance_do, attendanceSession.type),
style = SoptTheme.typography.heading18B,
color = SoptTheme.colors.onSurface10
)
Expand Down Expand Up @@ -114,7 +113,7 @@ private fun AttendanceCodeDialogPreview(
AttendanceCodeDialog(
codes = parameter.codes,
inputCodes = parameter.inputCodes,
attendanceType = parameter.attendanceType,
attendanceSession = parameter.attendanceSession,
modifier = Modifier.fillMaxWidth(),
onDismissRequest = {}
)
Expand All @@ -124,7 +123,7 @@ private fun AttendanceCodeDialogPreview(
data class AttendanceCodeDialogPreviewParameter(
val codes: ImmutableList<String>,
val inputCodes: ImmutableList<String?>,
val attendanceType: AttendanceType,
val attendanceSession: AttendanceSession,
)

class AttendanceCodeDialogPreviewParameterProvider :
Expand All @@ -134,22 +133,22 @@ class AttendanceCodeDialogPreviewParameterProvider :
AttendanceCodeDialogPreviewParameter(
codes = persistentListOf("1", "2", "3", "4", "5"),
inputCodes = persistentListOf("1", "2", "3", null, null),
AttendanceType.FIRST,
AttendanceSession.FIRST,
),
AttendanceCodeDialogPreviewParameter(
codes = persistentListOf("1", "2", "3", "4", "5"),
inputCodes = persistentListOf("1", "2", "3", "4", "5"),
AttendanceType.FIRST,
AttendanceSession.FIRST,
),
AttendanceCodeDialogPreviewParameter(
codes = persistentListOf("1", "2", "3", "4", "5"),
inputCodes = persistentListOf("1", "2", "3", null, null),
AttendanceType.SECOND,
AttendanceSession.SECOND,
),
AttendanceCodeDialogPreviewParameter(
codes = persistentListOf("1", "2", "3", "4", "5"),
inputCodes = persistentListOf("1", "2", "3", "4", "5"),
AttendanceType.SECOND,
AttendanceSession.SECOND,
),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import org.sopt.official.R
import org.sopt.official.designsystem.SoptTheme

@Composable
fun AttendanceCountCard(resultType: String, count: Int, modifier: Modifier = Modifier) {
fun AttendanceCountCard(
resultType: String,
count: Int,
modifier: Modifier = Modifier
) {
Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = resultType,
Expand Down
Loading

0 comments on commit d2b9c0d

Please sign in to comment.