Commit Graph
8134 Commits
Author SHA1 Message Date
AntsyLich fc20410ceb Allow skipping an app update version
Closes #3969
Closes #3700
2026-10-11 15:38:14 +06:00
AntsyLich b454c1b469 Keep the migration screen up for at least a second 2026-10-11 15:11:07 +06:00
AntsyLich f02bf5ba7e Queue many chapters without probing each one on disk 2026-10-11 14:54:32 +06:00
AntsyLich ba16158b13 Show download progress and open the manga screen with less work 2026-10-11 13:43:35 +06:00
AntsyLich 8066b8dfc9 Read extension stores once at startup
Refreshing stores now fetches them all first and writes them in one transaction.
2026-10-11 13:43:34 +06:00
AntsyLich 260e31cd2c Improve performance across screens (#4071)
* Keep screens loaded while they're hidden and rebuild the library faster

* Count chapters in SQL for the migration list

* Show the extension list sooner and check trust against loaded stores

* Cancel the previous tracker search when searching again

* Write reader progress less often and keep its work off the main thread

* Stop rebuilding the settings search index on every key

* Watch updates for widgets only while one is placed

The query re-ran on every chapter or manga write even with no widget on
the home screen.

* Observe download pages and limit how often their progress updates

* Throttle the library update notification and write fetch data together
2026-10-11 04:28:52 +00:00
AntsyLich b15af71b94 Load installed extension and source icons through Coil 2026-10-11 05:04:59 +06:00
AntsyLich 3e5d593e28 Implement parallel page loading and preloading in reader (#2986) 2026-10-10 19:14:53 +00:00
MajorTanya c0c0909999 Fix Kitsu showing novels in search results (#4069) 2026-10-11 00:48:29 +06:00
AntsyLich c46317f099 Move blocking work off the main thread and fix threading races (#4068)
* Defer startup work until first use

* Move cover work off the main thread

* Make tracker calls main-safe and token refresh thread-safe

Kitsu, Shikimori and MangaBaka refresh their token under a lock like
MAL, so parallel calls no longer refresh it twice.

* Fix extension threading and make installs cancellable

The store service read response bodies on Main, which failed with
NetworkOnMainThreadException for http stores.

* Move reader work off the main thread and save progress in order

* Serialize the downloader and fix download threading

* Stop blocking on WorkManager status queries

Also removes NotificationReceiver's open chapter action: nothing sends
it, and its handler used runBlocking.

* Start migration jobs on the migrator's dispatcher

They started undispatched, so each ran on the caller's thread until its
first suspension.

* Run screen and view model work on fitting dispatchers

* Launch work that outlives a screen on the app scope

A launch on another dispatcher is dropped if the screen closes before it
starts, which dialogs that dismiss right away often do. Only the UI
follow-up stays on viewModelScope.

* Remove the coroutine helper extensions

They hid which dispatcher and scope a call used, and the GlobalScope
ones hid that it was global.
2026-10-10 17:08:49 +00:00
AntsyLich f9c5fa9011 Log app scope failures instead of crashing outside debug builds 2026-10-10 22:51:17 +06:00
AntsyLich a82d27c3a6 Keep the chapter selection when new chapters download after a refresh 2026-10-10 22:37:58 +06:00
AntsyLich 611578313e Index a finished download found on disk instead of downloading it again 2026-10-10 20:19:06 +06:00
AntsyLich f921ec07a6 Use an app scoped CoroutineScope
Replaces the eight ad hoc application lifetime scopes and the GlobalScope
launchUI/launchIO/launchNow helpers with a single injected
CoroutineScope(SupervisorJob() + Dispatchers.IO), qualified by
@AppCoroutineScope.

Every scope this replaces was already on IO, or named IO explicitly, so
call sites keep their dispatcher. The two that need the main thread use
scope.launchUI. Scopes with a real cancellation point keep their own:
HttpPageLoader, ShizukuInstaller and the reader viewers. Only
HttpPageLoader's page list cache save moves to the app scope, since it
runs after recycle() has cancelled the loader's own scope.

NotificationReceiver now holds the broadcast open with goAsync() while
its work runs, so the process isn't torn down mid update.

This reverts the revert of #3403. It was reverted for #3429, where
restore() dropped every download because SourceManager.get() returned
null until the extensions had loaded. That surface suspends since #3869,
so the race is gone.
2026-10-10 17:37:45 +06:00
AntsyLich e21414b229 Drop the legacy chapter model and narrow last page read to an Int
eu.kanade.tachiyomi.data.database.models.Chapter predates SQLDelight. It
survived because it implements SChapter, so ReaderChapter could hand the
same object to the database and to the source.

ReaderChapter now holds the domain Chapter and converts at the three
points that actually need a source model: getPageList, getFormat and
getChapterUrl. The domain model is immutable, so the reader replaces the
chapter rather than writing through it, behind an update function so the
field cannot be reassigned from outside. Equality stays on the chapter it
was loaded with, which keeps the identity comparisons in the viewers
stable while progress is recorded against it.

updateChapterProgress no longer mutates the chapter and reads the values
straight back out to build the update it persists; it computes them once
and passes them. Marking a chapter read moves out of the function named
for completing it and into the same place the page is recorded.

Removing the interface also drops the nullable id it carried, along with
three non-null assertions and a Float to Double conversion that the
compiler had been warning about.

A page position is an index into a chapter's pages, so it cannot exceed
Int range, but SQLite has one integer type and the column came back as a
Long. That width reached the domain model and then every caller either
carried it or converted, and the viewers had to narrow it again to index
a list with.

Declaring the column INTEGER AS Int moves the narrowing into a column
adapter, so it happens once where the value stops being a database
number. No migration: SQLite still stores an INTEGER, only the type
SQLDelight generates changes.

Backups are the exception and keep converting, because the field is on
the wire as int64 and has to stay that way. That is also the only place
the value arrives from outside the app, where a malformed file could
carry something that does not fit and truncate to a negative index, so
it is clamped rather than cast.
2026-10-10 17:37:44 +06:00
AntsyLich e42e01049d Recognize volumes and use neighbouring chapters for chapter numbers
Sync now recognizes the chapters of a manga together, which tells what a
name alone can't:
- Numbers every similar name shares, like the group in "Group 2 Chapter
  386", aren't the chapter number.
- Chapters without a number get one from the chapters around them, as long
  as none of them is in another volume, since numbers may start over in the
  next one. Between two chapters they get the missing whole numbers when
  those fit (2, ?, 4 -> 3), or .5, .6 and so on (10, ?, ?, 11 -> 10.5,
  10.6). Bonus chapters after the newest chapter go above it. A prologue
  gets 0, and volume 0 when the chapter after it has a volume.

Recognition returns a ChapterNumbering of the volume and chapter number as
strings, null when there is none. Sub-chapters keep their letter (19a) and
parts become one (Chapter 1.5 Part I -> 1.5a); sync turns the chapter
number into a double the way letters always counted. Volumes, seasons
included, are recognized from names and are no longer taken as the chapter
number. Sync only uses the chapter number for now.
2026-10-10 17:37:44 +06:00
AntsyLich 6c1b0702ba Use the beta Compose BOM
The alpha BOM's 2026.10.00 has the same Compose and Material 3 versions as the
beta one, but it keeps material3-adaptive on alpha. Tracker search now reads the
locale from composition, since Locale.current is deprecated.

Closes #4065
2026-10-10 17:37:44 +06:00
AntsyLich 292381662a Follow weekday and monthly release patterns for next update and back it up 2026-10-10 17:37:43 +06:00
AntsyLich 44c1e1915d Store every date in the database as an Instant 2026-10-10 17:37:43 +06:00
AntsyLich 8972882a34 Use plain icon buttons for extension actions 2026-10-10 17:37:43 +06:00
AntsyLichandJammo e9234f205d Match setting group headings in settings search (#4044)
Closes #4044
Fixes #3098

Co-authored-by: Jammo <8018115+kaosjammo@users.noreply.github.com>
2026-10-10 17:36:21 +06:00
Jammo adc9ee74ec Respect hidden missing chapter indicators in chapter headers (#4039)
Closes #4039
Fixes #2430
2026-10-10 17:36:20 +06:00
AntsyLichandAddictToTheKey be44a81fb6 Keep listing local chapters when one archive can't be read (#3997)
Closes #3997
Fixes #2548

Co-authored-by: AddictToTheKey <addicttothekey@local>
2026-10-10 17:36:20 +06:00
AntsyLichandChopper 88d4071cce Don't let the stored download index overwrite a startup rescan (#3968)
Closes #3968
Fixes #3526
Fixes #2808
Fixes #1429

Co-authored-by: Chopper <156493704+choppeh@users.noreply.github.com>
2026-10-10 17:36:20 +06:00
AntsyLichandJoseph f28b2d887e Cancel queued downloads of chapters the source removed (#3845)
Closes #3845
Fixes #3811
Fixes #3501

Co-authored-by: Joseph <50675784+JoJoKorok@users.noreply.github.com>
2026-10-10 17:36:20 +06:00
AntsyLichandAMendoza 287cbbb986 Keep the last update time on an empty Updates screen (#3790)
Closes #3790
Closes #4052
Fixes #3647

Co-authored-by: AMendoza <allanmaleman@gmail.com>
2026-10-10 17:36:20 +06:00
David d3f10772f2 Include the local source in global search (#3784)
Closes #3784
Fixes #3783
2026-10-10 17:36:19 +06:00
mliem2k 785f4fd1ed Keep downloads in excluded categories when marking them read (#3558)
Closes #3558
Closes #3130
Fixes #1521
2026-10-10 17:36:19 +06:00
AntsyLichandNarwhalHorns 40f552981a Don't match every library entry as a duplicate of a blank title (#3308)
Closes #3308

Co-authored-by: NarwhalHorns <onefailedgamer@gamil.com>
2026-10-10 17:36:19 +06:00
AntsyLichandNarwhalHorns 8c0419657b Always update library entries that were never initialized (#3179)
Closes #3179
Closes #3144

Co-authored-by: NarwhalHorns <onefailedgamer@gamil.com>
2026-10-10 17:36:19 +06:00
AntsyLichandLeodyver Semilla 36ec043a5c Delete downloads of duplicates read along with a chapter (#3030)
Closes #3030
Fixes #2454

Co-authored-by: Leodyver Semilla <leodyversemilla07@gmail.com>
2026-10-10 17:36:18 +06:00
AntsyLichandQuickdev 0c1be369b0 Ask to add an entry to the library before editing its cover (#2265)
Closes #2265

Co-authored-by: Quickdev <fyfrive@gmail.com>
2026-10-10 17:36:18 +06:00
Mend Renovate 157679bba5 Update spotless to v8.10.4 (#4063) 2026-10-10 07:23:12 +00:00
Mend Renovate 5b3505bf5f Update sqldelight to v2.4.1 (#4064) 2026-10-10 07:07:21 +00:00
Mend Renovate 2f5b9c1641 Update kotlin monorepo to v2.4.21 (#4061) 2026-10-10 07:06:15 +00:00
Mend Renovate 24bd3c95a5 Update Gradle to v9.8.1 (#4060) 2026-10-10 07:05:34 +00:00
Mend Renovate 7f2b4962b7 Update dependency com.google.firebase:firebase-bom to v35 (#4066) 2026-10-10 07:05:19 +00:00
Mend Renovate 8d39153569 Update androidx.paging to v3.5.2 (#4058) 2026-10-10 06:40:17 +00:00
Mend Renovate e998904fb6 Update GitHub Actions (#4059) 2026-10-10 06:38:43 +00:00
w d1e71ab58f Bump webgpuviewer (#4051) 2026-10-09 23:55:31 +06:00
AntsyLich a80027ff36 Update icons and move remaining to Material Symbols (#4057)
* Update Simple Icons to 16.34.0

The brand paths are unchanged; only the version in the headers moves.

* Use the current Material Symbols names

Several symbols were renamed after the Valkyrie migration. people_alt,
new_releases, screen_lock_*, screen_rotation and stay_current_* are only
aliases in the font now, for group, verified and the mobile_* symbols.
done, push_pin and expand_less/expand_more become check, keep and
keyboard_arrow_up/down, which draw the same or an almost identical glyph.

* Use filled icons where the Material Symbols migration dropped the fill

The migration mapped Filled and Default references to the outline symbols,
but the classic glyph was often solid, and Outlined Warning, Error and
Pause were solid as well. Each call site was compared against the rendered
classic glyph, and the solid ones now use RoundedFilled. view_list needs an
auto-mirrored filled pack. The outline SVGs this leaves unused are removed.

* Show a compact grid icon for the compact display modes

Compact and cover-only grids showed the same view_module icon as the
comfortable grid.

* Generate notification and layout drawables from Material Symbols

Notifications and XML layouts can't use ImageVectors, so they relied on
hand-kept copies of classic Material drawables. A build-logic task now
converts an opt-in list of the module's SVGs with AGP's Svg2Vector into
generated resources. sdk-common is taken from AGP's own dependency metadata,
so its version always matches AGP.

Compose call sites that only needed a drawable (tab close, crop) use the
ImageVectors instead. The icons module's R class must be imported as
MaterialSymbolsR, enforced by spotless, so it isn't mistaken for the app's R.

* Redraw custom icons in the Material Symbols style

The reading mode, crop off, mark previous as read and chapter download
icons were drawn in the classic style. They are rebuilt from Material
Symbols shapes (mobile_gear, mobile_arrow_right/down, crop,
arrow_circle_down, downloading) in a new custom-material-symbols module;
each SVG header lists where its parts come from. The default reading mode
and incognito use mobile_gear and eyeglasses_2 as they are.

ReadingMode holds an ImageVector now, and the module's R class follows the
same alias rule as MaterialSymbolsR.

* Use Material Symbols for the launcher shortcuts

Updates uses release_alert because the symbol named new_releases is now a
check badge.

* Rename the animated icon drawables

anim_*_enter no longer fits now that the icons play in both directions.
This is a pure rename so the following commits show only content changes.

* Use Material Symbols for the bottom navigation icons

The library, updates, history and browse animations are rebuilt from the
outline and filled symbols but keep their original motion: the white inside
is pushed into the ribbon, the "!" and the needle, and the history ring
still spins. Updates uses release_alert, like the shortcut. More already
matches more_horiz and is unchanged.

* Use rounded bars for the manga description caret

The animation is unchanged; the bars get rounded ends to match the
Material Symbols stroke.

* Settle the browse tab icon when selecting and deselecting

The compass turns a full turn and settles with overshoot both ways, instead
of deselecting by playing the select animation backwards. A
rememberAnimatedVectorPainter overload takes separate enter and exit
animations and doesn't animate on the first composition.
2026-10-09 17:50:12 +00:00
AntsyLich dd46413e10 List MangaBaka first among trackers 2026-10-09 19:16:42 +06:00
無字名3 ab7ee00c48 Fix tap navigation staying off after a cancelled button press (#3655)
Re-enable tap navigation after a cancelled button touch

A cancelled touch on a reader button (ACTION_CANCEL, e.g. the press turns
into a scroll) left tap navigation suppressed until the next press, so the
following tap did nothing.
2026-10-07 23:02:22 +06:00
AntsyLich fd4f73c908 Show a screen while the app migrates after an update 2026-10-07 22:22:32 +06:00
AntsyLich a6ee4bc596 Fix library range selection crash across categories 2026-10-07 19:59:52 +06:00
AntsyLich 6d4ed6cb22 Use the backport class loader for extensions before Android 17
ART maps app images compiled for the built-in DelegateLastClassLoader's class loader chain, and before Android 17 a damaged one crashes every launch until the app is updated.
2026-10-07 19:59:52 +06:00
AntsyLich 76b146f3d4 Show the updates widget's empty and locked text 2026-10-07 19:59:52 +06:00
AntsyLich 5910a51eb4 Keep the names of uninstalled sources across backup restores 2026-10-07 19:59:52 +06:00
AntsyLich 1e471a414c Stop updates showing a finished chapter as still downloading 2026-10-07 19:59:52 +06:00
AntsyLich 06d6128116 Let R8 shrink and optimize app code
Names stay as they are, since -dontobfuscate is unchanged. Injekt reads the injected type from the generic superclass of its type tokens, so those keep their Signature attribute.
2026-10-07 19:59:52 +06:00