From a86ff60213bafd7357a08523d54dbe481753bb73 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 14 Jan 2024 18:05:59 +0900 Subject: [PATCH 01/26] =?UTF-8?q?RenewDateUtil=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DateUtil을 대체할 RenewDateUtil을 구현 - string Date로 계산하는것이 아닌 LocalDateTime을 기반한 RenewDateUtil 구현 - RenewDateUtil과 LocalDateTime에 대한 유닛테스트 작성 --- .../java/com/yapp/buildsrc/Dependencies.kt | 5 ++ domain/build.gradle.kts | 7 ++ .../com/yapp/domain/util/RenewDateUtil.kt | 63 ++++++++++++++ domain/src/test/java/DateParserTest.kt | 33 ++++++++ domain/src/test/java/DateUtilTest.kt | 83 +++++++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt create mode 100644 domain/src/test/java/DateParserTest.kt create mode 100644 domain/src/test/java/DateUtilTest.kt 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/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/util/RenewDateUtil.kt b/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt new file mode 100644 index 00000000..950574be --- /dev/null +++ b/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt @@ -0,0 +1,63 @@ +package com.yapp.domain.util + +import java.time.Duration +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import javax.inject.Inject + +typealias Minute = Long + +class RenewDateUtil { + + fun getCurrentTime(): LocalDateTime { + return LocalDateTime.now() + } + + /** + * [startTime] 에서 [target] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 + * 양수 (+) 일 경우 [target] 으로부터 시간이 이미 흐른상태, 음수 (-)인 경우 시간이 아직 [target] 까지 시간이 흐르지 않은상태 + */ + fun getElapsedTimeInMinute( + target: LocalDateTime, + current: LocalDateTime = getCurrentTime() + ): Minute { + return Duration.between(target, current).toMinutes() + } + + fun isUpcomingDate( + target: LocalDateTime, + current: LocalDateTime = getCurrentTime() + ): Boolean { + return current <= target + } + + fun isPastDate( + target: LocalDateTime, + current: LocalDateTime = getCurrentTime() + ): Boolean { + return getElapsedTimeInMinute(target, current) >= 0 + } +} + +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) + } + + companion object { + private val DATE_FORMAT_WITH_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + } +} 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/domain/src/test/java/DateUtilTest.kt b/domain/src/test/java/DateUtilTest.kt new file mode 100644 index 00000000..e5108d11 --- /dev/null +++ b/domain/src/test/java/DateUtilTest.kt @@ -0,0 +1,83 @@ +import com.yapp.domain.util.DateParser +import com.yapp.domain.util.RenewDateUtil +import io.kotest.core.spec.style.BehaviorSpec +import io.kotest.matchers.shouldBe + +class DateUtilTest : BehaviorSpec({ + val dateParser = DateParser() + val dateUtil = RenewDateUtil() + + given("[세션시간]과 그로 부터 [30분 전 시간]이 주어진 경우") { + val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") + val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:30:00") + + `when`("두 시간의 차를 분 단위로 구하면") { + val result = dateUtil.getElapsedTimeInMinute(target = sessionTime, current = currentTime) + + then("차이는 -30분 이다") { result shouldBe -30 } + } + + `when`("곧 앞으로 다가올 Date인지 확인 했을때") { + val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + + then("앞으로 다가올 Date 이다") { result shouldBe true } + } + + `when`("이미 지난 Date인지 확인 했을때") { + val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + + then("이미 지난 Date가 아니다") { result shouldBe false } + } + } + + given("[세션시간]과 그로 부터 [20분이 지난 시간]이 주어진 경우") { + val currentTime = dateParser.parse(rawDate = "2024-01-04 14:20:00") + val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") + + `when`("두 시간의 차를 분 단위로 구했을 때") { + val result = dateUtil.getElapsedTimeInMinute(target = sessionTime, current = currentTime) + + then("차이는 20분 이다") { result shouldBe 20 } + } + + `when`("앞으로 다가올 Date인지 확인 했을때") { + val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + + then("앞으로 다가올 세션이 아니다") { result shouldBe false } + } + + `when`("이미 지난 Date인지 확인 했을때") { + val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + + then("이미 지난 Date 이다") { result shouldBe true } + } + } + + given("날짜가 다른, [현재시간]과 [세션시간]이 주어진 경우") { + val currentTime = dateParser.parse(rawDate = "2024-01-04 14:20:00") + val sessionTime = dateParser.parse(rawDate = "2024-01-05 14:00:00") + + `when`("앞으로 다가올 Date인지 확인 했을때") { + val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + + then("앞으로 다가올 Date이다") { result shouldBe true } + } + + `when`("이미 지난 Date인지 확인 했을때") { + val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + + then("이미 지난 Date가 아니다") { result shouldBe false } + } + } + + given("30분 50초 차의 두 시간이 주어진 경우") { + val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") + val sessionStartTime = dateParser.parse(rawDate = "2024-01-04 14:30:50") + + `when`("두 시간의 차를 분 단위로 구했을 때") { + val result = dateUtil.getElapsedTimeInMinute(target = sessionStartTime, current = currentTime) + + then("초 단위는 올림 or 반올림 되지 않고 버려진다") { result shouldBe -30 } + } + } +}) \ No newline at end of file From 4ab3b1dea1c8028f37a61bebc039eb092f3d7aa6 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 14 Jan 2024 19:13:22 +0900 Subject: [PATCH 02/26] =?UTF-8?q?Session=EC=9D=98=20date=20=EA=B0=92?= =?UTF-8?q?=EC=9D=84=20LocalDateTime=EC=9C=BC=EB=A1=9C=20=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 String으로 되어있는 값을 LocalDateTime으로 변경 --- .../java/com/yapp/attendance/di/DataModule.kt | 5 +++- .../java/com/yapp/data/model/SessionEntity.kt | 28 ++----------------- .../repository/RemoteConfigRepositoryImpl.kt | 15 +++++++++- .../java/com/yapp/domain/model/Session.kt | 17 ++++++++--- .../domain/usecases/CheckQrAuthTimeUseCase.kt | 13 +++++---- .../usecases/GetUpcomingSessionUseCase.kt | 8 ++++-- .../domain/usecases/MarkAttendanceUseCase.kt | 8 ++++-- .../com/yapp/domain/util/RenewDateUtil.kt | 11 +++++++- .../presentation/ui/admin/main/AdminMain.kt | 11 +++----- .../ui/admin/main/AdminMainViewModel.kt | 11 +++----- .../ui/member/score/MemberScore.kt | 11 +++----- .../ui/member/score/MemberScoreViewModel.kt | 5 ++-- .../ui/member/score/detail/SessionDetail.kt | 14 ++++------ .../ui/member/signup/password/Password.kt | 5 +++- .../ui/member/todaysession/TodaySession.kt | 6 ++-- .../util/attendance/AttendanceCheck.kt | 12 ++++---- 16 files changed, 94 insertions(+), 86 deletions(-) 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..27c378df 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,8 @@ 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 com.yapp.domain.util.RenewDateUtil import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -66,8 +68,9 @@ object DataModule { @Singleton fun provideRemoteConfigRepository( remoteConfigDataSource: FirebaseRemoteConfigDataSource, + dateParser: DateParser ): RemoteConfigRepository { - return RemoteConfigRepositoryImpl(remoteConfigDataSource) + return RemoteConfigRepositoryImpl(remoteConfigDataSource, dateParser) } @Provides 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..6c226350 100644 --- a/data/src/main/java/com/yapp/data/model/SessionEntity.kt +++ b/data/src/main/java/com/yapp/data/model/SessionEntity.kt @@ -1,8 +1,6 @@ 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 kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable @@ -19,26 +17,4 @@ data class SessionEntity( val description: String? = null, @PropertyName("code") val code: String? = null -) - -fun SessionEntity.toDomain(): Session { - return Session( - sessionId = sessionId!!, - title = title!!, - startTime = startTime!!, - description = description!!, - type = NeedToAttendType.valueOf(type!!), - code = code ?: "" - ) -} - -fun Session.toData(): SessionEntity { - return SessionEntity( - sessionId = sessionId, - title = title, - startTime = startTime, - description = description, - type = type.name, - code = code - ) -} +) \ No newline at end of file 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..67565570 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,15 @@ 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 dateParser: DateParser ) : RemoteConfigRepository { private var isAlreadyRequestUpdate = false @@ -38,7 +41,17 @@ class RemoteConfigRepositoryImpl @Inject constructor( firebaseRemoteConfigDataSource.getSessionList() }.fold( onSuccess = { entities: List -> - Result.success(entities.map { it.toDomain() }) + Result.success( + entities.map { entity -> + Session( + sessionId = entity.sessionId!!, + title = entity.title!!, + date = dateParser.parse(entity.date!!), + description = entity.description!!, + type = NeedToAttendType.valueOf(entity.type!!) + ) + } + ) }, onFailure = { exception -> Result.failure(exception) 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..d4870c31 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,21 @@ 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 description: String, - val code: String, -) + val date: LocalDateTime, + val description: String +) { + + val monthAndDay: String + get() = String.format(TWO_DIGIT, date.month.value) + "." + String.format(TWO_DIGIT, date.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/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index 384d958c..ba33e73b 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -1,13 +1,14 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session -import com.yapp.domain.repository.SessionRepository -import com.yapp.domain.util.DateUtil +import com.yapp.domain.repository.RemoteConfigRepository +import com.yapp.domain.util.RenewDateUtil import javax.inject.Inject class CheckQrAuthTimeUseCase @Inject constructor( - private val sessionRepository: SessionRepository, + private val remoteConfigRepository: RemoteConfigRepository, + private val dateUtil: RenewDateUtil ) { companion object { @@ -16,9 +17,9 @@ class CheckQrAuthTimeUseCase @Inject constructor( } 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 remoteConfigRepository.getSessionList().mapCatching { sessionList: List -> + val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDate(it.date) } ?: return@mapCatching false + val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.date) return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE } 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..d440f43e 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -3,16 +3,18 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.repository.SessionRepository import com.yapp.domain.util.DateUtil +import com.yapp.domain.util.RenewDateUtil import javax.inject.Inject class GetUpcomingSessionUseCase @Inject constructor( - private val sessionRepository: SessionRepository, + private val remoteConfigRepository: RemoteConfigRepository, + private val dateUtil: RenewDateUtil ) { suspend operator fun invoke(): Result { // 세션 당일 밤 12시까지 - return sessionRepository.getAllSession().mapCatching { sessionList -> - sessionList.firstOrNull { session -> DateUtil.isUpcomingSession(session.startTime) } + return remoteConfigRepository.getSessionList().mapCatching { sessionList -> + sessionList.firstOrNull { session -> dateUtil.isUpcomingDate(session.date) } } } } 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..a7de3128 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -5,11 +5,13 @@ 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 com.yapp.domain.util.RenewDateUtil import javax.inject.Inject class MarkAttendanceUseCase @Inject constructor( private val localRepository: LocalRepository, private val memberRepository: MemberRepository, + private val dateUtil: RenewDateUtil ) { suspend operator fun invoke(checkedSession: Session): Result { @@ -20,15 +22,15 @@ class MarkAttendanceUseCase @Inject constructor( currentMemberInfo!!.attendances.changeAttendanceType( sessionId = checkedSession.sessionId, - changingAttendance = checkAttendanceState(checkedSession.startTime) + changingAttendance = checkAttendanceState(dateUtil.getElapsedTimeInMinute(checkedSession.date)) ).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/util/RenewDateUtil.kt b/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt index 950574be..7cd21966 100644 --- a/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt +++ b/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt @@ -7,7 +7,7 @@ import javax.inject.Inject typealias Minute = Long -class RenewDateUtil { +class RenewDateUtil @Inject constructor() { fun getCurrentTime(): LocalDateTime { return LocalDateTime.now() @@ -57,6 +57,15 @@ class DateParser @Inject constructor() { 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") } 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..036effa4 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, ) @@ -404,7 +401,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..da3ddab6 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 @@ -7,6 +7,7 @@ import com.yapp.domain.model.collections.AttendanceList import com.yapp.domain.usecases.GetSessionListUseCase import com.yapp.domain.usecases.GetUpcomingSessionUseCase import com.yapp.domain.util.DateUtil +import com.yapp.domain.util.RenewDateUtil 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,6 +19,7 @@ import javax.inject.Inject class AdminMainViewModel @Inject constructor( private val getSessionListUseCase: GetSessionListUseCase, private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase, + private val dateUtil: RenewDateUtil ) : BaseViewModel( AdminMainUiState() ) { @@ -49,11 +51,10 @@ class AdminMainViewModel @Inject constructor( private suspend fun getSessions() { getSessionListUseCase() .onSuccess { sessions -> - val upcomingSession = - sessions.firstOrNull { DateUtil.isUpcomingSession(it.startTime) } + val upcomingSession = getUpcomingSessionUseCase().getOrThrow() upcomingSession?.let { - var lastSessionId = if (isUpcomingSessionIsStarted(it)) it.sessionId else it.sessionId - 1 + var lastSessionId = if (dateUtil.isPastDate(upcomingSession.date)) it.sessionId else it.sessionId - 1 if (lastSessionId < 0) lastSessionId = AttendanceList.DEFAULT_UPCOMING_SESSION_ID setState { copy(lastSessionId = lastSessionId) } } @@ -70,8 +71,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/member/score/MemberScore.kt b/presentation/src/main/java/com/yapp/presentation/ui/member/score/MemberScore.kt index 28b35f41..56225c9d 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 @@ -59,10 +59,9 @@ 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.domain.util.RenewDateUtil import com.yapp.presentation.R import com.yapp.presentation.util.attendance.checkSessionAttendance -import java.text.SimpleDateFormat -import java.util.Locale @Composable fun MemberScore( @@ -338,15 +337,13 @@ private fun AttendUserSession( attendanceInfo: Pair, navigateToSessionDetail: (Int) -> Unit ) { + val dateUtil = remember { RenewDateUtil() } 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 = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDate(session.date))!!, + date = session.monthAndDay, title = session.title, description = session.description, ) { 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..12e75b39 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 @@ -3,7 +3,7 @@ package com.yapp.presentation.ui.member.score import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel import com.yapp.domain.usecases.GetMemberAttendanceListUseCase -import com.yapp.domain.util.DateUtil +import com.yapp.domain.util.RenewDateUtil 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 +15,7 @@ import javax.inject.Inject @HiltViewModel class MemberScoreViewModel @Inject constructor( private val getMemberAttendanceListUseCase: GetMemberAttendanceListUseCase, + private val dateUtil: RenewDateUtil ) : BaseViewModel(initialState = MemberScoreUiState()) { init { @@ -36,7 +37,7 @@ class MemberScoreViewModel @Inject constructor( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, lastAttendanceList = attendanceList.filter { - DateUtil.isPastSession(it.first.startTime) + dateUtil.isPastDate(it.first.date) } ) } 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..64af21ee 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 @@ -13,6 +13,7 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -28,25 +29,24 @@ 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.domain.util.RenewDateUtil import com.yapp.presentation.util.attendance.checkSessionAttendance -import java.text.SimpleDateFormat -import java.util.Locale @Composable fun SessionDetail( viewModel: SessionDetailViewModel = hiltViewModel(), onClickBackButton: () -> Unit, ) { - + val dateUtil = remember { RenewDateUtil() } val uiState by viewModel.uiState.collectAsState() val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance(session, uiState.session?.second) + val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDate(session.date)) Scaffold( topBar = { YDSAppBar( modifier = Modifier.background(AttendanceTheme.colors.backgroundColors.background), - title = session?.title ?: "", + title = session.title, onClickBackButton = onClickBackButton ) }, @@ -114,10 +114,8 @@ fun SessionDetailScreen( ) } 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), + text = session.monthAndDay, style = AttendanceTypography.body1, color = AttendanceTheme.colors.grayScale.Gray600 ) 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..8d98c60e 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,9 @@ 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.DateParser import com.yapp.domain.util.DateUtil +import com.yapp.domain.util.RenewDateUtil import com.yapp.presentation.R import com.yapp.presentation.common.AttendanceBundle import com.yapp.presentation.ui.member.signup.name.OnKeyboardNextButton @@ -76,6 +78,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 +131,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?.date?.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 index 136429d4..a98c7023 100644 --- a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt +++ b/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt @@ -7,13 +7,11 @@ import com.yapp.domain.model.types.NeedToAttendType import com.yapp.domain.util.DateUtil fun checkSessionAttendance( - session: Session?, - attendance: Attendance? + session: Session, + attendance: Attendance, + isPastSession: Boolean ): YDSAttendanceType? { - if ((session == null) or (attendance == null)) { - return null - } - if (!DateUtil.isPastSession(session!!.startTime)) { + if (isPastSession.not()) { return YDSAttendanceType.TBD } if (session.type == NeedToAttendType.DONT_NEED_ATTENDANCE) { @@ -22,7 +20,7 @@ fun checkSessionAttendance( if (session.type == NeedToAttendType.DAY_OFF) { return YDSAttendanceType.NO_YAPP } - return when (attendance!!.status) { + return when (attendance.status) { Attendance.Status.ABSENT -> YDSAttendanceType.ABSENT Attendance.Status.ADMIT -> YDSAttendanceType.ATTEND Attendance.Status.LATE -> YDSAttendanceType.TARDY From 245b83aafe49e8ade031244c2e3fccbaedf02354 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 14 Jan 2024 19:13:50 +0900 Subject: [PATCH 03/26] =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20DateUtil=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/usecases/MarkAttendanceUseCase.kt | 1 - .../java/com/yapp/domain/util/DateUtil.kt | 51 ------------------- .../ui/admin/main/AdminMainViewModel.kt | 1 - .../ui/member/signup/password/Password.kt | 1 - .../util/attendance/AttendanceCheck.kt | 1 - 5 files changed, 55 deletions(-) delete mode 100644 domain/src/main/java/com/yapp/domain/util/DateUtil.kt 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 a7de3128..7eb22642 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -4,7 +4,6 @@ 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 com.yapp.domain.util.RenewDateUtil import javax.inject.Inject 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/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 da3ddab6..31880f3a 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 @@ -6,7 +6,6 @@ import com.yapp.domain.model.Session import com.yapp.domain.model.collections.AttendanceList import com.yapp.domain.usecases.GetSessionListUseCase import com.yapp.domain.usecases.GetUpcomingSessionUseCase -import com.yapp.domain.util.DateUtil import com.yapp.domain.util.RenewDateUtil import com.yapp.presentation.ui.admin.main.AdminMainContract.AdminMainUiEvent import com.yapp.presentation.ui.admin.main.AdminMainContract.AdminMainUiSideEffect 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 8d98c60e..892ac145 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 @@ -51,7 +51,6 @@ 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.DateParser -import com.yapp.domain.util.DateUtil import com.yapp.domain.util.RenewDateUtil import com.yapp.presentation.R import com.yapp.presentation.common.AttendanceBundle 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 index a98c7023..05700886 100644 --- a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt +++ b/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt @@ -4,7 +4,6 @@ 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, From 3d1d8498226ce25501621cdd5351c026ac7c19a8 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 14 Jan 2024 19:15:11 +0900 Subject: [PATCH 04/26] =?UTF-8?q?RenewDateUtil=20=EC=9D=84=20DateUtil?= =?UTF-8?q?=EB=A1=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/yapp/attendance/di/DataModule.kt | 1 - .../java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt | 4 ++-- .../com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt | 2 +- .../java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt | 4 ++-- .../com/yapp/domain/util/{RenewDateUtil.kt => DateUtil.kt} | 2 +- domain/src/test/java/DateUtilTest.kt | 4 ++-- .../yapp/presentation/ui/admin/main/AdminMainViewModel.kt | 5 ++--- .../com/yapp/presentation/ui/member/score/MemberScore.kt | 4 ++-- .../presentation/ui/member/score/MemberScoreViewModel.kt | 4 ++-- .../presentation/ui/member/score/detail/SessionDetail.kt | 4 ++-- .../yapp/presentation/ui/member/signup/password/Password.kt | 1 - 11 files changed, 16 insertions(+), 19 deletions(-) rename domain/src/main/java/com/yapp/domain/util/{RenewDateUtil.kt => DateUtil.kt} (97%) 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 27c378df..4080eb88 100644 --- a/app/src/main/java/com/yapp/attendance/di/DataModule.kt +++ b/app/src/main/java/com/yapp/attendance/di/DataModule.kt @@ -14,7 +14,6 @@ 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 com.yapp.domain.util.RenewDateUtil import dagger.Module import dagger.Provides import dagger.hilt.InstallIn diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index ba33e73b..2e425a41 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -2,13 +2,13 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.repository.RemoteConfigRepository -import com.yapp.domain.util.RenewDateUtil +import com.yapp.domain.util.DateUtil import javax.inject.Inject class CheckQrAuthTimeUseCase @Inject constructor( private val remoteConfigRepository: RemoteConfigRepository, - private val dateUtil: RenewDateUtil + private val dateUtil: DateUtil ) { companion object { 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 d440f43e..03faee88 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -8,7 +8,7 @@ import javax.inject.Inject class GetUpcomingSessionUseCase @Inject constructor( private val remoteConfigRepository: RemoteConfigRepository, - private val dateUtil: RenewDateUtil + private val dateUtil: DateUtil ) { suspend operator fun invoke(): Result { 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 7eb22642..66635b40 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -4,13 +4,13 @@ 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.RenewDateUtil +import com.yapp.domain.util.DateUtil import javax.inject.Inject class MarkAttendanceUseCase @Inject constructor( private val localRepository: LocalRepository, private val memberRepository: MemberRepository, - private val dateUtil: RenewDateUtil + private val dateUtil: DateUtil ) { suspend operator fun invoke(checkedSession: Session): Result { diff --git a/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt similarity index 97% rename from domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt rename to domain/src/main/java/com/yapp/domain/util/DateUtil.kt index 7cd21966..e9c2d6d9 100644 --- a/domain/src/main/java/com/yapp/domain/util/RenewDateUtil.kt +++ b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt @@ -7,7 +7,7 @@ import javax.inject.Inject typealias Minute = Long -class RenewDateUtil @Inject constructor() { +class DateUtil @Inject constructor() { fun getCurrentTime(): LocalDateTime { return LocalDateTime.now() diff --git a/domain/src/test/java/DateUtilTest.kt b/domain/src/test/java/DateUtilTest.kt index e5108d11..d8c3d268 100644 --- a/domain/src/test/java/DateUtilTest.kt +++ b/domain/src/test/java/DateUtilTest.kt @@ -1,11 +1,11 @@ import com.yapp.domain.util.DateParser -import com.yapp.domain.util.RenewDateUtil +import com.yapp.domain.util.DateUtil import io.kotest.core.spec.style.BehaviorSpec import io.kotest.matchers.shouldBe class DateUtilTest : BehaviorSpec({ val dateParser = DateParser() - val dateUtil = RenewDateUtil() + val dateUtil = DateUtil() given("[세션시간]과 그로 부터 [30분 전 시간]이 주어진 경우") { val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") 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 31880f3a..786e0c3c 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.GetSessionListUseCase import com.yapp.domain.usecases.GetUpcomingSessionUseCase -import com.yapp.domain.util.RenewDateUtil +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,7 +17,7 @@ import javax.inject.Inject class AdminMainViewModel @Inject constructor( private val getSessionListUseCase: GetSessionListUseCase, private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase, - private val dateUtil: RenewDateUtil + private val dateUtil: DateUtil ) : BaseViewModel( AdminMainUiState() ) { 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 56225c9d..02ba5e17 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 @@ -59,7 +59,7 @@ 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.domain.util.RenewDateUtil +import com.yapp.domain.util.DateUtil import com.yapp.presentation.R import com.yapp.presentation.util.attendance.checkSessionAttendance @@ -337,7 +337,7 @@ private fun AttendUserSession( attendanceInfo: Pair, navigateToSessionDetail: (Int) -> Unit ) { - val dateUtil = remember { RenewDateUtil() } + val dateUtil = remember { DateUtil() } val session = attendanceInfo.first val attendance = attendanceInfo.second 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 12e75b39..4efc118c 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 @@ -3,7 +3,7 @@ package com.yapp.presentation.ui.member.score import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel import com.yapp.domain.usecases.GetMemberAttendanceListUseCase -import com.yapp.domain.util.RenewDateUtil +import com.yapp.domain.util.DateUtil 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,7 +15,7 @@ import javax.inject.Inject @HiltViewModel class MemberScoreViewModel @Inject constructor( private val getMemberAttendanceListUseCase: GetMemberAttendanceListUseCase, - private val dateUtil: RenewDateUtil + private val dateUtil: DateUtil ) : BaseViewModel(initialState = MemberScoreUiState()) { init { 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 64af21ee..b0a7c57a 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 @@ -29,7 +29,7 @@ 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.domain.util.RenewDateUtil +import com.yapp.domain.util.DateUtil import com.yapp.presentation.util.attendance.checkSessionAttendance @Composable @@ -37,7 +37,7 @@ fun SessionDetail( viewModel: SessionDetailViewModel = hiltViewModel(), onClickBackButton: () -> Unit, ) { - val dateUtil = remember { RenewDateUtil() } + val dateUtil = remember { DateUtil() } val uiState by viewModel.uiState.collectAsState() val session: Session? = uiState.session?.first val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDate(session.date)) 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 892ac145..b44fd3c3 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 @@ -51,7 +51,6 @@ 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.DateParser -import com.yapp.domain.util.RenewDateUtil import com.yapp.presentation.R import com.yapp.presentation.common.AttendanceBundle import com.yapp.presentation.ui.member.signup.name.OnKeyboardNextButton From f513e62df859471905bb525e25c542828b4938cf Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 14 Jan 2024 19:17:21 +0900 Subject: [PATCH 05/26] =?UTF-8?q?DateParser=EB=A5=BC=20=EB=8B=A4=EB=A5=B8?= =?UTF-8?q?=20=ED=8C=8C=EC=9D=BC=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yapp/domain/util/DateParser.kt | 37 +++++++++++++++++++ .../java/com/yapp/domain/util/DateUtil.kt | 35 +----------------- 2 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 domain/src/main/java/com/yapp/domain/util/DateParser.kt 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 index e9c2d6d9..f1d0ce46 100644 --- a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt +++ b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt @@ -2,7 +2,6 @@ package com.yapp.domain.util import java.time.Duration import java.time.LocalDateTime -import java.time.format.DateTimeFormatter import javax.inject.Inject typealias Minute = Long @@ -37,36 +36,4 @@ class DateUtil @Inject constructor() { ): Boolean { return getElapsedTimeInMinute(target, current) >= 0 } -} - -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 From 5e4644001a15c316d04e8ba6acda0525a1a0f885 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 20 Jan 2024 17:06:55 +0900 Subject: [PATCH 06/26] =?UTF-8?q?develop=20=EB=B8=8C=EB=9E=9C=EC=B9=98=20r?= =?UTF-8?q?ebase=ED=9B=84=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yapp/attendance/di/DataModule.kt | 5 ++-- .../java/com/yapp/data/model/SessionEntity.kt | 29 +++++++++++++++++-- .../repository/RemoteConfigRepositoryImpl.kt | 5 ++-- .../data/repository/SessionRepositoryImpl.kt | 12 ++++---- .../java/com/yapp/domain/model/Session.kt | 7 +++-- .../domain/usecases/CheckQrAuthTimeUseCase.kt | 4 +-- .../usecases/GetUpcomingSessionUseCase.kt | 7 ++--- .../domain/usecases/MarkAttendanceUseCase.kt | 2 +- .../yapp/domain/usecases/SetSessionUseCase.kt | 6 ++-- .../createsession/CreateSessionViewModel.kt | 2 +- .../ui/admin/main/AdminMainViewModel.kt | 2 +- .../ui/member/score/MemberScore.kt | 2 +- .../ui/member/score/MemberScoreViewModel.kt | 2 +- .../ui/member/score/detail/SessionDetail.kt | 2 +- .../ui/member/signup/password/Password.kt | 2 +- 15 files changed, 59 insertions(+), 30 deletions(-) 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 4080eb88..c3950e48 100644 --- a/app/src/main/java/com/yapp/attendance/di/DataModule.kt +++ b/app/src/main/java/com/yapp/attendance/di/DataModule.kt @@ -58,9 +58,10 @@ object DataModule { @Provides @Singleton fun provideSessionRepository( - sessionDataSource: SessionRemoteDataSource + sessionDataSource: SessionRemoteDataSource, + dateParser: DateParser ): SessionRepository { - return SessionRepositoryImpl(sessionDataSource) + return SessionRepositoryImpl(sessionDataSource, dateParser) } @Provides 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 6c226350..463fb850 100644 --- a/data/src/main/java/com/yapp/data/model/SessionEntity.kt +++ b/data/src/main/java/com/yapp/data/model/SessionEntity.kt @@ -1,6 +1,9 @@ package com.yapp.data.model -import kotlinx.serialization.SerialName +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 @@ -17,4 +20,26 @@ data class SessionEntity( val description: String? = null, @PropertyName("code") val code: String? = null -) \ No newline at end of file +) + +fun SessionEntity.toDomain(dateParser: DateParser): Session { + return Session( + sessionId = sessionId!!, + title = title!!, + type = NeedToAttendType.valueOf(type!!), + startTime = dateParser.parse(rawDate = startTime!!), + description = description!!, + code = code!! + ) +} + +fun Session.toDate(dateParser: DateParser): SessionEntity { + return SessionEntity( + sessionId = sessionId, + title = title, + 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/repository/RemoteConfigRepositoryImpl.kt b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt index 67565570..2e456836 100644 --- a/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt @@ -46,9 +46,10 @@ class RemoteConfigRepositoryImpl @Inject constructor( Session( sessionId = entity.sessionId!!, title = entity.title!!, - date = dateParser.parse(entity.date!!), + startTime = dateParser.parse(entity.startTime!!), description = entity.description!!, - type = NeedToAttendType.valueOf(entity.type!!) + type = NeedToAttendType.valueOf(entity.type!!), + code = entity.code!! ) } ) 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..27502eed 100644 --- a/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt @@ -1,18 +1,20 @@ package com.yapp.data.repository import com.yapp.data.datasource.SessionRemoteDataSource -import com.yapp.data.model.toData +import com.yapp.data.model.toDate 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.toDate(dateParser)) }.fold( onSuccess = { Result.success(Unit) @@ -25,7 +27,7 @@ class SessionRepositoryImpl @Inject constructor( override suspend fun getSession(id: Long): 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/src/main/java/com/yapp/domain/model/Session.kt b/domain/src/main/java/com/yapp/domain/model/Session.kt index d4870c31..9b8c6fa2 100644 --- a/domain/src/main/java/com/yapp/domain/model/Session.kt +++ b/domain/src/main/java/com/yapp/domain/model/Session.kt @@ -7,12 +7,13 @@ data class Session( val sessionId: Int, val title: String, val type: NeedToAttendType, - val date: LocalDateTime, - val description: String + val startTime: LocalDateTime, + val description: String, + val code: String ) { val monthAndDay: String - get() = String.format(TWO_DIGIT, date.month.value) + "." + String.format(TWO_DIGIT, date.dayOfMonth) + get() = String.format(TWO_DIGIT, startTime.month.value) + "." + String.format(TWO_DIGIT, startTime.dayOfMonth) companion object { private const val TWO_DIGIT = "%02d" diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index 2e425a41..4687af1b 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -18,8 +18,8 @@ class CheckQrAuthTimeUseCase @Inject constructor( suspend operator fun invoke(): Result { return remoteConfigRepository.getSessionList().mapCatching { sessionList: List -> - val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDate(it.date) } ?: return@mapCatching false - val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.date) + val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDate(it.startTime) } ?: return@mapCatching false + val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.startTime) return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE } 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 03faee88..5038ff87 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -3,18 +3,17 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.repository.SessionRepository import com.yapp.domain.util.DateUtil -import com.yapp.domain.util.RenewDateUtil import javax.inject.Inject class GetUpcomingSessionUseCase @Inject constructor( - private val remoteConfigRepository: RemoteConfigRepository, + private val sessionRepository: SessionRepository, private val dateUtil: DateUtil ) { suspend operator fun invoke(): Result { // 세션 당일 밤 12시까지 - return remoteConfigRepository.getSessionList().mapCatching { sessionList -> - sessionList.firstOrNull { session -> dateUtil.isUpcomingDate(session.date) } + return sessionRepository.getAllSession().mapCatching { sessionList -> + sessionList.firstOrNull { session -> dateUtil.isUpcomingDate(session.startTime) } } } } 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 66635b40..58ad0151 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -21,7 +21,7 @@ class MarkAttendanceUseCase @Inject constructor( currentMemberInfo!!.attendances.changeAttendanceType( sessionId = checkedSession.sessionId, - changingAttendance = checkAttendanceState(dateUtil.getElapsedTimeInMinute(checkedSession.date)) + changingAttendance = checkAttendanceState(dateUtil.getElapsedTimeInMinute(checkedSession.startTime)) ).also { updatedAttendanceList -> memberRepository.setMember(member = currentMemberInfo.copy(attendances = updatedAttendanceList)) } 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/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/AdminMainViewModel.kt b/presentation/src/main/java/com/yapp/presentation/ui/admin/main/AdminMainViewModel.kt index 786e0c3c..bf488b83 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 @@ -52,7 +52,7 @@ class AdminMainViewModel @Inject constructor( val upcomingSession = getUpcomingSessionUseCase().getOrThrow() upcomingSession?.let { - var lastSessionId = if (dateUtil.isPastDate(upcomingSession.date)) it.sessionId else it.sessionId - 1 + var lastSessionId = if (dateUtil.isPastDate(upcomingSession.startTime)) it.sessionId else it.sessionId - 1 if (lastSessionId < 0) lastSessionId = AttendanceList.DEFAULT_UPCOMING_SESSION_ID setState { copy(lastSessionId = lastSessionId) } } 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 02ba5e17..e89c9243 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 @@ -342,7 +342,7 @@ private fun AttendUserSession( val attendance = attendanceInfo.second YDSAttendanceList( - attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDate(session.date))!!, + attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDate(session.startTime))!!, date = session.monthAndDay, title = session.title, description = session.description, 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 4efc118c..76063f62 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 @@ -37,7 +37,7 @@ class MemberScoreViewModel @Inject constructor( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, lastAttendanceList = attendanceList.filter { - dateUtil.isPastDate(it.first.date) + dateUtil.isPastDate(it.first.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 b0a7c57a..caa13c05 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 @@ -40,7 +40,7 @@ fun SessionDetail( val dateUtil = remember { DateUtil() } val uiState by viewModel.uiState.collectAsState() val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDate(session.date)) + val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDate(session.startTime)) Scaffold( topBar = { 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 b44fd3c3..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 @@ -129,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, AttendanceBundle.upComingSession?.date?.let { dateParser.format(it, "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) From 7f3b2d989087e5425b577d3d8fce14aa109d38f1 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 20 Jan 2024 17:12:28 +0900 Subject: [PATCH 07/26] =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20RemoteConfig?= =?UTF-8?q?=EC=97=90=EC=84=9C=20SessionList=EB=A5=BC=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yapp/attendance/di/DataModule.kt | 5 ++-- .../FirebaseRemoteConfigDataSource.kt | 1 - .../FirebaseRemoteConfigDataSourceImpl.kt | 15 ----------- .../repository/RemoteConfigRepositoryImpl.kt | 27 +------------------ .../yapp/domain/firebase/RemoteConfigData.kt | 7 ----- .../repository/RemoteConfigRepository.kt | 1 - .../domain/usecases/CheckQrAuthTimeUseCase.kt | 5 ++-- 7 files changed, 6 insertions(+), 55 deletions(-) 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 c3950e48..a9ead0ce 100644 --- a/app/src/main/java/com/yapp/attendance/di/DataModule.kt +++ b/app/src/main/java/com/yapp/attendance/di/DataModule.kt @@ -67,10 +67,9 @@ object DataModule { @Provides @Singleton fun provideRemoteConfigRepository( - remoteConfigDataSource: FirebaseRemoteConfigDataSource, - dateParser: DateParser + remoteConfigDataSource: FirebaseRemoteConfigDataSource ): RemoteConfigRepository { - return RemoteConfigRepositoryImpl(remoteConfigDataSource, dateParser) + return RemoteConfigRepositoryImpl(remoteConfigDataSource) } @Provides 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/repository/RemoteConfigRepositoryImpl.kt b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt index 2e456836..0a708357 100644 --- a/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/RemoteConfigRepositoryImpl.kt @@ -17,8 +17,7 @@ import javax.inject.Inject class RemoteConfigRepositoryImpl @Inject constructor( - private val firebaseRemoteConfigDataSource: FirebaseRemoteConfigDataSource, - private val dateParser: DateParser + private val firebaseRemoteConfigDataSource: FirebaseRemoteConfigDataSource ) : RemoteConfigRepository { private var isAlreadyRequestUpdate = false @@ -36,30 +35,6 @@ class RemoteConfigRepositoryImpl @Inject constructor( ) } - override suspend fun getSessionList(): Result> { - return runCatching { - firebaseRemoteConfigDataSource.getSessionList() - }.fold( - onSuccess = { entities: List -> - Result.success( - entities.map { entity -> - Session( - sessionId = entity.sessionId!!, - title = entity.title!!, - startTime = dateParser.parse(entity.startTime!!), - description = entity.description!!, - type = NeedToAttendType.valueOf(entity.type!!), - code = entity.code!! - ) - } - ) - }, - onFailure = { exception -> - Result.failure(exception) - } - ) - } - override suspend fun getConfig(): Result { return runCatching { firebaseRemoteConfigDataSource.getConfig() 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/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/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index 4687af1b..cfd82633 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -2,12 +2,13 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session import com.yapp.domain.repository.RemoteConfigRepository +import com.yapp.domain.repository.SessionRepository import com.yapp.domain.util.DateUtil import javax.inject.Inject class CheckQrAuthTimeUseCase @Inject constructor( - private val remoteConfigRepository: RemoteConfigRepository, + private val sessionRepository: SessionRepository, private val dateUtil: DateUtil ) { @@ -17,7 +18,7 @@ class CheckQrAuthTimeUseCase @Inject constructor( } suspend operator fun invoke(): Result { - return remoteConfigRepository.getSessionList().mapCatching { sessionList: List -> + return sessionRepository.getAllSession().mapCatching { sessionList: List -> val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDate(it.startTime) } ?: return@mapCatching false val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.startTime) From c4ed6912dcd629a918d764281106b41ce6c444de Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 20 Jan 2024 18:04:28 +0900 Subject: [PATCH 08/26] =?UTF-8?q?=EC=B6=9C=EC=84=9D=EC=8B=9C=20Session=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=EC=97=90=20=EB=8B=B4=EA=B8=B4=20Code?= =?UTF-8?q?=EB=A1=9C=20=EC=B6=9C=EC=84=9D=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RemoteConfig에 존재하는 공통의 출석코드가 아닌 각 세션에 존재하는 Code를 Input과 비교하여 출석하도록 수정 --- .../yapp/data/datasource/SessionRemoteDataSource.kt | 2 +- .../data/datasource/SessionRemoteDataSourceImpl.kt | 2 +- .../yapp/data/repository/SessionRepositoryImpl.kt | 2 +- .../com/yapp/domain/repository/SessionRepository.kt | 2 +- .../domain/usecases/CheckSessionPasswordUseCase.kt | 12 +++++++----- .../ui/member/signup/password/PassWordViewModel.kt | 9 +++++++-- 6 files changed, 18 insertions(+), 11 deletions(-) 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/repository/SessionRepositoryImpl.kt b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt index 27502eed..668b0456 100644 --- a/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt @@ -25,7 +25,7 @@ class SessionRepositoryImpl @Inject constructor( ) } - override suspend fun getSession(id: Long): Result { + override suspend fun getSession(id: Int): Result { return runCatching { sessionRemoteDataSource.getSession(id)?.toDomain(dateParser) }.fold( 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/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/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( } } } - + } From fd662a7d75d893bf48831cc453ec33eb2e151a35 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 27 Jan 2024 16:47:06 +0900 Subject: [PATCH 09/26] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20Nu?= =?UTF-8?q?llable=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yapp/presentation/util/attendance/AttendanceCheck.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 05700886..eab423f2 100644 --- a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt +++ b/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt @@ -9,7 +9,7 @@ fun checkSessionAttendance( session: Session, attendance: Attendance, isPastSession: Boolean -): YDSAttendanceType? { +): YDSAttendanceType { if (isPastSession.not()) { return YDSAttendanceType.TBD } From b8052d176b837e04f0eef2da41d2ae237b8aa3a9 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 27 Jan 2024 16:57:41 +0900 Subject: [PATCH 10/26] =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85=20?= =?UTF-8?q?=EC=98=A4=ED=83=88=EC=9E=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/src/main/java/com/yapp/data/model/SessionEntity.kt | 2 +- .../java/com/yapp/data/repository/SessionRepositoryImpl.kt | 4 ++-- .../yapp/presentation/ui/member/score/MemberScoreViewModel.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) 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 463fb850..eb888649 100644 --- a/data/src/main/java/com/yapp/data/model/SessionEntity.kt +++ b/data/src/main/java/com/yapp/data/model/SessionEntity.kt @@ -33,7 +33,7 @@ fun SessionEntity.toDomain(dateParser: DateParser): Session { ) } -fun Session.toDate(dateParser: DateParser): SessionEntity { +fun Session.toData(dateParser: DateParser): SessionEntity { return SessionEntity( sessionId = sessionId, title = title, 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 668b0456..81590ec8 100644 --- a/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt +++ b/data/src/main/java/com/yapp/data/repository/SessionRepositoryImpl.kt @@ -1,7 +1,7 @@ package com.yapp.data.repository import com.yapp.data.datasource.SessionRemoteDataSource -import com.yapp.data.model.toDate +import com.yapp.data.model.toData import com.yapp.data.model.toDomain import com.yapp.domain.model.Session import com.yapp.domain.repository.SessionRepository @@ -14,7 +14,7 @@ class SessionRepositoryImpl @Inject constructor( ) : SessionRepository { override suspend fun setSession(session: Session): Result { return runCatching { - sessionRemoteDataSource.setSession(session.toDate(dateParser)) + sessionRemoteDataSource.setSession(session.toData(dateParser)) }.fold( onSuccess = { Result.success(Unit) 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 76063f62..21aa7053 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 @@ -36,8 +36,8 @@ class MemberScoreViewModel @Inject constructor( copy( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, - lastAttendanceList = attendanceList.filter { - dateUtil.isPastDate(it.first.startTime) + lastAttendanceList = attendanceList.filter { (session, _) -> + dateUtil.isPastDate(session.startTime) } ) } From 40911c10d34ffed0f13606e5ee40dd99cb536f63 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 27 Jan 2024 17:07:35 +0900 Subject: [PATCH 11/26] =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=EB=AA=85?= =?UTF-8?q?=EC=9D=84=20=EB=8D=94=20=EC=A7=81=EA=B4=80=EC=A0=81=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=ED=95=B4=ED=95=A0=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yapp/domain/usecases/CheckQrAuthTimeUseCase.kt | 3 +-- .../domain/usecases/GetUpcomingSessionUseCase.kt | 2 +- .../src/main/java/com/yapp/domain/util/DateUtil.kt | 6 +++--- domain/src/test/java/DateUtilTest.kt | 12 ++++++------ .../presentation/ui/admin/main/AdminMainViewModel.kt | 2 +- .../yapp/presentation/ui/member/score/MemberScore.kt | 2 +- .../ui/member/score/MemberScoreViewModel.kt | 2 +- .../ui/member/score/detail/SessionDetail.kt | 2 +- 8 files changed, 15 insertions(+), 16 deletions(-) diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index cfd82633..a0f6e85b 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -1,7 +1,6 @@ package com.yapp.domain.usecases import com.yapp.domain.model.Session -import com.yapp.domain.repository.RemoteConfigRepository import com.yapp.domain.repository.SessionRepository import com.yapp.domain.util.DateUtil import javax.inject.Inject @@ -19,7 +18,7 @@ class CheckQrAuthTimeUseCase @Inject constructor( suspend operator fun invoke(): Result { return sessionRepository.getAllSession().mapCatching { sessionList: List -> - val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDate(it.startTime) } ?: return@mapCatching false + val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDateFromCurrentTime(it.startTime) } ?: return@mapCatching false val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.startTime) return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE 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 5038ff87..3d2514f7 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -13,7 +13,7 @@ class GetUpcomingSessionUseCase @Inject constructor( suspend operator fun invoke(): Result { // 세션 당일 밤 12시까지 return sessionRepository.getAllSession().mapCatching { sessionList -> - sessionList.firstOrNull { session -> dateUtil.isUpcomingDate(session.startTime) } + sessionList.firstOrNull { session -> dateUtil.isUpcomingDateFromCurrentTime(session.startTime) } } } } diff --git a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt index f1d0ce46..cadb09f1 100644 --- a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt +++ b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt @@ -13,7 +13,7 @@ class DateUtil @Inject constructor() { } /** - * [startTime] 에서 [target] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 + * [current] 에서 [target] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 * 양수 (+) 일 경우 [target] 으로부터 시간이 이미 흐른상태, 음수 (-)인 경우 시간이 아직 [target] 까지 시간이 흐르지 않은상태 */ fun getElapsedTimeInMinute( @@ -23,14 +23,14 @@ class DateUtil @Inject constructor() { return Duration.between(target, current).toMinutes() } - fun isUpcomingDate( + fun isUpcomingDateFromCurrentTime( target: LocalDateTime, current: LocalDateTime = getCurrentTime() ): Boolean { return current <= target } - fun isPastDate( + fun isPastDateFromCurrentTime( target: LocalDateTime, current: LocalDateTime = getCurrentTime() ): Boolean { diff --git a/domain/src/test/java/DateUtilTest.kt b/domain/src/test/java/DateUtilTest.kt index d8c3d268..d5df61d5 100644 --- a/domain/src/test/java/DateUtilTest.kt +++ b/domain/src/test/java/DateUtilTest.kt @@ -18,13 +18,13 @@ class DateUtilTest : BehaviorSpec({ } `when`("곧 앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) then("앞으로 다가올 Date 이다") { result shouldBe true } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) then("이미 지난 Date가 아니다") { result shouldBe false } } @@ -41,13 +41,13 @@ class DateUtilTest : BehaviorSpec({ } `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) then("앞으로 다가올 세션이 아니다") { result shouldBe false } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) then("이미 지난 Date 이다") { result shouldBe true } } @@ -58,13 +58,13 @@ class DateUtilTest : BehaviorSpec({ val sessionTime = dateParser.parse(rawDate = "2024-01-05 14:00:00") `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDate(target = sessionTime, current = currentTime) + val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) then("앞으로 다가올 Date이다") { result shouldBe true } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDate(target = sessionTime, current = currentTime) + val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) then("이미 지난 Date가 아니다") { result shouldBe false } } 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 bf488b83..2b1520cc 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 @@ -52,7 +52,7 @@ class AdminMainViewModel @Inject constructor( val upcomingSession = getUpcomingSessionUseCase().getOrThrow() upcomingSession?.let { - var lastSessionId = if (dateUtil.isPastDate(upcomingSession.startTime)) it.sessionId else it.sessionId - 1 + var lastSessionId = if (dateUtil.isPastDateFromCurrentTime(upcomingSession.startTime)) it.sessionId else it.sessionId - 1 if (lastSessionId < 0) lastSessionId = AttendanceList.DEFAULT_UPCOMING_SESSION_ID setState { copy(lastSessionId = lastSessionId) } } 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 e89c9243..8bf5f0e8 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 @@ -342,7 +342,7 @@ private fun AttendUserSession( val attendance = attendanceInfo.second YDSAttendanceList( - attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDate(session.startTime))!!, + attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime))!!, date = session.monthAndDay, title = session.title, description = session.description, 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 21aa7053..b2a7f009 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 @@ -37,7 +37,7 @@ class MemberScoreViewModel @Inject constructor( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, lastAttendanceList = attendanceList.filter { (session, _) -> - dateUtil.isPastDate(session.startTime) + dateUtil.isPastDateFromCurrentTime(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 caa13c05..1c9c20fb 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 @@ -40,7 +40,7 @@ fun SessionDetail( val dateUtil = remember { DateUtil() } val uiState by viewModel.uiState.collectAsState() val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDate(session.startTime)) + val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime)) Scaffold( topBar = { From 3fc90dfe0a4b4c9d5cd314ffc1beea0357e93619 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 27 Jan 2024 17:11:04 +0900 Subject: [PATCH 12/26] =?UTF-8?q?WarningSign=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 불필요한 코드들을 제거합니다 --- .../java/com/yapp/presentation/ui/admin/main/AdminMain.kt | 3 --- .../yapp/presentation/ui/admin/management/Management.kt | 4 ++-- .../ui/admin/management/components/AnimatedCounterText.kt | 7 +++---- .../foldableHeaderItem/FoldableItemHeaderLayout.kt | 4 ++-- .../admin/management/components/tablayout/YDSTabLayout.kt | 2 +- .../components/tablayout/YDSTabLayoutItemStateList.kt | 2 +- .../presentation/ui/admin/totalscore/AdminTotalScore.kt | 4 ++-- .../com/yapp/presentation/ui/member/score/MemberScore.kt | 2 +- 8 files changed, 12 insertions(+), 16 deletions(-) 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 036effa4..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 @@ -380,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() 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 8bf5f0e8..dad4b5e2 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 @@ -342,7 +342,7 @@ private fun AttendUserSession( val attendance = attendanceInfo.second YDSAttendanceList( - attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime))!!, + attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime)), date = session.monthAndDay, title = session.title, description = session.description, From c61af0657718d2a2b674930372a2264c92822ca5 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 27 Jan 2024 19:18:53 +0900 Subject: [PATCH 13/26] =?UTF-8?q?DateUtil=EC=9D=98=20=ED=95=A8=EC=88=98?= =?UTF-8?q?=EB=AA=85=EA=B3=BC=20=EB=8F=99=EC=9E=91=EB=B0=A9=EC=8B=9D?= =?UTF-8?q?=EC=9D=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 로직에서의 더 나은 가독성을 위해 함수명을 도메인(비즈니스 로직에)에 연관되지 않은 이름으로 수정합니다 - infix 함수로 가독성을 향상시킵니다 --- .../domain/usecases/CheckQrAuthTimeUseCase.kt | 6 ++-- .../usecases/GetUpcomingSessionUseCase.kt | 5 +++- .../domain/usecases/MarkAttendanceUseCase.kt | 4 ++- .../java/com/yapp/domain/util/DateUtil.kt | 30 +++++++------------ domain/src/test/java/DateUtilTest.kt | 20 ++++++------- .../ui/admin/main/AdminMainViewModel.kt | 2 +- .../ui/member/score/MemberScore.kt | 6 +++- .../ui/member/score/MemberScoreViewModel.kt | 2 +- .../ui/member/score/detail/SessionDetail.kt | 6 +++- 9 files changed, 43 insertions(+), 38 deletions(-) diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index a0f6e85b..3172cb60 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -18,8 +18,10 @@ class CheckQrAuthTimeUseCase @Inject constructor( suspend operator fun invoke(): Result { return sessionRepository.getAllSession().mapCatching { sessionList: List -> - val upComingSession = sessionList.firstOrNull { dateUtil.isUpcomingDateFromCurrentTime(it.startTime) } ?: return@mapCatching false - val elapsedTime = dateUtil.getElapsedTimeInMinute(target = upComingSession.startTime) + val upComingSession = sessionList.firstOrNull { session -> + with(dateUtil) { currentTime isBeforeFrom session.startTime } + } ?: return@mapCatching false + val elapsedTime = with(dateUtil) { currentTime elapsedFrom upComingSession.startTime } return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE } 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 3d2514f7..1dc371ad 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -13,7 +13,10 @@ class GetUpcomingSessionUseCase @Inject constructor( suspend operator fun invoke(): Result { // 세션 당일 밤 12시까지 return sessionRepository.getAllSession().mapCatching { sessionList -> - sessionList.firstOrNull { session -> dateUtil.isUpcomingDateFromCurrentTime(session.startTime) } + sessionList.firstOrNull { session -> + with(dateUtil) { currentTime isBeforeFrom session.startTime } + } } + } } 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 58ad0151..6f1f1087 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/MarkAttendanceUseCase.kt @@ -21,7 +21,9 @@ class MarkAttendanceUseCase @Inject constructor( currentMemberInfo!!.attendances.changeAttendanceType( sessionId = checkedSession.sessionId, - changingAttendance = checkAttendanceState(dateUtil.getElapsedTimeInMinute(checkedSession.startTime)) + changingAttendance = checkAttendanceState( + elapsedTime = with(dateUtil) { currentTime elapsedFrom checkedSession.startTime} + ) ).also { updatedAttendanceList -> memberRepository.setMember(member = currentMemberInfo.copy(attendances = updatedAttendanceList)) } diff --git a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt index cadb09f1..1afb1bda 100644 --- a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt +++ b/domain/src/main/java/com/yapp/domain/util/DateUtil.kt @@ -8,32 +8,22 @@ typealias Minute = Long class DateUtil @Inject constructor() { - fun getCurrentTime(): LocalDateTime { - return LocalDateTime.now() - } + val currentTime: LocalDateTime + get() = LocalDateTime.now() /** - * [current] 에서 [target] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 - * 양수 (+) 일 경우 [target] 으로부터 시간이 이미 흐른상태, 음수 (-)인 경우 시간이 아직 [target] 까지 시간이 흐르지 않은상태 + * [from] 에서 [this] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 + * 양수 (+) 일 경우 [from] 으로부터 시간이 이미 흐른상태, 음수 (-)인 경우 시간이 아직 [from] 까지 시간이 흐르지 않은상태 */ - fun getElapsedTimeInMinute( - target: LocalDateTime, - current: LocalDateTime = getCurrentTime() - ): Minute { - return Duration.between(target, current).toMinutes() + infix fun LocalDateTime.elapsedFrom(from: LocalDateTime): Minute { + return Duration.between(from, this).toMinutes() } - fun isUpcomingDateFromCurrentTime( - target: LocalDateTime, - current: LocalDateTime = getCurrentTime() - ): Boolean { - return current <= target + infix fun LocalDateTime.isBeforeFrom(from: LocalDateTime): Boolean { + return this.isBefore(from) } - fun isPastDateFromCurrentTime( - target: LocalDateTime, - current: LocalDateTime = getCurrentTime() - ): Boolean { - return getElapsedTimeInMinute(target, current) >= 0 + infix fun LocalDateTime.isAfterFrom(from: LocalDateTime): Boolean { + return this.isAfter(from) } } \ No newline at end of file diff --git a/domain/src/test/java/DateUtilTest.kt b/domain/src/test/java/DateUtilTest.kt index d5df61d5..49d25b9b 100644 --- a/domain/src/test/java/DateUtilTest.kt +++ b/domain/src/test/java/DateUtilTest.kt @@ -12,19 +12,19 @@ class DateUtilTest : BehaviorSpec({ val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:30:00") `when`("두 시간의 차를 분 단위로 구하면") { - val result = dateUtil.getElapsedTimeInMinute(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime elapsedFrom sessionTime } then("차이는 -30분 이다") { result shouldBe -30 } } `when`("곧 앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } then("앞으로 다가올 Date 이다") { result shouldBe true } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isAfterFrom sessionTime } then("이미 지난 Date가 아니다") { result shouldBe false } } @@ -35,19 +35,19 @@ class DateUtilTest : BehaviorSpec({ val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") `when`("두 시간의 차를 분 단위로 구했을 때") { - val result = dateUtil.getElapsedTimeInMinute(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime elapsedFrom sessionTime } then("차이는 20분 이다") { result shouldBe 20 } } `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } then("앞으로 다가올 세션이 아니다") { result shouldBe false } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isAfterFrom sessionTime } then("이미 지난 Date 이다") { result shouldBe true } } @@ -58,13 +58,13 @@ class DateUtilTest : BehaviorSpec({ val sessionTime = dateParser.parse(rawDate = "2024-01-05 14:00:00") `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = dateUtil.isUpcomingDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } then("앞으로 다가올 Date이다") { result shouldBe true } } `when`("이미 지난 Date인지 확인 했을때") { - val result = dateUtil.isPastDateFromCurrentTime(target = sessionTime, current = currentTime) + val result = with(dateUtil) { currentTime isAfterFrom sessionTime } then("이미 지난 Date가 아니다") { result shouldBe false } } @@ -72,10 +72,10 @@ class DateUtilTest : BehaviorSpec({ given("30분 50초 차의 두 시간이 주어진 경우") { val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") - val sessionStartTime = dateParser.parse(rawDate = "2024-01-04 14:30:50") + val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:30:50") `when`("두 시간의 차를 분 단위로 구했을 때") { - val result = dateUtil.getElapsedTimeInMinute(target = sessionStartTime, current = currentTime) + val result = with(dateUtil) { currentTime elapsedFrom sessionTime } then("초 단위는 올림 or 반올림 되지 않고 버려진다") { result shouldBe -30 } } 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 2b1520cc..8f7b92c7 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 @@ -52,7 +52,7 @@ class AdminMainViewModel @Inject constructor( val upcomingSession = getUpcomingSessionUseCase().getOrThrow() upcomingSession?.let { - var lastSessionId = if (dateUtil.isPastDateFromCurrentTime(upcomingSession.startTime)) it.sessionId else it.sessionId - 1 + var lastSessionId = if (with(dateUtil) { currentTime isAfterFrom upcomingSession.startTime }) it.sessionId else it.sessionId - 1 if (lastSessionId < 0) lastSessionId = AttendanceList.DEFAULT_UPCOMING_SESSION_ID setState { copy(lastSessionId = lastSessionId) } } 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 dad4b5e2..e28d3b76 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 @@ -342,7 +342,11 @@ private fun AttendUserSession( val attendance = attendanceInfo.second YDSAttendanceList( - attendanceType = checkSessionAttendance(session, attendance, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime)), + attendanceType = checkSessionAttendance( + session = session, + attendance = attendance, + isPastSession = with(dateUtil) { currentTime isAfterFrom session.startTime } + ), date = session.monthAndDay, title = session.title, description = session.description, 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 b2a7f009..60342152 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 @@ -37,7 +37,7 @@ class MemberScoreViewModel @Inject constructor( loadState = MemberScoreUiState.LoadState.Idle, attendanceList = attendanceList, lastAttendanceList = attendanceList.filter { (session, _) -> - dateUtil.isPastDateFromCurrentTime(session.startTime) + with(dateUtil) { currentTime isAfterFrom 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 1c9c20fb..6fd96479 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 @@ -40,7 +40,11 @@ fun SessionDetail( val dateUtil = remember { DateUtil() } val uiState by viewModel.uiState.collectAsState() val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance(session!!, uiState.session!!.second, isPastSession = dateUtil.isPastDateFromCurrentTime(session.startTime)) + val attendance = checkSessionAttendance( + session = session!!, + attendance = uiState.session!!.second, + isPastSession = with(dateUtil) { currentTime isAfterFrom session.startTime } + ) Scaffold( topBar = { From 040f10af652a97e3c983a9f5986b7f283ed43aa9 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 21:57:34 +0900 Subject: [PATCH 14/26] =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20Te?= =?UTF-8?q?st=ED=8C=8C=EC=9D=BC=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 빌드 깨지는 원인 제거 --- .../attendance/ExampleInstrumentedTest.kt | 22 ------------------- .../com/yapp/data/ExampleInstrumentedTest.kt | 22 ------------------- 2 files changed, 44 deletions(-) delete mode 100644 app/src/androidTest/java/com/yapp/attendance/ExampleInstrumentedTest.kt delete mode 100644 data/src/androidTest/java/com/yapp/data/ExampleInstrumentedTest.kt 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/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) - } -} From f2686dbc6426f3b79179e64a75fd0b7148f712ab Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 21:57:47 +0900 Subject: [PATCH 15/26] =?UTF-8?q?DateUtil=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yapp/domain/util/DateUtil.kt | 29 ------- domain/src/test/java/DateUtilTest.kt | 83 ------------------- 2 files changed, 112 deletions(-) delete mode 100644 domain/src/main/java/com/yapp/domain/util/DateUtil.kt delete mode 100644 domain/src/test/java/DateUtilTest.kt 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 1afb1bda..00000000 --- a/domain/src/main/java/com/yapp/domain/util/DateUtil.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.yapp.domain.util - -import java.time.Duration -import java.time.LocalDateTime -import javax.inject.Inject - -typealias Minute = Long - -class DateUtil @Inject constructor() { - - val currentTime: LocalDateTime - get() = LocalDateTime.now() - - /** - * [from] 에서 [this] 까지 시간이 얼마나 흘렀는지를 나타내는 메서드 - * 양수 (+) 일 경우 [from] 으로부터 시간이 이미 흐른상태, 음수 (-)인 경우 시간이 아직 [from] 까지 시간이 흐르지 않은상태 - */ - infix fun LocalDateTime.elapsedFrom(from: LocalDateTime): Minute { - return Duration.between(from, this).toMinutes() - } - - infix fun LocalDateTime.isBeforeFrom(from: LocalDateTime): Boolean { - return this.isBefore(from) - } - - infix fun LocalDateTime.isAfterFrom(from: LocalDateTime): Boolean { - return this.isAfter(from) - } -} \ No newline at end of file diff --git a/domain/src/test/java/DateUtilTest.kt b/domain/src/test/java/DateUtilTest.kt deleted file mode 100644 index 49d25b9b..00000000 --- a/domain/src/test/java/DateUtilTest.kt +++ /dev/null @@ -1,83 +0,0 @@ -import com.yapp.domain.util.DateParser -import com.yapp.domain.util.DateUtil -import io.kotest.core.spec.style.BehaviorSpec -import io.kotest.matchers.shouldBe - -class DateUtilTest : BehaviorSpec({ - val dateParser = DateParser() - val dateUtil = DateUtil() - - given("[세션시간]과 그로 부터 [30분 전 시간]이 주어진 경우") { - val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") - val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:30:00") - - `when`("두 시간의 차를 분 단위로 구하면") { - val result = with(dateUtil) { currentTime elapsedFrom sessionTime } - - then("차이는 -30분 이다") { result shouldBe -30 } - } - - `when`("곧 앞으로 다가올 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } - - then("앞으로 다가올 Date 이다") { result shouldBe true } - } - - `when`("이미 지난 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isAfterFrom sessionTime } - - then("이미 지난 Date가 아니다") { result shouldBe false } - } - } - - given("[세션시간]과 그로 부터 [20분이 지난 시간]이 주어진 경우") { - val currentTime = dateParser.parse(rawDate = "2024-01-04 14:20:00") - val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") - - `when`("두 시간의 차를 분 단위로 구했을 때") { - val result = with(dateUtil) { currentTime elapsedFrom sessionTime } - - then("차이는 20분 이다") { result shouldBe 20 } - } - - `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } - - then("앞으로 다가올 세션이 아니다") { result shouldBe false } - } - - `when`("이미 지난 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isAfterFrom sessionTime } - - then("이미 지난 Date 이다") { result shouldBe true } - } - } - - given("날짜가 다른, [현재시간]과 [세션시간]이 주어진 경우") { - val currentTime = dateParser.parse(rawDate = "2024-01-04 14:20:00") - val sessionTime = dateParser.parse(rawDate = "2024-01-05 14:00:00") - - `when`("앞으로 다가올 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isBeforeFrom sessionTime } - - then("앞으로 다가올 Date이다") { result shouldBe true } - } - - `when`("이미 지난 Date인지 확인 했을때") { - val result = with(dateUtil) { currentTime isAfterFrom sessionTime } - - then("이미 지난 Date가 아니다") { result shouldBe false } - } - } - - given("30분 50초 차의 두 시간이 주어진 경우") { - val currentTime = dateParser.parse(rawDate = "2024-01-04 14:00:00") - val sessionTime = dateParser.parse(rawDate = "2024-01-04 14:30:50") - - `when`("두 시간의 차를 분 단위로 구했을 때") { - val result = with(dateUtil) { currentTime elapsedFrom sessionTime } - - then("초 단위는 올림 or 반올림 되지 않고 버려진다") { result shouldBe -30 } - } - } -}) \ No newline at end of file From 25a3a64d8f9d7b662b78a6dd67af575b55bc0042 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 21:59:04 +0900 Subject: [PATCH 16/26] =?UTF-8?q?UseCase=EC=97=90=EC=84=9C=20DateUtil?= =?UTF-8?q?=EC=9D=84=20=EB=8C=80=EC=8B=A0=20LocalDateTime=EC=9D=98=20?= =?UTF-8?q?=ED=99=95=EC=9E=A5=ED=95=A8=EC=88=98=EB=A1=9C=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/usecases/CheckQrAuthTimeUseCase.kt | 16 ++++++++-------- .../domain/usecases/GetCurrentTimeUseCase.kt | 12 ++++++++++++ .../domain/usecases/GetUpcomingSessionUseCase.kt | 10 ++++------ .../domain/usecases/MarkAttendanceUseCase.kt | 9 +++++---- 4 files changed, 29 insertions(+), 18 deletions(-) create mode 100644 domain/src/main/java/com/yapp/domain/usecases/GetCurrentTimeUseCase.kt diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index 3172cb60..83e8cf8d 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -2,13 +2,13 @@ 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.Duration +import java.time.LocalDateTime import javax.inject.Inject class CheckQrAuthTimeUseCase @Inject constructor( - private val sessionRepository: SessionRepository, - private val dateUtil: DateUtil + private val sessionRepository: SessionRepository ) { companion object { @@ -17,13 +17,13 @@ class CheckQrAuthTimeUseCase @Inject constructor( } suspend operator fun invoke(): Result { + val currentTime = LocalDateTime.now() + return sessionRepository.getAllSession().mapCatching { sessionList: List -> - val upComingSession = sessionList.firstOrNull { session -> - with(dateUtil) { currentTime isBeforeFrom session.startTime } - } ?: return@mapCatching false - val elapsedTime = with(dateUtil) { currentTime elapsedFrom upComingSession.startTime } + val upComingSession = sessionList.firstOrNull { session -> currentTime.isBefore(session.startTime) } ?: return@mapCatching false + val elapsedTimeInMinutes = Duration.between(upComingSession.startTime, currentTime).toMinutes() - return@mapCatching elapsedTime in BEFORE_5_MINUTE..AFTER_30_MINUTE + return@mapCatching elapsedTimeInMinutes in BEFORE_5_MINUTE..AFTER_30_MINUTE } } 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 1dc371ad..ba447ad7 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -2,20 +2,18 @@ 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 dateUtil: DateUtil + private val sessionRepository: SessionRepository ) { suspend operator fun invoke(): Result { // 세션 당일 밤 12시까지 return sessionRepository.getAllSession().mapCatching { sessionList -> - sessionList.firstOrNull { session -> - with(dateUtil) { currentTime isBeforeFrom session.startTime } - } + val currentTime = LocalDateTime.now() + sessionList.firstOrNull { session -> currentTime.isBefore(session.startTime) } } } 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 6f1f1087..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,25 +4,26 @@ 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 dateUtil: DateUtil + 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( - elapsedTime = with(dateUtil) { currentTime elapsedFrom checkedSession.startTime} + elapsedTime = Duration.between(checkedSession.startTime, currentTime).toMinutes() ) ).also { updatedAttendanceList -> memberRepository.setMember(member = currentMemberInfo.copy(attendances = updatedAttendanceList)) From 187278e1123a7bb489b60c743f7d783bb84a8d81 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 21:59:48 +0900 Subject: [PATCH 17/26] =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Attendance.Status의 매핑 확장함수의 위치를 변경합니다 --- .../com/yapp/data/model/AttendanceEntity.kt | 4 ++++ .../data/model/types/AttendanceTypeEntity.kt | 24 ------------------- 2 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 data/src/main/java/com/yapp/data/model/types/AttendanceTypeEntity.kt 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/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() -} From 48aac2e26ceedc0c7eeb47988fe662bcb366b278 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 22:04:41 +0900 Subject: [PATCH 18/26] =?UTF-8?q?YDSAttendanceType=EC=9D=B4=20ResId?= =?UTF-8?q?=EB=A5=BC=20=EA=B0=80=EC=A7=80=EA=B3=A0=20=EC=9E=88=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - YDSAttendanceType이 ResId를 가지고 있는 바람에 ViewModel 단에서 사용하지 못하는 단점이 존재 - YDSType을 ResId로 매핑하는 컴포저블을 생성 --- .../com/yapp/common/yds/YDSAttendanceList.kt | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) 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 } From 160adbb0820601e0a135a3d2bbcf1bb75ef9d2e3 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 22:06:35 +0900 Subject: [PATCH 19/26] =?UTF-8?q?UI=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EB=90=98=EB=8D=98=20checkSessionAttendance=EB=A5=BC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AttendanceType을 UI대신 ViewModel에서 연산토록 AttendanceTypeMapper를 생성 --- .../common/AttendanceTypeMapper.kt | 33 +++++++++++++++++++ .../util/attendance/AttendanceCheck.kt | 28 ---------------- 2 files changed, 33 insertions(+), 28 deletions(-) create mode 100644 presentation/src/main/java/com/yapp/presentation/common/AttendanceTypeMapper.kt delete mode 100644 presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt 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/util/attendance/AttendanceCheck.kt b/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt deleted file mode 100644 index eab423f2..00000000 --- a/presentation/src/main/java/com/yapp/presentation/util/attendance/AttendanceCheck.kt +++ /dev/null @@ -1,28 +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 - -fun checkSessionAttendance( - session: Session, - attendance: Attendance, - isPastSession: Boolean -): YDSAttendanceType { - if (isPastSession.not()) { - 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 - } -} From cfefc43224c934792e59679e88ad9ab9e269476b Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 22:07:11 +0900 Subject: [PATCH 20/26] =?UTF-8?q?AdminMain=20=ED=99=94=EB=A9=B4=20DateUtil?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/admin/main/AdminMainViewModel.kt | 30 ++++++++----------- 1 file changed, 12 insertions(+), 18 deletions(-) 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 8f7b92c7..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 @@ -3,9 +3,9 @@ package com.yapp.presentation.ui.admin.main import androidx.lifecycle.viewModelScope import com.yapp.common.base.BaseViewModel 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 @@ -17,10 +17,8 @@ import javax.inject.Inject class AdminMainViewModel @Inject constructor( private val getSessionListUseCase: GetSessionListUseCase, private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase, - private val dateUtil: DateUtil -) : BaseViewModel( - AdminMainUiState() -) { + private val getCurrentTimeUseCase: GetCurrentTimeUseCase +) : BaseViewModel(AdminMainUiState()) { init { viewModelScope.launch { @@ -31,18 +29,13 @@ 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) } } @@ -50,9 +43,10 @@ class AdminMainViewModel @Inject constructor( getSessionListUseCase() .onSuccess { sessions -> val upcomingSession = getUpcomingSessionUseCase().getOrThrow() + val currentTime = getCurrentTimeUseCase() upcomingSession?.let { - var lastSessionId = if (with(dateUtil) { currentTime isAfterFrom upcomingSession.startTime }) 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) } } From 55e6af0da0cc09b3fec8b5abf494cb20638e561c Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 22:09:01 +0900 Subject: [PATCH 21/26] =?UTF-8?q?SessionDetail=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - UIState 재설계 (UiState가 Domain의 모델을 가지고 있지 않도록 수정) - AttendanceType을 UI가 아닌 SessionDetailViewModel 에서 연산하도록 함 --- .../ui/member/score/detail/SessionDetail.kt | 87 +++++++------------ .../score/detail/SessionDetailContract.kt | 21 ++++- .../score/detail/SessionDetailViewModel.kt | 66 +++++++++----- 3 files changed, 93 insertions(+), 81 deletions(-) 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 6fd96479..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 @@ -13,12 +13,9 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember 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 @@ -28,29 +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.domain.util.DateUtil -import com.yapp.presentation.util.attendance.checkSessionAttendance +import com.yapp.common.yds.icon +import com.yapp.common.yds.text @Composable fun SessionDetail( viewModel: SessionDetailViewModel = hiltViewModel(), onClickBackButton: () -> Unit, ) { - val dateUtil = remember { DateUtil() } val uiState by viewModel.uiState.collectAsState() - val session: Session? = uiState.session?.first - val attendance = checkSessionAttendance( - session = session!!, - attendance = uiState.session!!.second, - isPastSession = with(dateUtil) { currentTime isAfterFrom session.startTime } - ) Scaffold( topBar = { YDSAppBar( modifier = Modifier.background(AttendanceTheme.colors.backgroundColors.background), - title = session.title, + title = uiState.appBarTitle, onClickBackButton = onClickBackButton ) }, @@ -64,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 ) } } @@ -74,10 +62,8 @@ fun SessionDetail( @Composable fun SessionDetailScreen( modifier: Modifier = Modifier, - session: Session?, - attendance: YDSAttendanceType? + state: SessionDetailContract.SessionDetailUiState.SessionDetailScreenState ) { - Column( modifier = modifier .fillMaxSize() @@ -85,57 +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) { - Text( - text = session.monthAndDay, - 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 + } From 30ee16345d1d669dce759a8848dab3a56282c0ec Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sat, 4 May 2024 22:09:45 +0900 Subject: [PATCH 22/26] =?UTF-8?q?MemberScore=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AttendanceType을 UI가 아닌 MemberScoreViewModel 에서 연산하도록 함 --- .../ui/member/score/MemberScore.kt | 46 +++++++------------ .../ui/member/score/MemberScoreContract.kt | 5 +- .../ui/member/score/MemberScoreViewModel.kt | 22 +++++++-- 3 files changed, 36 insertions(+), 37 deletions(-) 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 e28d3b76..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,14 +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.domain.util.DateUtil import com.yapp.presentation.R -import com.yapp.presentation.util.attendance.checkSessionAttendance @Composable fun MemberScore( @@ -92,7 +92,6 @@ fun MemberScore( navigateToSessionDetail = navigateToSessionDetail ) } - } } @@ -130,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, + ) } } } @@ -155,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), ) } @@ -193,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 @@ -225,7 +219,6 @@ fun SemiCircleProgressBar(score: Int) { style = Stroke(width = 25f, cap = StrokeCap.Round) ) - drawArc( color = arcColor, startAngle = 180f, @@ -334,19 +327,12 @@ fun RowScope.AttendanceCell( @Composable private fun AttendUserSession( - attendanceInfo: Pair, + session: Session, + attendanceType: YDSAttendanceType, navigateToSessionDetail: (Int) -> Unit ) { - val dateUtil = remember { DateUtil() } - val session = attendanceInfo.first - val attendance = attendanceInfo.second - YDSAttendanceList( - attendanceType = checkSessionAttendance( - session = session, - attendance = attendance, - isPastSession = with(dateUtil) { currentTime isAfterFrom session.startTime } - ), + 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 60342152..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,7 +16,8 @@ import javax.inject.Inject @HiltViewModel class MemberScoreViewModel @Inject constructor( private val getMemberAttendanceListUseCase: GetMemberAttendanceListUseCase, - private val dateUtil: DateUtil + private val getCurrentTimeUseCase: GetCurrentTimeUseCase, + private val attendanceTypeMapper: AttendanceTypeMapper ) : BaseViewModel(initialState = MemberScoreUiState()) { init { @@ -31,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 { (session, _) -> - with(dateUtil) { currentTime isAfterFrom session.startTime } + lastAttendanceList = (sessions zip attendances).filter { (session, _) -> + currentTime.isAfter(session.startTime) } ) } From 116078852b87ba5c7ab44edac11801df9a578fd0 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 5 May 2024 17:44:05 +0900 Subject: [PATCH 23/26] =?UTF-8?q?=EB=85=84,=20=EC=9B=94,=20=EC=9D=BC,=20?= =?UTF-8?q?=EC=9D=BC=EC=B9=98=ED=95=98=EB=8A=94=20=EA=B2=BD=EC=9A=B0=20?= =?UTF-8?q?=EC=98=A4=EB=8A=98=EC=9D=98=20=EC=84=B8=EC=85=98=EC=9D=84=20?= =?UTF-8?q?=EB=A6=AC=ED=84=B4=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 당일 12시까지 해당 세션을 노출하도록 수정합니다 --- .../domain/usecases/GetUpcomingSessionUseCase.kt | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 ba447ad7..e29cf321 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/GetUpcomingSessionUseCase.kt @@ -10,11 +10,23 @@ class GetUpcomingSessionUseCase @Inject constructor( ) { suspend operator fun invoke(): Result { - // 세션 당일 밤 12시까지 return sessionRepository.getAllSession().mapCatching { sessionList -> 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 + } } - } } From 0b78a995210ce04819d8fa423a38113bfd5161d5 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 5 May 2024 17:47:18 +0900 Subject: [PATCH 24/26] =?UTF-8?q?=EC=B6=9C=EC=84=9D=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=9D=84=20=EA=B3=84=EC=82=B0=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9D=84=20GetUpComingSessionUseCase=EC=97=90=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 반복되어 UpComingSession을 구하는 로직을 GetUpComingSessionUseCase를 사용하도록 수정 --- .../yapp/domain/usecases/CheckQrAuthTimeUseCase.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt index 83e8cf8d..163b39c7 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt @@ -1,14 +1,12 @@ package com.yapp.domain.usecases -import com.yapp.domain.model.Session -import com.yapp.domain.repository.SessionRepository import java.time.Duration import java.time.LocalDateTime import javax.inject.Inject class CheckQrAuthTimeUseCase @Inject constructor( - private val sessionRepository: SessionRepository + private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase ) { companion object { @@ -19,11 +17,14 @@ class CheckQrAuthTimeUseCase @Inject constructor( suspend operator fun invoke(): Result { val currentTime = LocalDateTime.now() - return sessionRepository.getAllSession().mapCatching { sessionList: List -> - val upComingSession = sessionList.firstOrNull { session -> currentTime.isBefore(session.startTime) } ?: return@mapCatching false + return getUpcomingSessionUseCase().mapCatching { upComingSession -> + if (upComingSession == null) { + return@mapCatching false + } + val elapsedTimeInMinutes = Duration.between(upComingSession.startTime, currentTime).toMinutes() - return@mapCatching elapsedTimeInMinutes in BEFORE_5_MINUTE..AFTER_30_MINUTE + elapsedTimeInMinutes in BEFORE_5_MINUTE..AFTER_30_MINUTE } } From 5c9afb6a568f154db93b275a71b228884dd470d5 Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Sun, 5 May 2024 17:48:58 +0900 Subject: [PATCH 25/26] =?UTF-8?q?UseCase=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - QR인증이 제거되어 CheckQRAuthTimeUseCase -> CheckAttendanceTimeUseCase 로 네이밍 수정 --- ...heckQrAuthTimeUseCase.kt => CheckAttendanceTimeUseCase.kt} | 2 +- .../src/main/java/com/yapp/presentation/ui/MainViewModel.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename domain/src/main/java/com/yapp/domain/usecases/{CheckQrAuthTimeUseCase.kt => CheckAttendanceTimeUseCase.kt} (93%) diff --git a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt b/domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt similarity index 93% rename from domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt rename to domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt index 163b39c7..15fa73ae 100644 --- a/domain/src/main/java/com/yapp/domain/usecases/CheckQrAuthTimeUseCase.kt +++ b/domain/src/main/java/com/yapp/domain/usecases/CheckAttendanceTimeUseCase.kt @@ -5,7 +5,7 @@ import java.time.LocalDateTime import javax.inject.Inject -class CheckQrAuthTimeUseCase @Inject constructor( +class CheckAttendanceTimeUseCase @Inject constructor( private val getUpcomingSessionUseCase: GetUpcomingSessionUseCase ) { 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..414c6324 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() From a717860ee98dba52bc23b5195a0ea443078986cd Mon Sep 17 00:00:00 2001 From: YeongSang Jeon Date: Mon, 6 May 2024 22:38:36 +0900 Subject: [PATCH 26/26] =?UTF-8?q?=EC=98=A4=ED=83=88=EC=9E=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UseCase 네이밍 변경으로 수정 --- .../src/main/java/com/yapp/presentation/ui/MainViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 414c6324..2ace70da 100644 --- a/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt +++ b/presentation/src/main/java/com/yapp/presentation/ui/MainViewModel.kt @@ -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)