Refs #609 (high RAM with stutters).
Manga / anime covers from sources are typically 720x1080 or larger
(~3 MB decoded RGBA per cover). The library grid, library list and
generic browse / search card widgets render those covers at roughly
150x220 logical pixels, but every cover decoded to its full source
resolution and that decoded bitmap landed in Flutter's `imageCache`.
With 30-50 covers in flight during a normal scroll, the default
100 MB cache filled and the engine started evicting + re-decoding
aggressively — exactly the symptom in #609 (stutters + high RAM).
Mangayomi already had `ExtendedResizeImage` available via the
`extended_image_library` package and used it in one place
(`cachedCompressedNetworkImage`, called only from the History
screen). This commit generalises that pattern.
Add a `coverProvider()` helper in `lib/utils/cached_network.dart`
that wraps `CustomExtendedNetworkImageProvider` in
`ExtendedResizeImage` with a 200 KB encoded budget — sharp at
typical thumbnail size on high-DPR screens, ~3.6x smaller decoded
than a full-resolution cover. Pass through the same `cache` /
`cacheMaxAge` knobs the underlying provider exposes so existing
disk-cache behaviour is preserved.
Swap the three high-traffic thumbnail call sites to use it:
* `lib/modules/library/widgets/library_gridview_widget.dart`
* `lib/modules/library/widgets/library_listview_widget.dart`
* `lib/modules/widgets/manga_image_card_widget.dart`
(both `MangaImageCardWidget` and `MangaImageCardListTileWidget`,
used by browse and search results)
Deliberately not changed:
* The manga / anime detail page hero cover — large display, full
resolution is appropriate.
* Reader pages — already memory-managed by `ChapterPreloadManager`
and need full resolution for actual reading.
* `cachedNetworkImage()` and other lower-traffic thumbnail surfaces
(tracker results, calendar, recommendation grid). Easy to extend
in a follow-up if anyone asks; kept narrow here so review is
manageable.
Verified
* `flutter analyze` clean on every touched file
* `flutter build macos --release` succeeds
* Smoke-tested on macOS with the local-all-fixes build: library
grid, library list and browse card all render identical-looking
covers at typical thumbnail sizes; no visible quality regression
at the displayed scale
Remove synchronous Isar queries from each library grid item when
downloadedChapter is enabled.
- Replace per-card download queries with downloadedChapterIdsProvider
- Compute downloadCount via in-memory lookup instead of DB calls
- Eliminate repeated sync queries on rebuilds and tab switches
- Minor cleanup of unread chapter filter
This avoids dozens of synchronous queries per frame and significantly
improves grid performance and responsiveness.
Refactor history lookup to use a direct mangaIdEqualTo query instead of the previous multi‑level chapter/manga filter.
The new approach improves performance, readability, and maintainability without changing how the play button behaves or how history entries are resolved.
Change per‑chapter synchronous lookups inside isar.txnSync to a single batched anyOf query using collected chapter IDs.
Reduces repeated filtering, removes unnecessary loop, and improves performance.
MangasListState previously stored selected manga IDs as List<int>.
Every visible library card called .contains() on that list once per
rebuild to determine its highlight state, making each check O(n) in
the number of selected items. The provider's own update/selectAll/
selectSome methods also used .contains() and .remove() on a List.
Change the state type to Set<int> throughout, making all membership
checks O(1). Updated all consumers: library_gridview_widget,
library_listview_widget, library_app_bar, library_dialogs, and
MangasSetIsReadState.
Merge `isLongPressedMangaStateProvider` and `isLongPressedStateProvider`
Both providers do the same thing and it is impossible to change the value of the provider in different places in the app at the same time.
So just use one `isLongPressedStateProvider`. Reduces code duplication and there is no confusion about which one to use.