From d300324111ba4fe19e42e5ee6b9ced01debff6c1 Mon Sep 17 00:00:00 2001 From: Jacob Bosco Date: Tue, 18 Oct 2022 21:54:09 +0530 Subject: [PATCH] WTA #44: Added use case to get cached data. --- .../usecases/GetCachedHomePageUiData.kt | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetCachedHomePageUiData.kt diff --git a/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetCachedHomePageUiData.kt b/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetCachedHomePageUiData.kt new file mode 100644 index 00000000..bcbb8d0d --- /dev/null +++ b/home/src/main/java/com/jacob/wakatimeapp/home/domain/usecases/GetCachedHomePageUiData.kt @@ -0,0 +1,114 @@ +package com.jacob.wakatimeapp.home.domain.usecases + +import arrow.core.computations.either +import arrow.core.right +import com.jacob.wakatimeapp.core.common.auth.AuthDataStore +import com.jacob.wakatimeapp.home.data.local.HomePageCache +import com.jacob.wakatimeapp.home.domain.InstantProvider +import com.jacob.wakatimeapp.home.domain.models.HomePageUserDetails +import com.jacob.wakatimeapp.home.domain.models.Last7DaysStats +import com.jacob.wakatimeapp.home.domain.models.StreakRange +import com.jacob.wakatimeapp.home.domain.models.Streaks +import com.jacob.wakatimeapp.home.domain.models.toHomePageUserDetails +import com.jacob.wakatimeapp.home.domain.usecases.CacheState.FirstRequest +import com.jacob.wakatimeapp.home.domain.usecases.CacheState.InvalidData +import com.jacob.wakatimeapp.home.domain.usecases.CacheState.ValidData +import com.jacob.wakatimeapp.home.domain.usecases.GetCachedHomePageUiData.CacheValidity.DEFAULT +import javax.inject.Inject +import javax.inject.Singleton +import kotlinx.coroutines.flow.channelFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onEach +import kotlinx.datetime.Instant +import kotlinx.datetime.toLocalDateTime + +@Singleton +class GetCachedHomePageUiData @Inject constructor( + private val instantProvider: InstantProvider, + private val homePageCache: HomePageCache, + private val authDataStore: AuthDataStore, +) { + operator fun invoke(cacheValidity: CacheValidity = DEFAULT) = channelFlow { + val lastRequestTime = homePageCache.getLastRequestTime() + + if (firstRequestOfDay(lastRequestTime)) { + send(FirstRequest.right()) + return@channelFlow + } + + combine( + getLast7DaysStats(), + getHomePageUserDetails(), + getStreaks() + ) { last7DaysStatsEither, userDetails, streaksEither -> + either { + val last7DaysStats = last7DaysStatsEither.bind() + val streakRange = streaksEither.bind() + val streaks = Streaks( + currentStreak = streakRange, + longestStreak = StreakRange.ZERO + ) + + when { + validDataInCache(lastRequestTime, cacheValidity) -> ValidData( + last7DaysStats = last7DaysStats, + userDetails = userDetails.toHomePageUserDetails(), + streaks = streaks + ) + + else -> InvalidData( + last7DaysStats = last7DaysStats, + userDetails = userDetails.toHomePageUserDetails(), + streaks = streaks + ) + } + } + }.onEach { send(it) } + .flowOn(this.coroutineContext) + } + + private fun getHomePageUserDetails() = authDataStore.getUserDetails() + + private fun getLast7DaysStats() = homePageCache.getLast7DaysStats() + + private fun getStreaks() = homePageCache.getCurrentStreak() + + private fun firstRequestOfDay(lastRequestTime: Instant) = lastRequestTime.isPreviousDay() + + private fun validDataInCache( + lastRequestTime: Instant, + cacheValidityTime: CacheValidity, + ): Boolean { + val minutesBetweenLastRequest = instantProvider.now() - lastRequestTime + return minutesBetweenLastRequest.inWholeMinutes < cacheValidityTime.minutes + } + + private fun Instant.isPreviousDay(): Boolean { + val lastRequestDate = this.toLocalDateTime(instantProvider.timeZone).date.toEpochDays() + val currentDate = + instantProvider.now().toLocalDateTime(instantProvider.timeZone).date.toEpochDays() + + return currentDate - lastRequestDate >= 1 + } + + enum class CacheValidity(val minutes: Long) { + DEFAULT(15L), + INVALID(0L), + } +} + +sealed class CacheState { + object FirstRequest : CacheState() + data class ValidData( + val last7DaysStats: Last7DaysStats, + val userDetails: HomePageUserDetails, + val streaks: Streaks, + ) : CacheState() + + data class InvalidData( + val last7DaysStats: Last7DaysStats, + val userDetails: HomePageUserDetails, + val streaks: Streaks, + ) : CacheState() +}