Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental loading and filter system for local source #437

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/java/eu/kanade/domain/manga/model/Manga.kt
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fun SManga.toDomainManga(sourceId: Long): Manga {
updateStrategy = update_strategy,
initialized = initialized,
source = sourceId,
dirLastModifiedAt = dirLastModifiedAt
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class MangaRestorer(
coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded,
mangaId = manga.id,
dirLastModifiedAt = manga.dirLastModifiedAt,
updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode),
version = manga.version,
isSyncing = 1,
Expand Down Expand Up @@ -259,6 +260,7 @@ class MangaRestorer(
chapterFlags = manga.chapterFlags,
coverLastModified = manga.coverLastModified,
dateAdded = manga.dateAdded,
dirLastModifiedAt = manga.dirLastModifiedAt,
updateStrategy = manga.updateStrategy,
version = manga.version,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import eu.kanade.presentation.manga.components.SetIntervalDialog
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.Screen
import eu.kanade.presentation.util.isTabletUi
import eu.kanade.tachiyomi.source.CatalogueSource
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.isLocalOrStub
import eu.kanade.tachiyomi.source.online.HttpSource
Expand Down Expand Up @@ -371,7 +372,7 @@ class MangaScreen(
}

val previousController = navigator.items[navigator.size - 2]
if (previousController is BrowseSourceScreen && source is HttpSource) {
if (previousController is BrowseSourceScreen && source is CatalogueSource) {
navigator.pop()
previousController.searchGenre(genreName)
} else {
Expand Down
4 changes: 2 additions & 2 deletions config/detekt/baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -301,8 +301,8 @@
<ID>LongParameterList:MangaInfoHeader.kt$( favorite: Boolean, trackingCount: Int, nextUpdate: Instant?, isUserIntervalMode: Boolean, onAddToLibraryClicked: () -&gt; Unit, onWebViewClicked: (() -&gt; Unit)?, onWebViewLongClicked: (() -&gt; Unit)?, onTrackingClicked: () -&gt; Unit, onEditIntervalClicked: (() -&gt; Unit)?, onEditCategory: (() -&gt; Unit)?, modifier: Modifier = Modifier, )</ID>
<ID>LongParameterList:MangaInfoHeader.kt$( isTabletUi: Boolean, appBarPadding: Dp, title: String, author: String?, artist: String?, sourceName: String, isStubSource: Boolean, coverDataProvider: () -&gt; Manga, status: Long, onCoverClick: () -&gt; Unit, doSearch: (query: String, global: Boolean) -&gt; Unit, modifier: Modifier = Modifier, )</ID>
<ID>LongParameterList:MangaInfoHeader.kt$( title: String, doSearch: (query: String, global: Boolean) -&gt; Unit, author: String?, artist: String?, status: Long, sourceName: String, isStubSource: Boolean, textAlign: TextAlign? = LocalTextStyle.current.textAlign, )</ID>
<ID>LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List&lt;String&gt;?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, )</ID>
<ID>LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List&lt;String&gt;?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, totalCount: Long, readCount: Double, latestUpload: Long, chapterFetchedAt: Long, lastRead: Long, bookmarkCount: Double, category: Long, )</ID>
<ID>LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List&lt;String&gt;?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, dirLastModifiedAt: Long?, )</ID>
<ID>LongParameterList:MangaMapper.kt$MangaMapper$( id: Long, source: Long, url: String, artist: String?, author: String?, description: String?, genre: List&lt;String&gt;?, title: String, status: Long, thumbnailUrl: String?, favorite: Boolean, lastUpdate: Long?, nextUpdate: Long?, initialized: Boolean, viewerFlags: Long, chapterFlags: Long, coverLastModified: Long, dateAdded: Long, updateStrategy: UpdateStrategy, calculateInterval: Long, lastModifiedAt: Long, favoriteModifiedAt: Long?, dirLastModifiedAt: Long?, totalCount: Long, readCount: Double, latestUpload: Long, chapterFetchedAt: Long, lastRead: Long, bookmarkCount: Double, category: Long, )</ID>
<ID>LongParameterList:MangaRestorer.kt$MangaRestorer$( manga: Manga, chapters: List&lt;BackupChapter&gt;, categories: List&lt;Long&gt;, backupCategories: List&lt;BackupCategory&gt;, history: List&lt;BackupHistory&gt;, tracks: List&lt;BackupTracking&gt;, excludedScanlators: List&lt;String&gt;, )</ID>
<ID>LongParameterList:MangaScreen.kt$( manga: Manga, chapters: List&lt;ChapterList&gt;, isAnyChapterSelected: Boolean, chapterSwipeStartAction: LibraryPreferences.ChapterSwipeAction, chapterSwipeEndAction: LibraryPreferences.ChapterSwipeAction, onChapterClicked: (Chapter) -&gt; Unit, onDownloadChapter: ((List&lt;ChapterList.Item&gt;, ChapterDownloadAction) -&gt; Unit)?, onChapterSelected: (ChapterList.Item, Boolean, Boolean, Boolean) -&gt; Unit, onChapterSwipe: (ChapterList.Item, LibraryPreferences.ChapterSwipeAction) -&gt; Unit, )</ID>
<ID>LongParameterList:MangaScreen.kt$( selected: List&lt;ChapterList.Item&gt;, onMultiBookmarkClicked: (List&lt;Chapter&gt;, bookmarked: Boolean) -&gt; Unit, onMultiMarkAsReadClicked: (List&lt;Chapter&gt;, markAsRead: Boolean) -&gt; Unit, onMarkPreviousAsReadClicked: (Chapter) -&gt; Unit, onDownloadChapter: ((List&lt;ChapterList.Item&gt;, ChapterDownloadAction) -&gt; Unit)?, onMultiDeleteClicked: (List&lt;Chapter&gt;) -&gt; Unit, fillFraction: Float, modifier: Modifier = Modifier, )</ID>
Expand Down
4 changes: 4 additions & 0 deletions data/src/main/java/tachiyomi/data/manga/MangaMapper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ object MangaMapper {
version: Long,
@Suppress("UNUSED_PARAMETER")
isSyncing: Long,
dirLastModifiedAt: Long?,
): Manga = Manga(
id = id,
source = source,
Expand All @@ -56,6 +57,7 @@ object MangaMapper {
lastModifiedAt = lastModifiedAt,
favoriteModifiedAt = favoriteModifiedAt,
version = version,
dirLastModifiedAt = dirLastModifiedAt,
)

@Suppress("LongParameterList")
Expand Down Expand Up @@ -84,6 +86,7 @@ object MangaMapper {
favoriteModifiedAt: Long?,
version: Long,
isSyncing: Long,
dirLastModifiedAt: Long?,
totalCount: Long,
readCount: Double,
latestUpload: Long,
Expand Down Expand Up @@ -117,6 +120,7 @@ object MangaMapper {
favoriteModifiedAt,
version,
isSyncing,
dirLastModifiedAt,
),
category = category,
totalChapters = totalCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class MangaRepositoryImpl(
dateAdded = manga.dateAdded,
updateStrategy = manga.updateStrategy,
version = manga.version,
dirLastModifiedAt = manga.dirLastModifiedAt,
)
mangasQueries.selectLastInsertedRowId()
}
Expand Down Expand Up @@ -161,6 +162,7 @@ class MangaRepositoryImpl(
coverLastModified = value.coverLastModified,
dateAdded = value.dateAdded,
mangaId = value.id,
dirLastModifiedAt = value.dirLastModifiedAt,
updateStrategy = value.updateStrategy?.let(UpdateStrategyColumnAdapter::encode),
version = value.version,
isSyncing = 0,
Expand Down
10 changes: 6 additions & 4 deletions data/src/main/sqldelight/tachiyomi/data/mangas.sq
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ CREATE TABLE mangas(
last_modified_at INTEGER NOT NULL DEFAULT 0,
favorite_modified_at INTEGER,
version INTEGER NOT NULL DEFAULT 0,
is_syncing INTEGER NOT NULL DEFAULT 0
is_syncing INTEGER NOT NULL DEFAULT 0,
dir_last_modified_at INTEGER
);

CREATE INDEX library_favorite_index ON mangas(favorite) WHERE favorite = 1;
Expand Down Expand Up @@ -141,8 +142,8 @@ WHERE favorite = 0
AND source IN :sourceIds;

insert:
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at, version)
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0, :version);
INSERT INTO mangas(source, url, artist, author, description, genre, title, status, thumbnail_url, favorite, last_update, next_update, initialized, viewer, chapter_flags, cover_last_modified, date_added, update_strategy, calculate_interval, last_modified_at, version, dir_last_modified_at)
VALUES (:source, :url, :artist, :author, :description, :genre, :title, :status, :thumbnailUrl, :favorite, :lastUpdate, :nextUpdate, :initialized, :viewerFlags, :chapterFlags, :coverLastModified, :dateAdded, :updateStrategy, :calculateInterval, 0, :version, :dirLastModifiedAt);

update:
UPDATE mangas SET
Expand All @@ -166,7 +167,8 @@ UPDATE mangas SET
update_strategy = coalesce(:updateStrategy, update_strategy),
calculate_interval = coalesce(:calculateInterval, calculate_interval),
version = coalesce(:version, version),
is_syncing = coalesce(:isSyncing, is_syncing)
is_syncing = coalesce(:isSyncing, is_syncing),
dir_last_modified_at = coalesce(:dirLastModifiedAt, dir_last_modified_at)
WHERE _id = :mangaId;

selectLastInsertedRowId:
Expand Down
1 change: 1 addition & 0 deletions data/src/main/sqldelight/tachiyomi/migrations/4.sqm
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE mangas ADD COLUMN dir_last_modified_at INTEGER;
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
package tachiyomi.domain.manga.interactor

import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaUpdate
import tachiyomi.domain.manga.model.toMangaUpdate
import tachiyomi.domain.manga.repository.MangaRepository

class NetworkToLocalManga(
private val mangaRepository: MangaRepository,
) {

suspend fun await(manga: Manga): Manga {
val localManga = getManga(manga.url, manga.source)
val localDbManga = getManga(manga.url, manga.source)

if (localDbManga != null && localDbManga.dirLastModifiedAt != manga.dirLastModifiedAt) {
updateManga(
localDbManga.copy(
url = manga.url,
title = manga.title,
artist = manga.artist,
author = manga.author,
description = manga.description,
genre = manga.genre,
status = manga.status,
thumbnailUrl = manga.thumbnailUrl,
dirLastModifiedAt = manga.dirLastModifiedAt,
).toMangaUpdate(),
)
}

return when {
localManga == null -> {
localDbManga == null -> {
val id = insertManga(manga)
manga.copy(id = id!!)
}
!localManga.favorite -> {
!localDbManga.favorite -> {
// if the manga isn't a favorite, set its display title from source
// if it later becomes a favorite, updated title will go to db
localManga.copy(title = manga.title)
localDbManga.copy(title = manga.title)
}
else -> {
localManga
localDbManga
}
}
}
Expand All @@ -32,4 +51,8 @@ class NetworkToLocalManga(
private suspend fun insertManga(manga: Manga): Long? {
return mangaRepository.insert(manga)
}

private suspend fun updateManga(mangaUpdate: MangaUpdate) {
mangaRepository.update(mangaUpdate)
}
}
2 changes: 2 additions & 0 deletions domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ data class Manga(
val updateStrategy: UpdateStrategy,
val initialized: Boolean,
val lastModifiedAt: Long,
val dirLastModifiedAt: Long?,
val favoriteModifiedAt: Long?,
val version: Long,
) : Serializable {
Expand Down Expand Up @@ -122,6 +123,7 @@ data class Manga(
updateStrategy = UpdateStrategy.ALWAYS_UPDATE,
initialized = false,
lastModifiedAt = 0L,
dirLastModifiedAt = null,
favoriteModifiedAt = null,
version = 0L,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ data class MangaUpdate(
val status: Long? = null,
val thumbnailUrl: String? = null,
val updateStrategy: UpdateStrategy? = null,
val dirLastModifiedAt: Long? = null,
val initialized: Boolean? = null,
val version: Long? = null,
)
Expand All @@ -47,6 +48,7 @@ fun Manga.toMangaUpdate(): MangaUpdate {
status = status,
thumbnailUrl = thumbnailUrl,
updateStrategy = updateStrategy,
dirLastModifiedAt = dirLastModifiedAt,
initialized = initialized,
version = version,
)
Expand Down
6 changes: 6 additions & 0 deletions i18n/src/commonMain/resources/MR/base/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,9 @@
<string name="chapter_not_found">Chapter not found</string>
<string name="local_invalid_format">Invalid chapter format</string>
<string name="local_filter_order_by">Order by</string>
<string name="local_filter_random_page">Load random manga page (ignores all filters)</string>
<string name="local_filter_text_search_header">Values separated by ,\nuse - before a value to filter it out</string>
<string name="local_filter_info_header">⚠️ Please use "Reset" to update your filters\n\nⓘ Filtering only works for manga that have already loaded\n\nⓘ "Order by" will only become available once all your manga have loaded</string>
<string name="date">Date</string>

<!-- Manga info -->
Expand Down Expand Up @@ -732,6 +735,9 @@
<string name="score">Score</string>
<string name="title">Title</string>
<string name="status">Status</string>
<string name="genres">Genres</string>
<string name="authors">Authors</string>
<string name="artists">Artists</string>
<string name="track_status">Status</string>
<string name="track_started_reading_date">Start date</string>
<string name="track_finished_reading_date">Finish date</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ interface SManga : Serializable {

var thumbnail_url: String?

var dirLastModifiedAt: Long?

var update_strategy: UpdateStrategy

var initialized: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class SMangaImpl : SManga {

override var thumbnail_url: String? = null

override var dirLastModifiedAt: Long? = null

override var update_strategy: UpdateStrategy = UpdateStrategy.ALWAYS_UPDATE

override var initialized: Boolean = false
Expand Down
Loading