From 818471b7e137a15dce48352f686db24b117414ea Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 16 Jul 2023 15:01:04 -0400 Subject: [PATCH] Set start date when tracker is bound if any chapters are already read Closes #6734 --- .../tachiyomi/data/backup/BackupManager.kt | 8 +++++--- .../tachiyomi/data/track/TrackService.kt | 15 +++++++++++++++ .../ui/manga/track/TrackInfoDialog.kt | 19 +++---------------- .../tachiyomi/util/lang/DateExtensions.kt | 13 +++++++++++++ .../data/history/HistoryRepositoryImpl.kt | 5 +++++ .../domain/history/interactor/GetHistory.kt | 5 +++++ .../history/repository/HistoryRepository.kt | 3 +++ 7 files changed, 49 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 9b3a731d49..753183f0e5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -40,6 +40,7 @@ import tachiyomi.data.updateStrategyAdapter import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.model.Category +import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.manga.interactor.GetFavorites @@ -61,6 +62,7 @@ class BackupManager( private val libraryPreferences: LibraryPreferences = Injekt.get() private val getCategories: GetCategories = Injekt.get() private val getFavorites: GetFavorites = Injekt.get() + private val getHistory: GetHistory = Injekt.get() internal val parser = ProtoBuf @@ -205,11 +207,11 @@ class BackupManager( // Check if user wants history information in backup if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) { - val historyByMangaId = handler.awaitList(true) { historyQueries.getHistoryByMangaId(manga.id) } + val historyByMangaId = getHistory.await(manga.id) if (historyByMangaId.isNotEmpty()) { val history = historyByMangaId.map { history -> - val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapter_id) } - BackupHistory(chapter.url, history.last_read?.time ?: 0L, history.time_read) + val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) } + BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration) } if (history.isNotEmpty()) { mangaObject.history = history diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt index b1444b0670..297e4a2924 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackService.kt @@ -13,6 +13,7 @@ import eu.kanade.domain.track.service.TrackPreferences import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.network.NetworkHelper +import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.toast import logcat.LogPriority import okhttp3.OkHttpClient @@ -20,10 +21,12 @@ import tachiyomi.core.util.lang.withIOContext import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.system.logcat import tachiyomi.domain.chapter.interactor.GetChapterByMangaId +import tachiyomi.domain.history.interactor.GetHistory import tachiyomi.domain.track.interactor.InsertTrack import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import java.time.ZoneOffset import tachiyomi.domain.track.model.Track as DomainTrack abstract class TrackService(val id: Long) { @@ -125,6 +128,18 @@ abstract class TrackService(val id: Long) { ) setRemoteLastChapterRead(updatedTrack.toDbTrack(), latestLocalReadChapterNumber.toInt()) } + + if (track.startDate <= 0) { + val firstReadChapterDate = Injekt.get().await(mangaId) + .sortedBy { it.readAt } + .firstOrNull() + ?.readAt + + firstReadChapterDate?.let { + val startDate = firstReadChapterDate.time.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) + setRemoteStartDate(track.toDbTrack(), startDate) + } + } } if (this is EnhancedTrackService) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt index 04c5cd40d6..815c8d4542 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackInfoDialog.kt @@ -56,6 +56,7 @@ import eu.kanade.tachiyomi.data.track.EnhancedTrackService import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.model.TrackSearch +import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.toast import kotlinx.coroutines.flow.catch @@ -82,7 +83,6 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.time.Instant import java.time.LocalDate -import java.time.LocalDateTime import java.time.ZoneId import java.time.ZoneOffset @@ -534,13 +534,13 @@ private data class TrackDateSelectorScreen( val millis = (if (start) track.startDate else track.finishDate) .takeIf { it != 0L } ?: Instant.now().toEpochMilli() - return convertEpochMillisZone(millis, ZoneOffset.systemDefault(), ZoneOffset.UTC) + return millis.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC) } // In UTC fun setDate(millis: Long) { // Convert to local time - val localMillis = convertEpochMillisZone(millis, ZoneOffset.UTC, ZoneOffset.systemDefault()) + val localMillis = millis.convertEpochMillisZone(ZoneOffset.UTC, ZoneOffset.systemDefault()) coroutineScope.launchNonCancellable { if (start) { service.setRemoteStartDate(track.toDbTrack(), localMillis) @@ -554,19 +554,6 @@ private data class TrackDateSelectorScreen( navigator.push(TrackDateRemoverScreen(track, service.id, start)) } } - - companion object { - private fun convertEpochMillisZone( - localMillis: Long, - from: ZoneId, - to: ZoneId, - ): Long { - return LocalDateTime.ofInstant(Instant.ofEpochMilli(localMillis), from) - .atZone(to) - .toInstant() - .toEpochMilli() - } - } } private data class TrackDateRemoverScreen( diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt index 3cf59811e8..c7c29561bc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/lang/DateExtensions.kt @@ -3,6 +3,9 @@ package eu.kanade.tachiyomi.util.lang import android.content.Context import eu.kanade.tachiyomi.R import java.text.DateFormat +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId import java.util.Calendar import java.util.Date import java.util.TimeZone @@ -17,6 +20,16 @@ fun Date.toTimestampString(): String { return DateFormat.getTimeInstance(DateFormat.SHORT).format(this) } +fun Long.convertEpochMillisZone( + from: ZoneId, + to: ZoneId, +): Long { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(this), from) + .atZone(to) + .toInstant() + .toEpochMilli() +} + /** * Get date as time key * diff --git a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt index f13569693a..7f349afc2c 100644 --- a/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt +++ b/data/src/main/java/tachiyomi/data/history/HistoryRepositoryImpl.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow import logcat.LogPriority import tachiyomi.core.util.system.logcat import tachiyomi.data.DatabaseHandler +import tachiyomi.domain.history.model.History import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.repository.HistoryRepository @@ -28,6 +29,10 @@ class HistoryRepositoryImpl( return handler.awaitOne { historyQueries.getReadDuration() } } + override suspend fun getHistoryByMangaId(mangaId: Long): List { + return handler.awaitList { historyQueries.getHistoryByMangaId(mangaId, historyMapper) } + } + override suspend fun resetHistory(historyId: Long) { try { handler.await { historyQueries.resetHistoryById(historyId) } diff --git a/domain/src/main/java/tachiyomi/domain/history/interactor/GetHistory.kt b/domain/src/main/java/tachiyomi/domain/history/interactor/GetHistory.kt index dd19a9e8f7..8a40096f86 100644 --- a/domain/src/main/java/tachiyomi/domain/history/interactor/GetHistory.kt +++ b/domain/src/main/java/tachiyomi/domain/history/interactor/GetHistory.kt @@ -1,6 +1,7 @@ package tachiyomi.domain.history.interactor import kotlinx.coroutines.flow.Flow +import tachiyomi.domain.history.model.History import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.repository.HistoryRepository @@ -8,6 +9,10 @@ class GetHistory( private val repository: HistoryRepository, ) { + suspend fun await(mangaId: Long): List { + return repository.getHistoryByMangaId(mangaId) + } + fun subscribe(query: String): Flow> { return repository.getHistory(query) } diff --git a/domain/src/main/java/tachiyomi/domain/history/repository/HistoryRepository.kt b/domain/src/main/java/tachiyomi/domain/history/repository/HistoryRepository.kt index 2123ae796d..410bfe951c 100644 --- a/domain/src/main/java/tachiyomi/domain/history/repository/HistoryRepository.kt +++ b/domain/src/main/java/tachiyomi/domain/history/repository/HistoryRepository.kt @@ -1,6 +1,7 @@ package tachiyomi.domain.history.repository import kotlinx.coroutines.flow.Flow +import tachiyomi.domain.history.model.History import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryWithRelations @@ -12,6 +13,8 @@ interface HistoryRepository { suspend fun getTotalReadDuration(): Long + suspend fun getHistoryByMangaId(mangaId: Long): List + suspend fun resetHistory(historyId: Long) suspend fun resetHistoryByMangaId(mangaId: Long)