diff --git a/app/src/androidTest/java/com/yapp/attendance/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/yapp/attendance/ExampleInstrumentedTest.kt deleted file mode 100644 index ca8453ac..00000000 --- a/app/src/androidTest/java/com/yapp/attendance/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.yapp.attendance - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert.* -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.yapp.attendance", appContext.packageName) - } -} diff --git a/app/src/main/java/com/yapp/attendance/di/DataModule.kt b/app/src/main/java/com/yapp/attendance/di/DataModule.kt index 5dc561fc..a9ead0ce 100644 --- a/app/src/main/java/com/yapp/attendance/di/DataModule.kt +++ b/app/src/main/java/com/yapp/attendance/di/DataModule.kt @@ -13,6 +13,7 @@ import com.yapp.domain.repository.MemberRepository import com.yapp.domain.repository.RemoteConfigRepository import com.yapp.domain.repository.SessionRepository import com.yapp.domain.repository.TeamRepository +import com.yapp.domain.util.DateParser import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -57,15 +58,16 @@ object DataModule { @Provides @Singleton fun provideSessionRepository( - sessionDataSource: SessionRemoteDataSource + sessionDataSource: SessionRemoteDataSource, + dateParser: DateParser ): SessionRepository { - return SessionRepositoryImpl(sessionDataSource) + return SessionRepositoryImpl(sessionDataSource, dateParser) } @Provides @Singleton fun provideRemoteConfigRepository( - remoteConfigDataSource: FirebaseRemoteConfigDataSource, + remoteConfigDataSource: FirebaseRemoteConfigDataSource ): RemoteConfigRepository { return RemoteConfigRepositoryImpl(remoteConfigDataSource) } diff --git a/buildSrc/src/main/java/com/yapp/buildsrc/Dependencies.kt b/buildSrc/src/main/java/com/yapp/buildsrc/Dependencies.kt index 8db2c679..1ecdf9c0 100644 --- a/buildSrc/src/main/java/com/yapp/buildsrc/Dependencies.kt +++ b/buildSrc/src/main/java/com/yapp/buildsrc/Dependencies.kt @@ -78,6 +78,11 @@ object Dependencies { const val JUNIT = "junit:junit:4.+" const val ANDROID_JUNIT = "androidx.test.ext:junit:1.1.3" const val ESPRESSO_CORE = "androidx.test.espresso:espresso-core:3.4.0" + + private const val kotest_version = "5.8.0" + const val KOTEST_RUNNER = "io.kotest:kotest-runner-junit5:${kotest_version}" + const val KOTEST_ASSERTION = "io.kotest:kotest-assertions-core:${kotest_version}" + const val KOTEST_PROPERTY = "io.kotest:kotest-property:${kotest_version}" } object Firebase { diff --git a/common/src/main/java/com/yapp/common/yds/YDSAttendanceList.kt b/common/src/main/java/com/yapp/common/yds/YDSAttendanceList.kt index 945cc368..0a2fdf0a 100644 --- a/common/src/main/java/com/yapp/common/yds/YDSAttendanceList.kt +++ b/common/src/main/java/com/yapp/common/yds/YDSAttendanceList.kt @@ -1,7 +1,5 @@ package com.yapp.common.yds -import androidx.annotation.DrawableRes -import androidx.annotation.StringRes import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -17,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow @@ -44,7 +43,7 @@ fun YDSAttendanceList( .padding(24.dp) ) { Icon( - painterResource(id = attendanceType.icon), + painter = attendanceType.icon(), contentDescription = null, tint = Color.Unspecified, modifier = Modifier.alpha( @@ -61,7 +60,7 @@ fun YDSAttendanceList( horizontalArrangement = Arrangement.SpaceBetween ) { Text( - text = stringResource(attendanceType.title), + text = attendanceType.text(), style = AttendanceTypography.body2, color = when (attendanceType) { YDSAttendanceType.ATTEND -> AttendanceTheme.colors.etcColors.EtcGreen @@ -97,11 +96,34 @@ fun YDSAttendanceList( } } -enum class YDSAttendanceType(@DrawableRes val icon: Int, @StringRes val title: Int) { - ATTEND(R.drawable.icon_attend, R.string.attend), - TARDY(R.drawable.icon_tardy, R.string.tardy), - ABSENT(R.drawable.icon_absent, R.string.absent), - TBD(R.drawable.icon_absent, R.string.tbd), - NO_ATTENDANCE(R.drawable.icon_absent, R.string.no_attendance), - NO_YAPP(R.drawable.icon_absent, R.string.no_yapp) +@Composable +fun YDSAttendanceType.text(): String { + return stringResource( + id = when (this) { + YDSAttendanceType.ATTEND -> R.string.attend + YDSAttendanceType.TARDY -> R.string.tardy + YDSAttendanceType.ABSENT -> R.string.absent + YDSAttendanceType.TBD -> R.string.tbd + YDSAttendanceType.NO_ATTENDANCE -> R.string.no_attendance + YDSAttendanceType.NO_YAPP -> R.string.no_yapp + } + ) +} + +@Composable +fun YDSAttendanceType.icon(): Painter { + return painterResource( + id = when (this) { + YDSAttendanceType.ATTEND -> R.drawable.icon_attend + YDSAttendanceType.TARDY -> R.drawable.icon_tardy + YDSAttendanceType.ABSENT -> R.drawable.icon_absent + YDSAttendanceType.TBD -> R.drawable.icon_absent + YDSAttendanceType.NO_ATTENDANCE -> R.drawable.icon_absent + YDSAttendanceType.NO_YAPP -> R.drawable.icon_absent + } + ) +} + +enum class YDSAttendanceType { + ATTEND, TARDY, ABSENT, TBD, NO_ATTENDANCE, NO_YAPP } diff --git a/data/src/androidTest/java/com/yapp/data/ExampleInstrumentedTest.kt b/data/src/androidTest/java/com/yapp/data/ExampleInstrumentedTest.kt deleted file mode 100644 index 057fa4b3..00000000 --- a/data/src/androidTest/java/com/yapp/data/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.yapp.data - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.type.app.InstrumentationRegistry -import org.junit.Assert.* -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.yapp.data.test", appContext.packageName) - } -} diff --git a/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSource.kt b/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSource.kt index 5847e869..817721b5 100644 --- a/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSource.kt +++ b/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSource.kt @@ -8,7 +8,6 @@ import com.yapp.data.model.VersionEntity interface FirebaseRemoteConfigDataSource { suspend fun getMaginotlineTime(): String - suspend fun getSessionList(): List suspend fun getConfig(): ConfigEntity suspend fun getTeamList(): List suspend fun getQrPassword(): String diff --git a/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSourceImpl.kt b/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSourceImpl.kt index 0977a3b9..d0c6705c 100644 --- a/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSourceImpl.kt +++ b/data/src/main/java/com/yapp/data/datasource/FirebaseRemoteConfigDataSourceImpl.kt @@ -42,21 +42,6 @@ class FirebaseRemoteConfigDataSourceImpl @Inject constructor() : FirebaseRemoteC } } - override suspend fun getSessionList(): List { - return suspendCancellableCoroutine { cancellableContinuation -> - firebaseRemoteConfig.fetchAndActivate().addOnSuccessListener { - val entities = firebaseRemoteConfig.getString(RemoteConfigData.SessionList.key) - .let { jsonString -> - Json.decodeFromString>(jsonString) - } - - cancellableContinuation.resume(value = entities, onCancellation = null) - }.addOnFailureListener { exception -> - cancellableContinuation.resumeWithException(exception) - } - } - } - override suspend fun getConfig(): ConfigEntity { return suspendCancellableCoroutine { cancellableContinuation -> firebaseRemoteConfig.fetchAndActivate().addOnSuccessListener { diff --git a/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSource.kt b/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSource.kt index a5a414c3..63dd6ce1 100644 --- a/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSource.kt +++ b/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSource.kt @@ -4,6 +4,6 @@ import com.yapp.data.model.SessionEntity interface SessionRemoteDataSource { suspend fun setSession(session: SessionEntity) - suspend fun getSession(id: Long): SessionEntity? + suspend fun getSession(id: Int): SessionEntity? suspend fun getAllSession(): List } diff --git a/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSourceImpl.kt b/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSourceImpl.kt index 8c31de19..a06d1c8e 100644 --- a/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSourceImpl.kt +++ b/data/src/main/java/com/yapp/data/datasource/SessionRemoteDataSourceImpl.kt @@ -26,7 +26,7 @@ class SessionRemoteDataSourceImpl @Inject constructor( } } - override suspend fun getSession(id: Long): SessionEntity? { + override suspend fun getSession(id: Int): SessionEntity? { return suspendCancellableCoroutine { cancellableContinuation -> fireStore.sessionRef() .document(id.toString()) diff --git a/data/src/main/java/com/yapp/data/model/AttendanceEntity.kt b/data/src/main/java/com/yapp/data/model/AttendanceEntity.kt index e106dce2..cf701a43 100644 --- a/data/src/main/java/com/yapp/data/model/AttendanceEntity.kt +++ b/data/src/main/java/com/yapp/data/model/AttendanceEntity.kt @@ -32,3 +32,7 @@ fun Attendance.toData(): AttendanceEntity { status = status.toData() ) } + +fun Attendance.Status.toData(): String { + return this.name.uppercase() +} \ No newline at end of file diff --git a/data/src/main/java/com/yapp/data/model/SessionEntity.kt b/data/src/main/java/com/yapp/data/model/SessionEntity.kt index e5e363d9..eb888649 100644 --- a/data/src/main/java/com/yapp/data/model/SessionEntity.kt +++ b/data/src/main/java/com/yapp/data/model/SessionEntity.kt @@ -3,6 +3,7 @@ package com.yapp.data.model import com.google.firebase.firestore.PropertyName import com.yapp.domain.model.Session import com.yapp.domain.model.types.NeedToAttendType +import com.yapp.domain.util.DateParser import kotlinx.serialization.Serializable @Serializable @@ -21,24 +22,24 @@ data class SessionEntity( val code: String? = null ) -fun SessionEntity.toDomain(): Session { +fun SessionEntity.toDomain(dateParser: DateParser): Session { return Session( sessionId = sessionId!!, title = title!!, - startTime = startTime!!, - description = description!!, type = NeedToAttendType.valueOf(type!!), - code = code ?: "" + startTime = dateParser.parse(rawDate = startTime!!), + description = description!!, + code = code!! ) } -fun Session.toData(): SessionEntity { +fun Session.toData(dateParser: DateParser): SessionEntity { return SessionEntity( sessionId = sessionId, title = title, - startTime = startTime, - description = description, type = type.name, + startTime = dateParser.format(date = startTime), + description = description, code = code ) -} +} \ No newline at end of file diff --git a/data/src/main/java/com/yapp/data/model/types/AttendanceTypeEntity.kt b/data/src/main/java/com/yapp/data/model/types/AttendanceTypeEntity.kt deleted file mode 100644 index 07aa6a15..00000000 --- a/data/src/main/java/com/yapp/data/model/types/AttendanceTypeEntity.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.yapp.data.model.types - -import com.yapp.domain.model.Attendance -import kotlinx.serialization.Serializable - - -@Serializable -data class AttendanceTypeEntity( - val text: String -) - -fun AttendanceTypeEntity.toDomain(): Attendance.Status { - return when (this.text) { - Attendance.Status.ABSENT.name -> Attendance.Status.ABSENT - Attendance.Status.LATE.name -> Attendance.Status.LATE - Attendance.Status.ADMIT.name -> Attendance.Status.ADMIT - Attendance.Status.NORMAL.name -> Attendance.Status.NORMAL - else -> error("알 수 없는 AttendanceType입니다.") - } -} - -fun Attendance.Status.toData(): String { - return this.name.uppercase() -} diff --git a/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt index 70b945aa..0a708357 100644 --- a/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt @@ -10,12 +10,14 @@ import com.yapp.domain.model.Config import com.yapp.domain.model.Session import com.yapp.domain.model.Team import com.yapp.domain.model.Version +import com.yapp.domain.model.types.NeedToAttendType import com.yapp.domain.repository.RemoteConfigRepository +import com.yapp.domain.util.DateParser import javax.inject.Inject class RemoteConfigRepositoryImpl @Inject constructor( - private val firebaseRemoteConfigDataSource: FirebaseRemoteConfigDataSource, + private val firebaseRemoteConfigDataSource: FirebaseRemoteConfigDataSource ) : RemoteConfigRepository { private var isAlreadyRequestUpdate = false @@ -33,19 +35,6 @@ class RemoteConfigRepositoryImpl @Inject constructor( ) } - override suspend fun getSessionList(): Result> { - return runCatching { - firebaseRemoteConfigDataSource.getSessionList() - }.fold( - onSuccess = { entities: List -> - Result.success(entities.map { it.toDomain() }) - }, - onFailure = { exception -> - Result.failure(exception) - } - ) - } - override suspend fun getConfig(): Result { return runCatching { firebaseRemoteConfigDataSource.getConfig() diff --git a/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt index 891a57fa..81590ec8 100644 --- a/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt @@ -5,14 +5,16 @@ import com.yapp.data.model.toData import com.yapp.data.model.toDomain import com.yapp.domain.model.Session import com.yapp.domain.repository.SessionRepository +import com.yapp.domain.util.DateParser import javax.inject.Inject class SessionRepositoryImpl @Inject constructor( private val sessionRemoteDataSource: SessionRemoteDataSource, + private val dateParser: DateParser ) : SessionRepository { override suspend fun setSession(session: Session): Result { return runCatching { - sessionRemoteDataSource.setSession(session.toData()) + sessionRemoteDataSource.setSession(session.toData(dateParser)) }.fold( onSuccess = { Result.success(Unit) @@ -23,9 +25,9 @@ class SessionRepositoryImpl @Inject constructor( ) } - override suspend fun getSession(id: Long): Result { + override suspend fun getSession(id: Int): Result { return runCatching { - sessionRemoteDataSource.getSession(id)?.toDomain() + sessionRemoteDataSource.getSession(id)?.toDomain(dateParser) }.fold( onSuccess = { Result.success(it) @@ -38,9 +40,7 @@ class SessionRepositoryImpl @Inject constructor( override suspend fun getAllSession(): Result> { return runCatching { - sessionRemoteDataSource.getAllSession().map { - it.toDomain() - } + sessionRemoteDataSource.getAllSession().map { entity -> entity.toDomain(dateParser) } }.fold( onSuccess = { Result.success(it) diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index c6763625..14bb5e4d 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -3,8 +3,15 @@ plugins { kotlin("kapt") } +tasks.test { + useJUnitPlatform() +} dependencies { implementation(Dependencies.INJECT) implementation(Dependencies.Kotlin.COROUTINE_CORE) + + testImplementation(Dependencies.Test.KOTEST_RUNNER) + testImplementation(Dependencies.Test.KOTEST_ASSERTION) + testImplementation(Dependencies.Test.KOTEST_PROPERTY) } diff --git a/domain/src/main/java/com/yapp/domain/firebase/RemoteConfigData.kt b/domain/src/main/java/com/yapp/domain/firebase/RemoteConfigData.kt index 5776312c..64115db7 100644 --- a/domain/src/main/java/com/yapp/domain/firebase/RemoteConfigData.kt +++ b/domain/src/main/java/com/yapp/domain/firebase/RemoteConfigData.kt @@ -9,11 +9,6 @@ sealed class RemoteConfigData { override val defaultValue: String = "fail" } - object SessionList : RemoteConfigData() { - override val key: String = ATTENDANCE_SESSION_LIST - override val defaultValue: String = "" - } - object Config : RemoteConfigData() { override val key: String = ATTENDANCE_CONFIG override val defaultValue: String = "" @@ -51,7 +46,6 @@ sealed class RemoteConfigData { companion object { private const val ATTENDANCE_MAGINOTLINE_TIME = "attendance_maginotline_time" - private const val ATTENDANCE_SESSION_LIST = "attendance_session_list" private const val ATTENDANCE_SELECT_TEAMS = "attendance_select_teams" private const val ATTENDANCE_CONFIG = "config" private const val ATTENDANCE_QR_PASSWORD = "attendance_qr_password" @@ -62,7 +56,6 @@ sealed class RemoteConfigData { val defaultMaps = mapOf( MaginotlineTime.defaultValue to MaginotlineTime.key, - SessionList.defaultValue to SessionList.key, AttendanceSelectTeams.defaultValue to AttendanceSelectTeams.key, Config.defaultValue to Config.key, QrPassword.defaultValue to QrPassword.key, diff --git a/domain/src/main/java/com/yapp/domain/model/Session.kt b/domain/src/main/java/com/yapp/domain/model/Session.kt index b75435fb..9b8c6fa2 100644 --- a/domain/src/main/java/com/yapp/domain/model/Session.kt +++ b/domain/src/main/java/com/yapp/domain/model/Session.kt @@ -1,12 +1,22 @@ package com.yapp.domain.model import com.yapp.domain.model.types.NeedToAttendType +import java.time.LocalDateTime data class Session( val sessionId: Int, val title: String, val type: NeedToAttendType, - val startTime: String, + val startTime: LocalDateTime, val description: String, - val code: String, -) + val code: String +) { + + val monthAndDay: String + get() = String.format(TWO_DIGIT, startTime.month.value) + "." + String.format(TWO_DIGIT, startTime.dayOfMonth) + + companion object { + private const val TWO_DIGIT = "%02d" + } + +} \ No newline at end of file diff --git a/domain/src/main/java/com/yapp/domain/repository/RemoteConfigRepository.kt b/domain/src/main/java/com/yapp/domain/repository/RemoteConfigRepository.kt index 7cc30100..0e708443 100644 --- a/domain/src/main/java/com/yapp/domain/repository/RemoteConfigRepository.kt +++ b/domain/src/main/java/com/yapp/domain/repository/RemoteConfigRepository.kt @@ -8,7 +8,6 @@ import com.yapp.domain.model.Version interface RemoteConfigRepository { suspend fun getMaginotlineTime(): Result - suspend fun getSessionList(): Result> suspend fun getConfig(): Result suspend fun getTeamList(): Result> suspend fun getQrPassword(): Result diff --git a/domain/src/main/java/com/yapp/domain/repository/SessionRepository.kt b/domain/src/main/java/com/yapp/domain/repository/SessionRepository.kt index b44c6ceb..4156742d 100644 --- a/domain/src/main/java/com/yapp/domain/repository/SessionRepository.kt +++ b/domain/src/main/java/com/yapp/domain/repository/SessionRepository.kt @@ -4,6 +4,6 @@ import com.yapp.domain.model.Session interface SessionRepository { suspend fun setSession(session: Session): Result - suspend fun getSession(id: Long): Result + suspend fun getSession(id: Int): Result suspend fun getAllSession(): Result> } diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt new file mode 100644 index 00000000..15fa73ae --- /dev/null +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt @@ -0,0 +1,31 @@ +package com.yapp.domain.usecases + +import java.time.Duration +import java.time.LocalDateTime +import javax.inject.Inject + + +class CheckAttendanceTimeUseCase @Inject constructor( + private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase +) { + + companion object { + private const val BEFORE_5_MINUTE = -5 + private const val AFTER_30_MINUTE = 30 + } + + suspend operator fun invoke(): Result { + val currentTime = LocalDateTime.now() + + return getUpcomingSessionUseCase().mapCatching { upComingSession -> + if (upComingSession == null) { + return@mapCatching false + } + + val elapsedTimeInMinutes = Duration.between(upComingSession.startTime, currentTime).toMinutes() + + elapsedTimeInMinutes in BEFORE_5_MINUTE..AFTER_30_MINUTE + } + } + +} diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt deleted file mode 100644 index 384d958c..00000000 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.yapp.domain.usecases - -import com.yapp.domain.model.Session -import com.yapp.domain.repository.SessionRepository -import com.yapp.domain.util.DateUtil -import javax.inject.Inject - - -class CheckQrAuthTimeUseCase @Inject constructor( - private val sessionRepository: SessionRepository, -) { - - companion object { - private const val BEFORE_5_MINUTE = -5 - private const val AFTER_30_MINUTE = 30 - } - - suspend operator fun invoke(): Result { - return sessionRepository.getAllSession().mapCatching { sessionList: List -> - val upCommingSession = sessionList.firstOrNull { DateUtil.isUpcomingSession(it.startTime) } ?: return@mapCatching false - val elapsedTime = DateUtil.getElapsedTime(upCommingSession.startTime) - - return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE - } - } - -} diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckSessionPasswordUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckSessionPasswordUseCase.kt index 49fe4cbe..50ba423c 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckSessionPasswordUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckSessionPasswordUseCase.kt @@ -1,14 +1,16 @@ package com.yapp.domain.usecases -import com.yapp.domain.repository.RemoteConfigRepository +import com.yapp.domain.repository.SessionRepository import javax.inject.Inject class CheckSessionPasswordUseCase @Inject constructor( - private val remoteConfigRepository: RemoteConfigRepository, + private val sessionRepository: SessionRepository ) { - suspend operator fun invoke(inputPassword: String): Result { - return remoteConfigRepository.getSessionPassword().mapCatching { sessionPassword: String -> - inputPassword == sessionPassword + suspend operator fun invoke(sessionId: Int, inputPassword: String): Result { + return sessionRepository.getSession(id = sessionId).mapCatching { session -> + check(session != null) { "${sessionId}에 해당하는 Session이 존재하지 않습니다" } + + inputPassword == session.code } } } \ No newline at end of file diff --git a/domain/src/main/java/com/yapp/domain/usecases/GetCurrentTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/GetCurrentTimeUseCase.kt new file mode 100644 index 00000000..04b7addb --- /dev/null +++ b/domain/src/main/java/com/yapp/domain/usecases/GetCurrentTimeUseCase.kt @@ -0,0 +1,12 @@ +package com.yapp.domain.usecases + +import java.time.LocalDateTime +import javax.inject.Inject + +class GetCurrentTimeUseCase @Inject constructor() { + + operator fun invoke(): LocalDateTime { + return LocalDateTime.now() + } + +} diff --git a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt index 6fcdfb8e..e29cf321 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -2,17 +2,31 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.repository.SessionRepository -import com.yapp.domain.util.DateUtil +import java.time.LocalDateTime import javax.inject.Inject class GetUpcomingSessionUseCase @Inject constructor( - private val sessionRepository: SessionRepository, + private val sessionRepository: SessionRepository ) { suspend operator fun invoke(): Result { - // 세션 당일 밤 12시까지 return sessionRepository.getAllSession().mapCatching { sessionList -> - sessionList.firstOrNull { session -> DateUtil.isUpcomingSession(session.startTime) } + val currentTime = LocalDateTime.now() + + // 세션 당일 밤 12시까지 노출을 위해, 현재 시간의 일자와 일치하는 세션이 있는경우 Early Return + sessionList + .firstOrNull { session -> + session.startTime.year == currentTime.year && + session.startTime.month == currentTime.month && + session.startTime.dayOfMonth == currentTime.dayOfMonth + }?.let { todaySession -> + return@mapCatching todaySession + } + + sessionList.firstOrNull { session -> currentTime.isBefore(session.startTime) } + ?.let { nextSession -> + return@mapCatching nextSession + } } } } diff --git a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt index 282a91b9..9f351a35 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -4,31 +4,35 @@ import com.yapp.domain.model.Attendance import com.yapp.domain.model.Session import com.yapp.domain.repository.LocalRepository import com.yapp.domain.repository.MemberRepository -import com.yapp.domain.util.DateUtil +import java.time.Duration +import java.time.LocalDateTime import javax.inject.Inject class MarkAttendanceUseCase @Inject constructor( private val localRepository: LocalRepository, - private val memberRepository: MemberRepository, + private val memberRepository: MemberRepository ) { suspend operator fun invoke(checkedSession: Session): Result { return localRepository.getMemberId().mapCatching { currentUserId: Long? -> require(currentUserId != null) + val currentTime = LocalDateTime.now() val currentMemberInfo = memberRepository.getMember(currentUserId).getOrThrow() currentMemberInfo!!.attendances.changeAttendanceType( sessionId = checkedSession.sessionId, - changingAttendance = checkAttendanceState(checkedSession.startTime) + changingAttendance = checkAttendanceState( + elapsedTime = Duration.between(checkedSession.startTime, currentTime).toMinutes() + ) ).also { updatedAttendanceList -> memberRepository.setMember(member = currentMemberInfo.copy(attendances = updatedAttendanceList)) } } } - private fun checkAttendanceState(sessionDate: String): Attendance.Status { - return when (DateUtil.getElapsedTime(sessionDate)) { + private fun checkAttendanceState(elapsedTime: Long): Attendance.Status { + return when (elapsedTime) { in -5..5 -> Attendance.Status.NORMAL in 6..30 -> Attendance.Status.LATE else -> Attendance.Status.ABSENT diff --git a/domain/src/main/java/com/yapp/domain/usecases/SetSessionUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/SetSessionUseCase.kt index 8f3f4f5d..4a4778cb 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/SetSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/SetSessionUseCase.kt @@ -3,15 +3,17 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.model.types.NeedToAttendType import com.yapp.domain.repository.SessionRepository +import com.yapp.domain.util.DateParser import javax.inject.Inject class SetSessionUseCase @Inject constructor( private val sessionRepository: SessionRepository, + private val dateParser: DateParser ) { suspend operator fun invoke( title: String, type: NeedToAttendType, - startTime: String, + rawDate: String, description: String, code: String, ): Result { @@ -27,7 +29,7 @@ class SetSessionUseCase @Inject constructor( sessionId = newSessionId, title = title, type = type, - startTime = startTime, + startTime = dateParser.parse(rawDate = rawDate), description = description, code = code ) diff --git a/domain/src/main/java/com/yapp/domain/util/DateParser.kt b/domain/src/main/java/com/yapp/domain/util/DateParser.kt new file mode 100644 index 00000000..0608d9ca --- /dev/null +++ b/domain/src/main/java/com/yapp/domain/util/DateParser.kt @@ -0,0 +1,37 @@ +package com.yapp.domain.util + +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import javax.inject.Inject + +class DateParser @Inject constructor() { + + fun parse( + rawDate: String, + formatter: DateTimeFormatter = DATE_FORMAT_WITH_TIME + ): LocalDateTime { + require(rawDate.isNotBlank()) + + return LocalDateTime.parse(rawDate, formatter) + } + + fun format( + date: LocalDateTime, + formatter: DateTimeFormatter = DATE_FORMAT_WITH_TIME + ): String { + return formatter.format(date) + } + + fun format( + date: LocalDateTime, + format: String + ): String { + val formatter = DateTimeFormatter.ofPattern(format) + + return formatter.format(date) + } + + companion object { + private val DATE_FORMAT_WITH_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + } +} \ No newline at end of file diff --git a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt deleted file mode 100644 index edb76220..00000000 --- a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.yapp.domain.util - -import java.text.SimpleDateFormat -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import java.util.Locale - -object DateUtil { - - private const val oneSecond = 1000 - private const val oneMinute = 60 * oneSecond - private const val oneHour = 60 * oneMinute - private const val oneDay = 24 * oneHour - - // 현재 시각이 session 시작 시간에서 몇 분 지났는지 계산 - // 세션 시작 시간이 지난 경우 양수(+) - // 세션 시작이 아직 남은 경우 음수(-) - fun getElapsedTime(sessionDateStr: String): Long { - val currentDate = System.currentTimeMillis() - val sessionDate = - SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.KOREA).parse(sessionDateStr).time - return (currentDate - sessionDate) / oneMinute - } - - // 다가오는 세션인지 확인 - // 세션 날짜가 오늘 이후이면 true - fun isUpcomingSession(sessionDateStr: String): Boolean { - val currentDate = - SimpleDateFormat("yyyy-MM-dd", Locale.KOREA).format(System.currentTimeMillis()) - val sessionDate = sessionDateStr.substring(0, 10) - return currentDate <= sessionDate - } - - // 지난 세션인지 확인 - // 세션 시작 시간이 지나면 true - fun isPastSession(sessionDateStr: String): Boolean { - return getElapsedTime(sessionDateStr) >= 0 - } - - fun parseDate(date: String, format: String): String { - val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - - if (date.isEmpty()) { - val now = LocalDateTime.now() - return formatter.format(now) - } - - val currentDate = formatter.parse(date) - return DateTimeFormatter.ofPattern(format).format(currentDate) - } -} diff --git a/domain/src/test/java/DateParserTest.kt b/domain/src/test/java/DateParserTest.kt new file mode 100644 index 00000000..eeb842fd --- /dev/null +++ b/domain/src/test/java/DateParserTest.kt @@ -0,0 +1,33 @@ +import com.yapp.domain.util.DateParser +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe + +class DateParserTest : BehaviorSpec({ + val dateParser = DateParser() + + given("2024-01-04 14:00:00 String 날짜를") { + val rawDate = "2024-01-04 14:12:34" + + `when`("parsing 했을 때") { + val result = dateParser.parse(rawDate = rawDate) + + then("Year 은 2024년 이다") { result.year shouldBe 2024 } + then("Month 는 1월 이다") { result.monthValue shouldBe 1 } + then("Day 는 4일 이다") { result.dayOfMonth shouldBe 4 } + + then("Hour 는 4일 이다") { result.hour shouldBe 14 } + then("Minute 는 4일 이다") { result.minute shouldBe 12 } + then("Second 는 4일 이다") { result.second shouldBe 34 } + } + } + + given("2024-01-04 14:00:00 LocalDateTime을") { + val date = dateParser.parse("2024-01-04 14:00:00") + + `when`("Formatting 했을 때") { + val rawString = dateParser.format(date = date) + + then("'2024-01-04 14:00:00' 의 문자열을 반환한다") { rawString shouldBe "2024-01-04 14:00:00" } + } + } +}) \ No newline at end of file diff --git a/presentation/src/main/java/com/yapp/presentation/common/AttendanceTypeMapper.kt b/presentation/src/main/java/com/yapp/presentation/common/AttendanceTypeMapper.kt new file mode 100644 index 00000000..036f2f70 --- /dev/null +++ b/presentation/src/main/java/com/yapp/presentation/common/AttendanceTypeMapper.kt @@ -0,0 +1,33 @@ +package com.yapp.presentation.common + +import com.yapp.common.yds.YDSAttendanceType +import com.yapp.domain.model.Attendance +import com.yapp.domain.model.types.NeedToAttendType +import javax.inject.Inject + +class AttendanceTypeMapper @Inject constructor() { + + fun map( + sessionType: NeedToAttendType, + attendanceStatus: Attendance.Status, + isPastSession: Boolean + ): YDSAttendanceType { + if (isPastSession.not()) { + return YDSAttendanceType.TBD + } + if (sessionType == NeedToAttendType.DONT_NEED_ATTENDANCE) { + return YDSAttendanceType.NO_ATTENDANCE + } + if (sessionType == NeedToAttendType.DAY_OFF) { + return YDSAttendanceType.NO_YAPP + } + + return when (attendanceStatus) { + Attendance.Status.ABSENT -> YDSAttendanceType.ABSENT + Attendance.Status.ADMIT -> YDSAttendanceType.ATTEND + Attendance.Status.LATE -> YDSAttendanceType.TARDY + Attendance.Status.NORMAL -> YDSAttendanceType.ATTEND + } + } + +} \ No newline at end of file diff --git a/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt index a1a00b84..2ace70da 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt @@ -1,7 +1,7 @@ package com.yapp.presentation.ui import com.yapp.common.base.BaseViewModel -import com.yapp.domain.usecases.CheckQrAuthTimeUseCase +import com.yapp.domain.usecases.CheckAttendanceTimeUseCase import com.yapp.domain.usecases.MarkAttendanceUseCase import com.yapp.presentation.R import com.yapp.presentation.common.AttendanceBundle @@ -14,7 +14,7 @@ import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor( private val resourcesProvider: ResourceProvider, - private val checkQrAuthTime: CheckQrAuthTimeUseCase, + private val checkAttendanceTime: CheckAttendanceTimeUseCase, private val markAttendanceUseCase: MarkAttendanceUseCase ) : BaseViewModel( MainContract.MainUiState() @@ -29,7 +29,7 @@ class MainViewModel @Inject constructor( private suspend fun checkAttendanceValidate() = coroutineScope { if (AttendanceBundle.isAbsent) { - checkQrAuthTime() + checkAttendanceTime() .onSuccess { isQRCheckEnable -> if (isQRCheckEnable) { setEffect(MainContract.MainUiSideEffect.NavigateToPassword) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/createsession/CreateSessionViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/createsession/CreateSessionViewModel.kt index 7a435806..e0675aa3 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/createsession/CreateSessionViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/createsession/CreateSessionViewModel.kt @@ -82,7 +82,7 @@ class CreateSessionViewModel @Inject constructor( setSessionUseCase( title = currentState.title, type = type, - startTime = currentState.startTime, + rawDate = currentState.startTime, description = currentState.description, code = currentState.code, ).onSuccess { diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMain.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMain.kt index 0f47fae2..1c428cd0 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMain.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMain.kt @@ -280,7 +280,8 @@ fun LazyListScope.GraySpacing(modifier: Modifier) { fun LazyListScope.GrayDivider(modifier: Modifier) { item { Divider( - modifier = modifier.fillMaxWidth() + modifier = modifier + .fillMaxWidth() .padding(horizontal = 24.dp) .background(AttendanceTheme.colors.grayScale.Gray300) ) @@ -291,9 +292,6 @@ fun LazyListScope.UpcomingSession( upcomingSession: Session, onManagementButtonClicked: (Int, String) -> Unit, ) { - val MONTH_RANGE = 5..6 - val DAY_RANGE = 8..9 - item { Column( modifier = Modifier @@ -301,8 +299,7 @@ fun LazyListScope.UpcomingSession( .padding(horizontal = 24.dp) ) { Text( - text = upcomingSession.startTime.substring(MONTH_RANGE) + - "." + upcomingSession.startTime.substring(DAY_RANGE), + text = upcomingSession.monthAndDay, color = AttendanceTheme.colors.grayScale.Gray600, style = AttendanceTypography.body2, ) @@ -383,9 +380,6 @@ private fun SessionItem( session: Session, onSessionItemClicked: (Int, String) -> Unit, ) { - val MONTH_RANGE = 5..6 - val DAY_RANGE = 8..9 - Row( modifier = Modifier .fillMaxWidth() @@ -404,7 +398,7 @@ private fun SessionItem( Text( modifier = Modifier.width(64.dp), - text = "${session.startTime.substring(MONTH_RANGE)}.${session.startTime.substring(DAY_RANGE)}", + text = session.monthAndDay, color = textColor, style = AttendanceTypography.body1, ) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMainViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMainViewModel.kt index 47110c35..6b16a2fd 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMainViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMainViewModel.kt @@ -2,11 +2,10 @@ package com.yapp.presentation.ui.admin.main import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel -import com.yapp.domain.model.Session import com.yapp.domain.model.collections.AttendanceList +import com.yapp.domain.usecases.GetCurrentTimeUseCase import com.yapp.domain.usecases.GetSessionListUseCase import com.yapp.domain.usecases.GetUpcomingSessionUseCase -import com.yapp.domain.util.DateUtil import com.yapp.presentation.ui.admin.main.AdminMainContract.AdminMainUiEvent import com.yapp.presentation.ui.admin.main.AdminMainContract.AdminMainUiSideEffect import com.yapp.presentation.ui.admin.main.AdminMainContract.AdminMainUiState @@ -18,9 +17,8 @@ import javax.inject.Inject class AdminMainViewModel @Inject constructor( private val getSessionListUseCase: GetSessionListUseCase, private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase, -) : BaseViewModel( - AdminMainUiState() -) { + private val getCurrentTimeUseCase: GetCurrentTimeUseCase +) : BaseViewModel(AdminMainUiState()) { init { viewModelScope.launch { @@ -31,29 +29,24 @@ class AdminMainViewModel @Inject constructor( override suspend fun handleEvent(event: AdminMainUiEvent) { when (event) { - is AdminMainUiEvent.OnUserScoreCardClicked -> setEffect( - AdminMainUiSideEffect.NavigateToAdminTotalScore(event.lastSessionId) - ) - is AdminMainUiEvent.OnCreateSessionClicked -> setEffect( - AdminMainUiSideEffect.NavigateToCreateSession - ) - is AdminMainUiEvent.OnSessionClicked -> setEffect( - AdminMainUiSideEffect.NavigateToManagement(event.sessionId, event.sessionTitle) - ) - is AdminMainUiEvent.OnLogoutClicked -> setEffect( - AdminMainUiSideEffect.NavigateToLogin - ) + is AdminMainUiEvent.OnUserScoreCardClicked -> setEffect(AdminMainUiSideEffect.NavigateToAdminTotalScore(event.lastSessionId)) + + is AdminMainUiEvent.OnCreateSessionClicked -> setEffect(AdminMainUiSideEffect.NavigateToCreateSession) + + is AdminMainUiEvent.OnSessionClicked -> setEffect(AdminMainUiSideEffect.NavigateToManagement(event.sessionId, event.sessionTitle)) + + is AdminMainUiEvent.OnLogoutClicked -> setEffect(AdminMainUiSideEffect.NavigateToLogin) } } private suspend fun getSessions() { getSessionListUseCase() .onSuccess { sessions -> - val upcomingSession = - sessions.firstOrNull { DateUtil.isUpcomingSession(it.startTime) } + val upcomingSession = getUpcomingSessionUseCase().getOrThrow() + val currentTime = getCurrentTimeUseCase() upcomingSession?.let { - var lastSessionId = if (isUpcomingSessionIsStarted(it)) it.sessionId else it.sessionId - 1 + var lastSessionId = if (currentTime.isAfter(upcomingSession.startTime)) it.sessionId else it.sessionId - 1 if (lastSessionId < 0) lastSessionId = AttendanceList.DEFAULT_UPCOMING_SESSION_ID setState { copy(lastSessionId = lastSessionId) } } @@ -70,8 +63,4 @@ class AdminMainViewModel @Inject constructor( setState { copy(loadState = AdminMainUiState.LoadState.Error) } } } - - private fun isUpcomingSessionIsStarted(upcomingSession: Session): Boolean { - return DateUtil.isPastSession(upcomingSession.startTime) - } } diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/Management.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/Management.kt index cd90c297..1393815e 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/Management.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/Management.kt @@ -246,7 +246,7 @@ internal fun ManagementScreen( FoldableHeaderItem( modifier = Modifier.animateItemPlacement(), state = itemState, - onExpandClicked = { isExpanded, teamName, teamNumber -> + onExpandClicked = { _, teamName, teamNumber -> onEvent(ManagementEvent.OnTeamTypeHeaderItemClicked(teamName, teamNumber)) } ) @@ -259,7 +259,7 @@ internal fun ManagementScreen( FoldableHeaderItem( modifier = Modifier.animateItemPlacement(), state = itemState, - onExpandClicked = { isExpanded, position -> + onExpandClicked = { _, position -> onEvent(ManagementEvent.OnPositionTypeHeaderItemClicked(positionName = position)) } ) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/AnimatedCounterText.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/AnimatedCounterText.kt index a6501296..e6906f14 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/AnimatedCounterText.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/AnimatedCounterText.kt @@ -42,18 +42,17 @@ internal fun AnimatedCounterText( for (i in countString.indices) { val oldChar = oldCountString.getOrNull(i) val newChar = countString[i] - val char = if (oldChar == newChar) { + val updatedChar = if (oldChar == newChar) { oldCountString[i] } else { countString[i] } AnimatedContent( - targetState = char, + targetState = updatedChar, transitionSpec = { slideInVertically { it } with slideOutVertically { -it } - } + }, label = "" ) { char -> - Text( text = char.toString(), style = style, diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/foldableItem/foldableHeaderItem/FoldableItemHeaderLayout.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/foldableItem/foldableHeaderItem/FoldableItemHeaderLayout.kt index a0230343..5b34e921 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/foldableItem/foldableHeaderItem/FoldableItemHeaderLayout.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/foldableItem/foldableHeaderItem/FoldableItemHeaderLayout.kt @@ -61,14 +61,14 @@ private fun FoldableItemHeaderLayoutPreview() { Column(modifier = Modifier) { FoldableHeaderItem( state = teamState, - onExpandClicked = { a, b, c -> + onExpandClicked = { _, _, _ -> } ) FoldableHeaderItem( state = positionState, - onExpandClicked = { a, b -> + onExpandClicked = { _, _ -> } ) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayout.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayout.kt index bd07b3ff..501e32d6 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayout.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayout.kt @@ -117,7 +117,7 @@ internal fun YDSTabLayout( val widthList = mutableListOf() val tabLabelPlaceables = measurables.filter { it.layoutId == LAYOUT_ID_SELECTED_TAB_LABEL || it.layoutId == LAYOUT_ID_UNSELECTED_TAB_LABEL } - .mapIndexed { index, tabLabelMeasurable -> + .mapIndexed { _, tabLabelMeasurable -> tabLabelMeasurable.measure(constraints).also { placeable -> tabLabelMaxHeight = max(tabLabelMaxHeight, placeable.height) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayoutItemStateList.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayoutItemStateList.kt index 88337c0b..dba93f92 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayoutItemStateList.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/management/components/tablayout/YDSTabLayoutItemStateList.kt @@ -18,7 +18,7 @@ data class YDSTabLayoutItemStateList( fun select(targetIndex: Int): YDSTabLayoutItemStateList { return this.copy( - value = value.mapIndexed { index, itemState -> + value = value.mapIndexed { _, itemState -> if (itemState.isSelected) { return@mapIndexed itemState.unSelect() } diff --git a/presentation/src/main/java/com/yapp/presentation/ui/admin/totalscore/AdminTotalScore.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/totalscore/AdminTotalScore.kt index 65d29606..4dbcda2f 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/admin/totalscore/AdminTotalScore.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/admin/totalscore/AdminTotalScore.kt @@ -143,7 +143,7 @@ fun AdminTotalScoreScreen( FoldableHeaderItem( modifier = Modifier.animateItemPlacement(), state = itemState, - onExpandClicked = { isExpanded, teamName, teamNumber -> + onExpandClicked = { _, teamName, teamNumber -> onEvent(AdminTotalScoreUiEvent.OnTeamTypeHeaderItemClicked(teamName, teamNumber)) } ) @@ -156,7 +156,7 @@ fun AdminTotalScoreScreen( FoldableHeaderItem( modifier = Modifier.animateItemPlacement(), state = itemState, - onExpandClicked = { isExpanded, position -> + onExpandClicked = { _, position -> onEvent(AdminTotalScoreUiEvent.OnPositionTypeHeaderItemClicked(positionName = position)) } ) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScore.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScore.kt index 28b35f41..26b01bba 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScore.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScore.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -54,15 +55,13 @@ import com.yapp.common.theme.AttendanceTheme import com.yapp.common.theme.AttendanceTypography import com.yapp.common.yds.YDSAppBar import com.yapp.common.yds.YDSAttendanceList +import com.yapp.common.yds.YDSAttendanceType import com.yapp.common.yds.YDSEmptyScreen import com.yapp.common.yds.YDSProgressBar import com.yapp.domain.model.Attendance import com.yapp.domain.model.Session import com.yapp.domain.model.types.NeedToAttendType import com.yapp.presentation.R -import com.yapp.presentation.util.attendance.checkSessionAttendance -import java.text.SimpleDateFormat -import java.util.Locale @Composable fun MemberScore( @@ -93,7 +92,6 @@ fun MemberScore( navigateToSessionDetail = navigateToSessionDetail ) } - } } @@ -131,8 +129,13 @@ fun MemberScoreScreen( .background(AttendanceTheme.colors.backgroundColors.background) ) } - items(uiState.attendanceList) { attendanceInfo -> - AttendUserSession(attendanceInfo, navigateToSessionDetail) + + items(uiState.attendanceList) { (session, attendanceType) -> + AttendUserSession( + session = session, + attendanceType = attendanceType, + navigateToSessionDetail = navigateToSessionDetail, + ) } } } @@ -156,9 +159,7 @@ private fun HelpIcon(navigateToHelpScreen: () -> Unit) { .align(Alignment.TopEnd) .padding(top = 18.dp, end = 14.dp) .clip(CircleShape) - .clickable { - navigateToHelpScreen() - } + .clickable { navigateToHelpScreen() } .padding(10.dp), ) } @@ -194,23 +195,15 @@ fun SemiCircleProgressBar(score: Int) { Column( verticalArrangement = Arrangement.Center, ) { - BoxWithConstraints( - modifier = Modifier - .padding(start = 64.dp, end = 64.dp), - ) { - + BoxWithConstraints(modifier = Modifier.padding(start = 64.dp, end = 64.dp)) { val gray200 = AttendanceTheme.colors.grayScale.Gray200 val etcGreen = AttendanceTheme.colors.etcColors.EtcGreen val etcYellow = AttendanceTheme.colors.etcColors.EtcYellow val etcRed = AttendanceTheme.colors.etcColors.EtcRed - androidx.compose.foundation.Canvas( - modifier = Modifier - .size(maxWidth, (maxWidth.value / 2).dp) - ) { - + Canvas(modifier = Modifier.size(maxWidth, (maxWidth.value / 2).dp)) { val arcColor = fillColorByUserScore(score).let { score -> - when(score) { + when (score) { Score.GOOD -> etcGreen Score.NORMAL -> etcYellow Score.DANGEROUS -> etcRed @@ -226,7 +219,6 @@ fun SemiCircleProgressBar(score: Int) { style = Stroke(width = 25f, cap = StrokeCap.Round) ) - drawArc( color = arcColor, startAngle = 180f, @@ -335,18 +327,13 @@ fun RowScope.AttendanceCell( @Composable private fun AttendUserSession( - attendanceInfo: Pair, + session: Session, + attendanceType: YDSAttendanceType, navigateToSessionDetail: (Int) -> Unit ) { - val session = attendanceInfo.first - val attendance = attendanceInfo.second - YDSAttendanceList( - attendanceType = checkSessionAttendance(session, attendance)!!, - date = SimpleDateFormat( - "MM.dd", - Locale.KOREA - ).format(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.KOREA).parse(session.startTime)?.time), + attendanceType = attendanceType, + date = session.monthAndDay, title = session.title, description = session.description, ) { diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreContract.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreContract.kt index 6dcfc9f0..4eedb2f7 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreContract.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreContract.kt @@ -3,14 +3,15 @@ package com.yapp.presentation.ui.member.score import com.yapp.common.base.UiEvent import com.yapp.common.base.UiSideEffect import com.yapp.common.base.UiState +import com.yapp.common.yds.YDSAttendanceType import com.yapp.domain.model.Attendance import com.yapp.domain.model.Session class MemberScoreContract { data class MemberScoreUiState( val loadState: LoadState = LoadState.Loading, - val attendanceList: List> = emptyList(), - val lastAttendanceList: List> = emptyList(), + val attendanceList: List> = emptyList(), + val lastAttendanceList: List> = emptyList() ) : UiState { enum class LoadState { Loading, Idle, Error diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreViewModel.kt index 2cf06c40..6dbdc610 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScoreViewModel.kt @@ -2,8 +2,9 @@ package com.yapp.presentation.ui.member.score import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel +import com.yapp.domain.usecases.GetCurrentTimeUseCase import com.yapp.domain.usecases.GetMemberAttendanceListUseCase -import com.yapp.domain.util.DateUtil +import com.yapp.presentation.common.AttendanceTypeMapper import com.yapp.presentation.ui.member.score.MemberScoreContract.MemberScoreUiEvent import com.yapp.presentation.ui.member.score.MemberScoreContract.MemberScoreUiSideEffect import com.yapp.presentation.ui.member.score.MemberScoreContract.MemberScoreUiState @@ -15,6 +16,8 @@ import javax.inject.Inject @HiltViewModel class MemberScoreViewModel @Inject constructor( private val getMemberAttendanceListUseCase: GetMemberAttendanceListUseCase, + private val getCurrentTimeUseCase: GetCurrentTimeUseCase, + private val attendanceTypeMapper: AttendanceTypeMapper ) : BaseViewModel(initialState = MemberScoreUiState()) { init { @@ -30,13 +33,23 @@ class MemberScoreViewModel @Inject constructor( return@onSuccess } - val attendanceList = sessions zip attendances + val currentTime = getCurrentTimeUseCase() + val attendanceList = (sessions zip attendances).map { (session, attendance) -> + val attendanceType = attendanceTypeMapper.map( + sessionType = session.type, + attendanceStatus = attendance.status, + isPastSession = currentTime.isAfter(session.startTime) + ) + + session to attendanceType + } + setState { copy( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, - lastAttendanceList = attendanceList.filter { - DateUtil.isPastSession(it.first.startTime) + lastAttendanceList = (sessions zip attendances).filter { (session, _) -> + currentTime.isAfter(session.startTime) } ) } diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetail.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetail.kt index 7abceaf4..8265445a 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetail.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetail.kt @@ -16,8 +16,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.google.accompanist.insets.systemBarsPadding @@ -27,26 +25,21 @@ import com.yapp.common.yds.YDSAppBar import com.yapp.common.yds.YDSAttendanceType import com.yapp.common.yds.YDSEmptyScreen import com.yapp.common.yds.YDSProgressBar -import com.yapp.domain.model.Session -import com.yapp.presentation.util.attendance.checkSessionAttendance -import java.text.SimpleDateFormat -import java.util.Locale +import com.yapp.common.yds.icon +import com.yapp.common.yds.text @Composable fun SessionDetail( viewModel: SessionDetailViewModel = hiltViewModel(), onClickBackButton: () -> Unit, ) { - val uiState by viewModel.uiState.collectAsState() - val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance(session, uiState.session?.second) Scaffold( topBar = { YDSAppBar( modifier = Modifier.background(AttendanceTheme.colors.backgroundColors.background), - title = session?.title ?: "", + title = uiState.appBarTitle, onClickBackButton = onClickBackButton ) }, @@ -60,8 +53,7 @@ fun SessionDetail( SessionDetailContract.SessionDetailUiState.LoadState.Error -> YDSEmptyScreen() SessionDetailContract.SessionDetailUiState.LoadState.Idle -> SessionDetailScreen( modifier = Modifier.padding(contentPadding), - session = session, - attendance = attendance + state = uiState.screenState ) } } @@ -70,10 +62,8 @@ fun SessionDetail( @Composable fun SessionDetailScreen( modifier: Modifier = Modifier, - session: Session?, - attendance: YDSAttendanceType? + state: SessionDetailContract.SessionDetailUiState.SessionDetailScreenState ) { - Column( modifier = modifier .fillMaxSize() @@ -81,59 +71,46 @@ fun SessionDetailScreen( .padding(horizontal = 24.dp, vertical = 40.dp) ) { Row( - modifier = Modifier - .fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - if (attendance != null) { - if (attendance in listOf( - YDSAttendanceType.ABSENT, - YDSAttendanceType.ATTEND, - YDSAttendanceType.TARDY - ) - ) { - Icon( - painterResource(attendance.icon), - contentDescription = null, - tint = Color.Unspecified, - ) - } - Text( - text = stringResource(id = attendance.title), - modifier = Modifier - .fillMaxWidth() - .weight(1f) - .padding(horizontal = 4.dp), - color = when (attendance) { - YDSAttendanceType.ATTEND -> AttendanceTheme.colors.etcColors.EtcGreen - YDSAttendanceType.ABSENT -> AttendanceTheme.colors.etcColors.EtcRed - YDSAttendanceType.TARDY -> AttendanceTheme.colors.etcColors.EtcYellowFont - YDSAttendanceType.TBD, YDSAttendanceType.NO_ATTENDANCE, YDSAttendanceType.NO_YAPP -> AttendanceTheme.colors.grayScale.Gray400 - } - ) - } - if (session != null) { - val sessionDate = - SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.KOREA).parse(session.startTime)?.time - Text( - text = SimpleDateFormat("MM.dd", Locale.KOREA).format(sessionDate), - style = AttendanceTypography.body1, - color = AttendanceTheme.colors.grayScale.Gray600 + if (state.shouldShowIcon) { + Icon( + painter = state.attendanceType.icon(), + contentDescription = null, + tint = Color.Unspecified, ) } - + Text( + text = state.attendanceType.text(), + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 4.dp), + color = when (state.attendanceType) { + YDSAttendanceType.ATTEND -> AttendanceTheme.colors.etcColors.EtcGreen + YDSAttendanceType.ABSENT -> AttendanceTheme.colors.etcColors.EtcRed + YDSAttendanceType.TARDY -> AttendanceTheme.colors.etcColors.EtcYellowFont + YDSAttendanceType.TBD, YDSAttendanceType.NO_ATTENDANCE, YDSAttendanceType.NO_YAPP -> AttendanceTheme.colors.grayScale.Gray400 + } + ) + Text( + text = state.date, + style = AttendanceTypography.body1, + color = AttendanceTheme.colors.grayScale.Gray600 + ) } Text( - text = session?.title ?: "", + text = state.title, modifier = Modifier.padding(top = 28.dp), style = AttendanceTypography.h1, color = AttendanceTheme.colors.grayScale.Gray1000 ) Text( - text = session?.description ?: "", + text = state.description, modifier = Modifier.padding(top = 12.dp), style = AttendanceTypography.body1, color = AttendanceTheme.colors.grayScale.Gray800 diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailContract.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailContract.kt index 0f0d0bbe..f1f8545f 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailContract.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailContract.kt @@ -3,17 +3,32 @@ package com.yapp.presentation.ui.member.score.detail import com.yapp.common.base.UiEvent import com.yapp.common.base.UiSideEffect import com.yapp.common.base.UiState -import com.yapp.domain.model.Attendance -import com.yapp.domain.model.Session +import com.yapp.common.yds.YDSAttendanceType class SessionDetailContract { data class SessionDetailUiState( val loadState: LoadState = LoadState.Idle, - val session: Pair? = null, + val appBarTitle: String = "", + val screenState: SessionDetailScreenState = SessionDetailScreenState() ) : UiState { enum class LoadState { Loading, Idle, Error } + + data class SessionDetailScreenState( + val title: String = "", + val description: String = "", + val date: String = "", + val attendanceType: YDSAttendanceType = YDSAttendanceType.ABSENT + ) { + + val shouldShowIcon: Boolean + get() = attendanceType in showingIconTypes + + private companion object { + val showingIconTypes = listOf(YDSAttendanceType.ABSENT, YDSAttendanceType.ATTEND, YDSAttendanceType.TARDY) + } + } } sealed class SessionDetailUiSideEffect : UiSideEffect {} diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailViewModel.kt index 8f20fd55..10379713 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/score/detail/SessionDetailViewModel.kt @@ -3,7 +3,13 @@ package com.yapp.presentation.ui.member.score.detail import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel +import com.yapp.domain.usecases.GetCurrentTimeUseCase import com.yapp.domain.usecases.GetMemberAttendanceListUseCase +import com.yapp.presentation.common.AttendanceTypeMapper +import com.yapp.presentation.ui.member.score.detail.SessionDetailContract.SessionDetailUiEvent +import com.yapp.presentation.ui.member.score.detail.SessionDetailContract.SessionDetailUiSideEffect +import com.yapp.presentation.ui.member.score.detail.SessionDetailContract.SessionDetailUiState +import com.yapp.presentation.ui.member.score.detail.SessionDetailContract.SessionDetailUiState.SessionDetailScreenState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest @@ -14,41 +20,57 @@ import javax.inject.Inject @HiltViewModel class SessionDetailViewModel @Inject constructor( private val getMemberAttendanceListUseCase: GetMemberAttendanceListUseCase, - private val savedStateHandle: SavedStateHandle, -) : BaseViewModel( - SessionDetailContract.SessionDetailUiState() -) { + private val getCurrentTimeUseCase: GetCurrentTimeUseCase, + private val attendanceTypeMapper: AttendanceTypeMapper, + savedStateHandle: SavedStateHandle, +) : BaseViewModel(SessionDetailUiState()) { init { - setState { copy(loadState = SessionDetailContract.SessionDetailUiState.LoadState.Loading) } + setState { copy(loadState = SessionDetailUiState.LoadState.Loading) } val sessionId = savedStateHandle.get("session") + val currentTime = getCurrentTimeUseCase() if (sessionId != null) { viewModelScope.launch { - getMemberAttendanceListUseCase().collectLatest { result -> - result.onSuccess { (sessions, attendances) -> - if (attendances.isEmpty()) { - setState { copy(loadState = SessionDetailContract.SessionDetailUiState.LoadState.Error) } - return@onSuccess - } + withContext(Dispatchers.IO) { + getMemberAttendanceListUseCase().collectLatest { result -> + result.onSuccess { (sessions, attendances) -> + if (attendances.isEmpty()) { + setState { copy(loadState = SessionDetailUiState.LoadState.Error) } + return@onSuccess + } + + val session = sessions[sessionId] + val attendance = attendances[sessionId] - setState { - copy( - loadState = SessionDetailContract.SessionDetailUiState.LoadState.Idle, - session = sessions[sessionId] to attendances[sessionId] - ) + setState { + copy( + loadState = SessionDetailUiState.LoadState.Idle, + appBarTitle = session.title, + screenState = SessionDetailScreenState( + title = session.title, + description = session.description, + date = session.monthAndDay, + attendanceType = attendanceTypeMapper.map( + sessionType = session.type, + attendanceStatus = attendance.status, + isPastSession = currentTime.isAfter(session.startTime) + ) + ) + ) + } } - }.onFailure { - setState { copy(loadState = SessionDetailContract.SessionDetailUiState.LoadState.Error) } + .onFailure { + setState { copy(loadState = SessionDetailUiState.LoadState.Error) } + } } } } } else { - setState { copy(loadState = SessionDetailContract.SessionDetailUiState.LoadState.Error) } + setState { copy(loadState = SessionDetailUiState.LoadState.Error) } } } - override suspend fun handleEvent(event: SessionDetailContract.SessionDetailUiEvent) { - TODO("Not yet implemented") - } + override suspend fun handleEvent(event: SessionDetailUiEvent) = Unit + } diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/PassWordViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/PassWordViewModel.kt index 54c6fc13..47b70706 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/PassWordViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/PassWordViewModel.kt @@ -5,6 +5,7 @@ import com.google.firebase.FirebaseNetworkException import com.yapp.common.base.BaseViewModel import com.yapp.domain.usecases.CheckSessionPasswordUseCase import com.yapp.domain.usecases.CheckSignUpPasswordUseCase +import com.yapp.presentation.common.AttendanceBundle import com.yapp.presentation.ui.member.signup.password.PasswordContract.PasswordSideEffect import com.yapp.presentation.ui.member.signup.password.PasswordContract.PasswordUiEvent import com.yapp.presentation.ui.member.signup.password.PasswordContract.PasswordUiState @@ -70,7 +71,11 @@ internal class PassWordViewModel @Inject constructor( private fun checkSessionPassword(password: String) = viewModelScope.launch { setEffect(PasswordSideEffect.KeyboardHide) - checkSessionPasswordUseCase(password) + + // TODO AttendanceBundle을 사용하지 않고 Navagation의 Argument로 넘어온 Id를 사용하도록 수정할것 + val sessionId = AttendanceBundle.upComingSession!!.sessionId + + checkSessionPasswordUseCase(sessionId = sessionId, inputPassword = password) .onSuccess { isPasswordValid -> when (isPasswordValid) { true -> { @@ -91,5 +96,5 @@ internal class PassWordViewModel @Inject constructor( } } } - + } diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/Password.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/Password.kt index c436c3a4..14cfaca0 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/Password.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/signup/password/Password.kt @@ -50,7 +50,7 @@ import com.yapp.common.theme.AttendanceTypography import com.yapp.common.theme.Light_Gray_200 import com.yapp.common.util.rememberKeyboardVisible import com.yapp.common.yds.YDSAppBar -import com.yapp.domain.util.DateUtil +import com.yapp.domain.util.DateParser import com.yapp.presentation.R import com.yapp.presentation.common.AttendanceBundle import com.yapp.presentation.ui.member.signup.name.OnKeyboardNextButton @@ -76,6 +76,7 @@ internal fun Password( val focusRequester = remember { FocusRequester() } val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current + val dateParser = remember { DateParser() } LaunchedEffect(Unit) { focusRequester.requestFocus() @@ -128,7 +129,7 @@ internal fun Password( ) { val title = when(type) { PasswordType.SignUp -> stringResource(id = R.string.member_signup_password_title) - PasswordType.Session -> stringResource(id = R.string.member_session_password_title, DateUtil.parseDate(AttendanceBundle.upComingSession?.startTime.orEmpty(), "MM월 dd일")) + PasswordType.Session -> stringResource(id = R.string.member_session_password_title, AttendanceBundle.upComingSession?.startTime?.let { dateParser.format(it, "MM월 dd일") } ?: "") } val subTitle = when(type) { PasswordType.SignUp -> stringResource(id = R.string.member_signup_password_subtitle) diff --git a/presentation/src/main/java/com/yapp/presentation/ui/member/todaysession/TodaySession.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/todaysession/TodaySession.kt index d90374e9..f80f7fcc 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/member/todaysession/TodaySession.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/member/todaysession/TodaySession.kt @@ -19,6 +19,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier @@ -41,6 +42,7 @@ import com.yapp.common.yds.YDSProgressBar import com.yapp.common.yds.YDSSingleButtonPopupDialog import com.yapp.domain.model.Attendance import com.yapp.domain.model.Session +import com.yapp.domain.util.DateParser import com.yapp.presentation.R import com.yapp.presentation.ui.AttendanceScreenRoute import com.yapp.presentation.ui.member.todaysession.TodaySessionContract.DialogState @@ -192,6 +194,7 @@ private fun TodaysAttendance(attendanceType: Attendance.Status) { @Composable private fun SessionDescriptionModal(session: Session?, modifier: Modifier) { + Column( modifier = modifier .layoutId("modal", "modal") @@ -201,9 +204,8 @@ private fun SessionDescriptionModal(session: Session?, modifier: Modifier) { .background(AttendanceTheme.colors.backgroundColors.background) .padding(24.dp), ) { - val sessionDate = session?.startTime?.substring(5, 10)?.replace("-", ".") Text( - text = sessionDate ?: "", + text = session?.monthAndDay ?: "", style = AttendanceTypography.body1, color = AttendanceTheme.colors.grayScale.Gray600 ) diff --git a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt b/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt deleted file mode 100644 index 136429d4..00000000 --- a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.yapp.presentation.util.attendance - -import com.yapp.common.yds.YDSAttendanceType -import com.yapp.domain.model.Attendance -import com.yapp.domain.model.Session -import com.yapp.domain.model.types.NeedToAttendType -import com.yapp.domain.util.DateUtil - -fun checkSessionAttendance( - session: Session?, - attendance: Attendance? -): YDSAttendanceType? { - if ((session == null) or (attendance == null)) { - return null - } - if (!DateUtil.isPastSession(session!!.startTime)) { - return YDSAttendanceType.TBD - } - if (session.type == NeedToAttendType.DONT_NEED_ATTENDANCE) { - return YDSAttendanceType.NO_ATTENDANCE - } - if (session.type == NeedToAttendType.DAY_OFF) { - return YDSAttendanceType.NO_YAPP - } - return when (attendance!!.status) { - Attendance.Status.ABSENT -> YDSAttendanceType.ABSENT - Attendance.Status.ADMIT -> YDSAttendanceType.ATTEND - Attendance.Status.LATE -> YDSAttendanceType.TARDY - Attendance.Status.NORMAL -> YDSAttendanceType.ATTEND - } -}