Loading app/src/main/java/foundation/e/advancedprivacy/domain/entities/weeklyreport/WeeklyReport.kt +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package foundation.e.advancedprivacy.domain.entities.weeklyreport import foundation.e.advancedprivacy.core.utils.InstantSerializer import java.time.Instant import java.time.LocalDate import java.time.ZoneId import kotlinx.serialization.Serializable @Serializable Loading @@ -30,6 +32,10 @@ data class WeeklyReport( val primaryValue: String, val secondaryValues: List<String> ) { fun getDate(): LocalDate { return timestamp.atZone(ZoneId.systemDefault()).toLocalDate() } @Serializable enum class StatType { CALLS_PER_APP, Loading app/src/main/java/foundation/e/advancedprivacy/domain/usecases/WeeklyReportUseCase.kt +4 −5 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReportSco import foundation.e.advancedprivacy.externalinterfaces.workers.WeeklyReportWorkerScheduler import foundation.e.advancedprivacy.trackers.data.StatsDatabase import foundation.e.advancedprivacy.trackers.data.TrackersRepository import java.time.Duration import java.time.Instant import java.time.LocalDate import java.time.temporal.ChronoUnit import kotlin.collections.component1 import kotlin.collections.component2 Loading @@ -47,7 +47,8 @@ class WeeklyReportUseCase( private val scope: CoroutineScope ) { companion object { val DISPLAY_DURATION: Duration = Duration.ofDays(1) const val REPORT_DAY_OF_WEEK: Long = 7L const val REPORT_HOUR: Long = 11L } private val _currentReport = MutableStateFlow<DisplayableReport?>(null) val currentReport: StateFlow<DisplayableReport?> = _currentReport Loading @@ -63,9 +64,7 @@ class WeeklyReportUseCase( suspend fun updateCurrent() { val weeklyReport = weeklyReportRepository.getLastWeeklyReport() ?: return val now = Instant.now() val endOfDisplay = weeklyReport.timestamp + DISPLAY_DURATION if (now < endOfDisplay) { if (LocalDate.now() == weeklyReport.getDate()) { _currentReport.value = weeklyReport.toDisplayableReport() } else { _currentReport.value = null Loading app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/workers/WeeklyReportWorker.kt +17 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.work.WorkManager import androidx.work.WorkerParameters import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReport import foundation.e.advancedprivacy.domain.usecases.WeeklyReportUseCase import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime import java.time.temporal.ChronoUnit Loading Loading @@ -59,16 +58,18 @@ class WeeklyReportWorkerScheduler(private val appContext: Context) { fun scheduleNext(lastReport: WeeklyReport?) { val now = ZonedDateTime.now() var next = now next = next.with(WeekFields.of(appContext.resources.configuration.locales[0]).dayOfWeek(), 7) next = next.with(WeekFields.of(appContext.resources.configuration.locales[0]).dayOfWeek(), WeeklyReportUseCase.REPORT_DAY_OF_WEEK) next = next.truncatedTo(ChronoUnit.DAYS) if (next.toLocalDate() == lastReport?.timestamp?.atZone(ZoneId.systemDefault())?.toLocalDate() && now.hour >= 11) { // Report has already been created today, // next report will be scheduled for next week if (next.toLocalDate() == lastReport?.timestamp && now.hour >= WeeklyReportUseCase.REPORT_HOUR) { next = next.plus(7, ChronoUnit.DAYS) } next = next.plus(11, ChronoUnit.HOURS) next = next.plus(WeeklyReportUseCase.REPORT_HOUR, ChronoUnit.HOURS) val delay = next.toEpochSecond() - ZonedDateTime.now().toEpochSecond() val delay = next.toEpochSecond() - now.toEpochSecond() Timber.d("Schedule Weeklyreport for $next, in $delay seconds") val request = OneTimeWorkRequestBuilder<WeeklyReportWorker>() Loading @@ -83,15 +84,22 @@ class WeeklyReportWorkerScheduler(private val appContext: Context) { } fun scheduleDismiss(currentReport: WeeklyReport?) { val next = currentReport?.timestamp?.plus(WeeklyReportUseCase.DISPLAY_DURATION) ?: return val delay = next.toEpochMilli() - Instant.now().toEpochMilli() if (currentReport == null) { return } val dismiss = ZonedDateTime.ofInstant(currentReport.timestamp, ZoneId.systemDefault()) .plus(1, ChronoUnit.DAYS) .truncatedTo(ChronoUnit.DAYS) val delay = dismiss.toEpochSecond() - ZonedDateTime.now().toEpochSecond() if (delay < 0) { return } Timber.d("Schedule Dismiss of WeeklyReport of ${currentReport.timestamp} at $next, in $delay milliseconds") Timber.d("Schedule Dismiss of WeeklyReport of ${currentReport.timestamp} at $dismiss, in $delay seconds") val request = OneTimeWorkRequestBuilder<WeeklyReportDismissWorker>() .setInitialDelay(delay, TimeUnit.MILLISECONDS) .setInitialDelay(delay, TimeUnit.SECONDS) .build() WorkManager.getInstance(appContext).enqueueUniqueWork( Loading Loading
app/src/main/java/foundation/e/advancedprivacy/domain/entities/weeklyreport/WeeklyReport.kt +6 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package foundation.e.advancedprivacy.domain.entities.weeklyreport import foundation.e.advancedprivacy.core.utils.InstantSerializer import java.time.Instant import java.time.LocalDate import java.time.ZoneId import kotlinx.serialization.Serializable @Serializable Loading @@ -30,6 +32,10 @@ data class WeeklyReport( val primaryValue: String, val secondaryValues: List<String> ) { fun getDate(): LocalDate { return timestamp.atZone(ZoneId.systemDefault()).toLocalDate() } @Serializable enum class StatType { CALLS_PER_APP, Loading
app/src/main/java/foundation/e/advancedprivacy/domain/usecases/WeeklyReportUseCase.kt +4 −5 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReportSco import foundation.e.advancedprivacy.externalinterfaces.workers.WeeklyReportWorkerScheduler import foundation.e.advancedprivacy.trackers.data.StatsDatabase import foundation.e.advancedprivacy.trackers.data.TrackersRepository import java.time.Duration import java.time.Instant import java.time.LocalDate import java.time.temporal.ChronoUnit import kotlin.collections.component1 import kotlin.collections.component2 Loading @@ -47,7 +47,8 @@ class WeeklyReportUseCase( private val scope: CoroutineScope ) { companion object { val DISPLAY_DURATION: Duration = Duration.ofDays(1) const val REPORT_DAY_OF_WEEK: Long = 7L const val REPORT_HOUR: Long = 11L } private val _currentReport = MutableStateFlow<DisplayableReport?>(null) val currentReport: StateFlow<DisplayableReport?> = _currentReport Loading @@ -63,9 +64,7 @@ class WeeklyReportUseCase( suspend fun updateCurrent() { val weeklyReport = weeklyReportRepository.getLastWeeklyReport() ?: return val now = Instant.now() val endOfDisplay = weeklyReport.timestamp + DISPLAY_DURATION if (now < endOfDisplay) { if (LocalDate.now() == weeklyReport.getDate()) { _currentReport.value = weeklyReport.toDisplayableReport() } else { _currentReport.value = null Loading
app/src/main/java/foundation/e/advancedprivacy/externalinterfaces/workers/WeeklyReportWorker.kt +17 −9 Original line number Diff line number Diff line Loading @@ -25,7 +25,6 @@ import androidx.work.WorkManager import androidx.work.WorkerParameters import foundation.e.advancedprivacy.domain.entities.weeklyreport.WeeklyReport import foundation.e.advancedprivacy.domain.usecases.WeeklyReportUseCase import java.time.Instant import java.time.ZoneId import java.time.ZonedDateTime import java.time.temporal.ChronoUnit Loading Loading @@ -59,16 +58,18 @@ class WeeklyReportWorkerScheduler(private val appContext: Context) { fun scheduleNext(lastReport: WeeklyReport?) { val now = ZonedDateTime.now() var next = now next = next.with(WeekFields.of(appContext.resources.configuration.locales[0]).dayOfWeek(), 7) next = next.with(WeekFields.of(appContext.resources.configuration.locales[0]).dayOfWeek(), WeeklyReportUseCase.REPORT_DAY_OF_WEEK) next = next.truncatedTo(ChronoUnit.DAYS) if (next.toLocalDate() == lastReport?.timestamp?.atZone(ZoneId.systemDefault())?.toLocalDate() && now.hour >= 11) { // Report has already been created today, // next report will be scheduled for next week if (next.toLocalDate() == lastReport?.timestamp && now.hour >= WeeklyReportUseCase.REPORT_HOUR) { next = next.plus(7, ChronoUnit.DAYS) } next = next.plus(11, ChronoUnit.HOURS) next = next.plus(WeeklyReportUseCase.REPORT_HOUR, ChronoUnit.HOURS) val delay = next.toEpochSecond() - ZonedDateTime.now().toEpochSecond() val delay = next.toEpochSecond() - now.toEpochSecond() Timber.d("Schedule Weeklyreport for $next, in $delay seconds") val request = OneTimeWorkRequestBuilder<WeeklyReportWorker>() Loading @@ -83,15 +84,22 @@ class WeeklyReportWorkerScheduler(private val appContext: Context) { } fun scheduleDismiss(currentReport: WeeklyReport?) { val next = currentReport?.timestamp?.plus(WeeklyReportUseCase.DISPLAY_DURATION) ?: return val delay = next.toEpochMilli() - Instant.now().toEpochMilli() if (currentReport == null) { return } val dismiss = ZonedDateTime.ofInstant(currentReport.timestamp, ZoneId.systemDefault()) .plus(1, ChronoUnit.DAYS) .truncatedTo(ChronoUnit.DAYS) val delay = dismiss.toEpochSecond() - ZonedDateTime.now().toEpochSecond() if (delay < 0) { return } Timber.d("Schedule Dismiss of WeeklyReport of ${currentReport.timestamp} at $next, in $delay milliseconds") Timber.d("Schedule Dismiss of WeeklyReport of ${currentReport.timestamp} at $dismiss, in $delay seconds") val request = OneTimeWorkRequestBuilder<WeeklyReportDismissWorker>() .setInitialDelay(delay, TimeUnit.MILLISECONDS) .setInitialDelay(delay, TimeUnit.SECONDS) .build() WorkManager.getInstance(appContext).enqueueUniqueWork( Loading