Set start date when tracker is bound if any chapters are already read

Closes #6734
This commit is contained in:
arkon 2023-07-16 15:01:04 -04:00
parent a3a3f44056
commit 818471b7e1
7 changed files with 49 additions and 19 deletions

View file

@ -40,6 +40,7 @@ import tachiyomi.data.updateStrategyAdapter
import tachiyomi.domain.backup.service.BackupPreferences import tachiyomi.domain.backup.service.BackupPreferences
import tachiyomi.domain.category.interactor.GetCategories import tachiyomi.domain.category.interactor.GetCategories
import tachiyomi.domain.category.model.Category import tachiyomi.domain.category.model.Category
import tachiyomi.domain.history.interactor.GetHistory
import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryUpdate
import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.domain.manga.interactor.GetFavorites import tachiyomi.domain.manga.interactor.GetFavorites
@ -61,6 +62,7 @@ class BackupManager(
private val libraryPreferences: LibraryPreferences = Injekt.get() private val libraryPreferences: LibraryPreferences = Injekt.get()
private val getCategories: GetCategories = Injekt.get() private val getCategories: GetCategories = Injekt.get()
private val getFavorites: GetFavorites = Injekt.get() private val getFavorites: GetFavorites = Injekt.get()
private val getHistory: GetHistory = Injekt.get()
internal val parser = ProtoBuf internal val parser = ProtoBuf
@ -205,11 +207,11 @@ class BackupManager(
// Check if user wants history information in backup // Check if user wants history information in backup
if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) { 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()) { if (historyByMangaId.isNotEmpty()) {
val history = historyByMangaId.map { history -> val history = historyByMangaId.map { history ->
val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapter_id) } val chapter = handler.awaitOne { chaptersQueries.getChapterById(history.chapterId) }
BackupHistory(chapter.url, history.last_read?.time ?: 0L, history.time_read) BackupHistory(chapter.url, history.readAt?.time ?: 0L, history.readDuration)
} }
if (history.isNotEmpty()) { if (history.isNotEmpty()) {
mangaObject.history = history mangaObject.history = history

View file

@ -13,6 +13,7 @@ import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.model.TrackSearch import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.util.lang.convertEpochMillisZone
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import logcat.LogPriority import logcat.LogPriority
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -20,10 +21,12 @@ import tachiyomi.core.util.lang.withIOContext
import tachiyomi.core.util.lang.withUIContext import tachiyomi.core.util.lang.withUIContext
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.domain.chapter.interactor.GetChapterByMangaId import tachiyomi.domain.chapter.interactor.GetChapterByMangaId
import tachiyomi.domain.history.interactor.GetHistory
import tachiyomi.domain.track.interactor.InsertTrack import tachiyomi.domain.track.interactor.InsertTrack
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.time.ZoneOffset
import tachiyomi.domain.track.model.Track as DomainTrack import tachiyomi.domain.track.model.Track as DomainTrack
abstract class TrackService(val id: Long) { abstract class TrackService(val id: Long) {
@ -125,6 +128,18 @@ abstract class TrackService(val id: Long) {
) )
setRemoteLastChapterRead(updatedTrack.toDbTrack(), latestLocalReadChapterNumber.toInt()) setRemoteLastChapterRead(updatedTrack.toDbTrack(), latestLocalReadChapterNumber.toInt())
} }
if (track.startDate <= 0) {
val firstReadChapterDate = Injekt.get<GetHistory>().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) { if (this is EnhancedTrackService) {

View file

@ -56,6 +56,7 @@ import eu.kanade.tachiyomi.data.track.EnhancedTrackService
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch 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.openInBrowser
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.catch
@ -82,7 +83,6 @@ import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.ZoneOffset import java.time.ZoneOffset
@ -534,13 +534,13 @@ private data class TrackDateSelectorScreen(
val millis = (if (start) track.startDate else track.finishDate) val millis = (if (start) track.startDate else track.finishDate)
.takeIf { it != 0L } .takeIf { it != 0L }
?: Instant.now().toEpochMilli() ?: Instant.now().toEpochMilli()
return convertEpochMillisZone(millis, ZoneOffset.systemDefault(), ZoneOffset.UTC) return millis.convertEpochMillisZone(ZoneOffset.systemDefault(), ZoneOffset.UTC)
} }
// In UTC // In UTC
fun setDate(millis: Long) { fun setDate(millis: Long) {
// Convert to local time // Convert to local time
val localMillis = convertEpochMillisZone(millis, ZoneOffset.UTC, ZoneOffset.systemDefault()) val localMillis = millis.convertEpochMillisZone(ZoneOffset.UTC, ZoneOffset.systemDefault())
coroutineScope.launchNonCancellable { coroutineScope.launchNonCancellable {
if (start) { if (start) {
service.setRemoteStartDate(track.toDbTrack(), localMillis) service.setRemoteStartDate(track.toDbTrack(), localMillis)
@ -554,19 +554,6 @@ private data class TrackDateSelectorScreen(
navigator.push(TrackDateRemoverScreen(track, service.id, start)) 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( private data class TrackDateRemoverScreen(

View file

@ -3,6 +3,9 @@ package eu.kanade.tachiyomi.util.lang
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import java.text.DateFormat import java.text.DateFormat
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.TimeZone import java.util.TimeZone
@ -17,6 +20,16 @@ fun Date.toTimestampString(): String {
return DateFormat.getTimeInstance(DateFormat.SHORT).format(this) 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 * Get date as time key
* *

View file

@ -4,6 +4,7 @@ import kotlinx.coroutines.flow.Flow
import logcat.LogPriority import logcat.LogPriority
import tachiyomi.core.util.system.logcat import tachiyomi.core.util.system.logcat
import tachiyomi.data.DatabaseHandler import tachiyomi.data.DatabaseHandler
import tachiyomi.domain.history.model.History
import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryUpdate
import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.model.HistoryWithRelations
import tachiyomi.domain.history.repository.HistoryRepository import tachiyomi.domain.history.repository.HistoryRepository
@ -28,6 +29,10 @@ class HistoryRepositoryImpl(
return handler.awaitOne { historyQueries.getReadDuration() } return handler.awaitOne { historyQueries.getReadDuration() }
} }
override suspend fun getHistoryByMangaId(mangaId: Long): List<History> {
return handler.awaitList { historyQueries.getHistoryByMangaId(mangaId, historyMapper) }
}
override suspend fun resetHistory(historyId: Long) { override suspend fun resetHistory(historyId: Long) {
try { try {
handler.await { historyQueries.resetHistoryById(historyId) } handler.await { historyQueries.resetHistoryById(historyId) }

View file

@ -1,6 +1,7 @@
package tachiyomi.domain.history.interactor package tachiyomi.domain.history.interactor
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import tachiyomi.domain.history.model.History
import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.model.HistoryWithRelations
import tachiyomi.domain.history.repository.HistoryRepository import tachiyomi.domain.history.repository.HistoryRepository
@ -8,6 +9,10 @@ class GetHistory(
private val repository: HistoryRepository, private val repository: HistoryRepository,
) { ) {
suspend fun await(mangaId: Long): List<History> {
return repository.getHistoryByMangaId(mangaId)
}
fun subscribe(query: String): Flow<List<HistoryWithRelations>> { fun subscribe(query: String): Flow<List<HistoryWithRelations>> {
return repository.getHistory(query) return repository.getHistory(query)
} }

View file

@ -1,6 +1,7 @@
package tachiyomi.domain.history.repository package tachiyomi.domain.history.repository
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import tachiyomi.domain.history.model.History
import tachiyomi.domain.history.model.HistoryUpdate import tachiyomi.domain.history.model.HistoryUpdate
import tachiyomi.domain.history.model.HistoryWithRelations import tachiyomi.domain.history.model.HistoryWithRelations
@ -12,6 +13,8 @@ interface HistoryRepository {
suspend fun getTotalReadDuration(): Long suspend fun getTotalReadDuration(): Long
suspend fun getHistoryByMangaId(mangaId: Long): List<History>
suspend fun resetHistory(historyId: Long) suspend fun resetHistory(historyId: Long)
suspend fun resetHistoryByMangaId(mangaId: Long) suspend fun resetHistoryByMangaId(mangaId: Long)