Commit graph

121 commits

Author SHA1 Message Date
Schnitzel5
afb7cf1c9d optimized performance 2026-08-15 17:56:49 +02:00
Moustapha Kodjo Amadou
165c5fc2d6
Merge pull request #860 from mrandhawa14/fix/tv-and-display-scaling
fix: make the TV layout testable and stop the scaled UI clipping on desktop
2026-08-14 14:00:36 +01:00
Mehakdeep Singh
dc2c5ba783 fix: surface swallowed failures and stop hardcoding neutrals
Four silent catches on network paths now log instead of discarding the
error. Each had a user visible consequence and no way to diagnose it:
a failed source filter drops sources from the list, a failed epub parse
shows the not-found placeholder, a failed index_v2 redirect makes a repo
look empty, and a failed repo fetch shows no sources at all. They go to
AppLogger, which is off unless the user enables logs, so nothing changes
by default and the failure is recoverable from a bug report.

The other empty catches are left alone deliberately: teardown paths like
stopServer and disposing a headless webview, and formatting fallbacks
that already have a sane default.

Eleven hardcoded neutrals become theme colours. The palette is chosen at
runtime, so a fixed grey is wrong on some schemes: the read chapter dim
in updates, the tab bar dividers, the empty category state, the disabled
webview arrows, and the about divider.

Greys that are meant to be literal are untouched: the reader background
named "grey", the novel colour picker swatches, player chrome sitting on
video, and the icon on the sync tile's fixed dark box.
2026-08-14 03:09:08 -07:00
Mehakdeep Singh
b8f1e91985 fix: keep the scaled UI pinned to the window on desktop
Raising the interface scale on desktop left the right and bottom edges
of the window blank. AppUiScale measured MediaQuery.size, which can
differ from the constraints it is actually given there, and its FittedBox
sat under loose constraints, so it shrank to the smaller design child and
kept it in the top left instead of covering the window.

Measure the real box with a LayoutBuilder and pin the FittedBox to it
with an explicit SizedBox, so the scaled subtree always fills the window.
Safe area insets are still converted into design space, so padding stays
correct.

Validated on desktop.
2026-08-14 02:54:46 -07:00
Mehakdeep Singh
ad57e7013a feat: show a cover grid skeleton while a source page loads
Fetching a source page is the app's longest routine wait and it showed a
centred spinner, which says nothing about what is coming and reads as a
stall.

CoverGridSkeleton lays out the shape the covers will land in. It renders
through the real GridViewWidget with the same gridSize and aspect ratio,
so the delegate, spacing, padding and TV insets cannot drift from the
loaded grid and nothing shifts when the data arrives.

The tint is the theme foreground at low alpha rather than a fixed grey,
since the palette is chosen at runtime. The pulse rebuilds a dozen plain
boxes instead of wrapping the grid in an Opacity, which would force a
save layer every frame, and it holds a flat tint when the platform asks
for reduced motion.

List display keeps the spinner: it has no fixed cell shape to stand in
for.
2026-08-14 02:54:34 -07:00
Mehakdeep Singh
b0896f2cf8 refactor: use the shared error state across screens
Nine screens rendered a bare Center(child: Text(error.toString())), so a
failure showed the user a stack trace with nothing to do about it, and
looked different in every place it appeared. They now use ErrorState,
each wired to a retry that re-runs the work that failed: invalidate the
provider for the AsyncValue screens, reset the flags and call the init
again for the ones holding _errorMessage in state.

retry was already translated into fifteen languages but only reachable
from reader image retries and the download queue. It is now offered
wherever a screen fails.

manga_home_screen keeps its own layout: it already has source specific
recovery (refresh through the right provider, and a webview for
Cloudflare), so only the raw cause is demoted to match.

ErrorState gains autofocusRetry because the anime player deliberately
autofocuses its back button for TV, and two widgets asking for autofocus
in one scope resolve arbitrarily.
2026-08-14 02:54:34 -07:00
Mehakdeep Singh
9ed8607e49 fix: show a real error state when startup fails
The root shell rendered LoadingIcon for both the loading and the error
branch of migrationProvider, so a failed migration left the app on a
blank splash forever with no message, no cause and nothing to act on.

Add a shared ErrorState widget (readable line, the technical cause kept
but demoted, optional retry) and use it for the error branch, wired to
re-run the migration. Screens currently hand-roll
Center(child: Text(error.toString())) in ten places; those move over
separately.

LoadingIcon also hardcoded a white background with a black icon, which
meant a full screen white flash on every cold start under a dark theme.
Both colours now come from the active scheme.
2026-08-14 01:30:56 -07:00
Moustapha Kodjo Amadou
22f2a70e75 chore: update dependencies and SDK version
Some checks are pending
CI / Analyze (push) Waiting to run
CI / Build (Android debug) (push) Waiting to run
CI / Build (Linux debug) (push) Waiting to run
- Updated Dart SDK version to ^3.13.0 in pubspec.yaml
- Updated various package versions in pubspec.lock
- Changed macOS platform version from 10.15 to 12.0 in Podfile and project.pbxproj
- Added cupertino_ui dependency
- Refactored code for better readability by removing unnecessary line breaks
2026-08-13 09:44:05 +01:00
Moustapha Kodjo Amadou
a79b7997d8 feat: add ExtensionServerWarningBanner to various screens and implement server installation check 2026-08-11 10:26:29 +01:00
Mehakdeep Singh
dc89fcfbdf feat: make the UI scale universal, not TV-only (#589)
The interface-scale option was gated to TV. Generalize it to every platform:
TV keeps the fixed-reference-width normalization (for density consistency),
while desktop/tablet/phone get a straight multiplier on the native size (1.0 is
native, higher zooms in). Renamed TvUiScale -> AppUiScale and the setting /
slider accordingly, and the slider now shows in Appearance on all platforms.
Addresses #589 (scale the app UI while navigating, especially on big screens).
2026-07-26 00:17:11 -07:00
Mehakdeep Singh
93b788a462 Merge remote-tracking branch 'fork/fix/tv-source-search-focus' into feat/tv-ui-combined 2026-07-25 18:34:22 -07:00
Mehakdeep Singh
4acbe7ce0a fix(android-tv): ignore a stray Select key-up on TV pills
A TvPill fired its onTap on any Select KeyUp, even one whose KeyDown landed on a
different control. Activating something that removes itself (the source page's
search button) reverts focus to the previously focused pill, and the trailing
KeyUp then re-selected it. Only act on a KeyUp that has its matching KeyDown on
the same pill, matching the cover-card guard.
2026-07-25 18:14:29 -07:00
Mehakdeep Singh
9bea3398a3 feat(android-tv): adaptable UI scale
TVs report display density wildly inconsistently, so the fixed-dp layout is
comfortable on one box and zoomed-in on another. Normalize the whole TV UI to a
fixed 1280 logical reference width (== Android density 240 on a 1080p panel) and
scale it uniformly to fill the real panel, so it looks the same on every TV
regardless of reported density. Add a 'TV interface scale' slider (85 to 125
percent, persisted on the Isar Settings collection) so users can fine-tune for
their screen and viewing distance. No-op off TV.
2026-07-25 13:43:01 -07:00
Moustapha Kodjo Amadou
dd7b7b9bcc refactor: improve code formatting and readability across multiple files 2026-07-24 15:10:18 +01:00
Mehakdeep Singh
fe2b2295d1 fix(android-tv): player settings check mark + focus, slider focus cue
- TV player settings: the quality/subtitle/audio pages were built once and never
  rebuilt, so after switching a track the check mark stayed on the old option.
  Wrap them in a StreamBuilder on player.stream.track so the list recomputes from
  live player state. Also autofocus the first row of every drilled-in page so a
  row is highlighted immediately instead of focus landing nowhere.
- TvEscapableSlider draws an accent tint and ring while focused, since the inner
  Slider (excluded from focus) gave no cue of which slider the d-pad was on.
2026-07-23 14:09:24 -07:00
Mehakdeep Singh
560b56ab76 fix(android-tv): statistics/calendar, back-button re-open, tracker button, migrate focus, DoH sliders
- Statistics and Calendar: on the anime-only TV layout, force the anime tab
  instead of intersecting with hiddenItemTypes. When the Anime library was
  hidden from that list the intersection was empty, blanking Statistics (it hit
  a leftover debug placeholder, now a proper empty state) and leaving Calendar
  with a null item type and no data.
- Covers: ignore a Select KeyUp that has no matching KeyDown on the same card.
  A detail screen's Back button pops on KeyDown and the trailing KeyUp landed on
  whatever cover regained focus, immediately re-opening the detail just closed.
- TV anime detail: only reclaim focus when it is the current route. It watches a
  live chapters stream and rebuilt while Migrate/Mass migration/Recommendations/
  Tracking sat on top, stealing focus back to Continue so those screens never
  held focus and OK played a random episode.
- TV anime detail: add a Tracking action opening the same tracker sheet as the
  classic detail (extracted into a shared openTrackingMenu), or routing to the
  tracking settings when no tracker is logged in.
- Migrate: claim the initial TV focus from the first source that returns results
  rather than always source #0, which could be empty.
- General settings: wrap the four recommendation-weight sliders in
  TvEscapableSlider so the d-pad can leave them.
2026-07-23 13:14:21 -07:00
Mehakdeep Singh
9feecd8e82 feat(android-tv): TV UI — shared widgets, detail, focus model, centred menus
Builds on the merged TV base (#799): adds the pieces that did not land there.

- Shared TV widgets: TvPill, TvRowButton/TvListRow (band + fade focus),
  TvMenu (centred d-pad menus replacing anchored dropdowns).
- Dedicated d-pad anime detail (hero + vertical action list).
- Nav rail branded with the app glyph, sized/spaced/animated for a TV.
- Browse/Updates/History/Source: home-style pills, focusable rows with the lit
  band, accent focus tint on top-bar icons.
- Global-search + library covers d-pad reachable and scale on focus.
- Centred menus for the source, download queue, detail and library overflows,
  and the source filter sheet.
- Settings + menu rows get the accent band; app-wide TV focus tint.
- Error/empty pushed screens autofocus a back button; held-OK long-press so
  multi-select is reachable with a remote.

TV-only (isTv); phones and desktop unchanged.
2026-07-22 19:21:46 -07:00
Moustapha Kodjo Amadou
b6d2f4cc8b
Merge branch 'main' into feat/android-tv 2026-07-22 10:25:20 +01:00
Moustapha Kodjo Amadou
57880a9f96 Revert "fix"
This reverts commit bb764c4303.
2026-07-22 10:00:58 +01:00
Moustapha Kodjo Amadou
bb764c4303 fix 2026-07-22 09:58:20 +01:00
Moustapha Kodjo Amadou
448ae6e826 refactor: optimize state rebuilds and improve cover image overlay UI components 2026-07-17 16:18:21 +01:00
Mehakdeep Singh
ec7ab692b4 fix(android-tv): clear the analyzer deprecations and warnings
Matrix4.scale is deprecated in favour of the explicit per-axis form. For a
double it just forwards to scaleByDouble(x, y ?? x, z ?? x, 1.0), so calling
scaleByDouble directly is the same transform. Hoist the factor into a local so
the ternary is not repeated once per axis.

Also drop the dead optional focusNode on _TvSeekBar: no call site ever passed
it, and its getter already falls back to a node of its own.

Leaves the branch with no analyzer warnings, and no deprecations beyond the
WillPopScope in webview.dart that main carries already.
2026-07-16 15:52:15 -07:00
Mehakdeep Singh
db8b56a048 style(android-tv): remove brand references and em dashes from TV code
Reword the TV comments to describe behaviour without naming Netflix or YouTube,
and replace em dashes with hyphens (including two decoder labels). No logic
change; comments and label text only.
2026-07-16 04:26:24 -07:00
Mehakdeep Singh
8b6a2e636e feat(android-tv): d-pad TV shell — home, library grid, nav, anime-only gates (#729)
Rows-based TV home (hero + Continue/New/Recently Added/category rows), d-pad
library grid + focus ring, tab-rail focus, anime-only layout across
Library/Browse/History/Updates/Categories, escapable settings sliders, and no
autofocus on dialog text fields for the on-screen keyboard.
2026-07-16 04:26:24 -07:00
Mehakdeep Singh
34caae8591 feat(android-tv): form-factor detection (isTv) + TV mode providers (#729)
Detect Android TV / leanback natively (MainActivity method channel) and expose
it as isTv; init at startup. Add the anime-only / TV-home / TV-player style
providers with an explicit user override so a wrong detection is never a trap.
2026-07-16 04:26:23 -07:00
Moustapha Kodjo Amadou
da67933942 Update SDK constraints to support Dart 3.12.0 and refactor 2026-06-07 18:09:24 +01:00
NBA2K1
10b1ec226a Replace Container with Material to fix warning 2026-06-03 18:26:32 +02:00
Mehakdeep Singh
e16f0ba9be Merge remote-tracking branch 'upstream/main' into fix/cover-decode-resize
# Conflicts:
#	lib/modules/library/widgets/library_gridview_widget.dart
#	lib/modules/library/widgets/library_listview_widget.dart
2026-05-11 00:56:00 -07:00
Mehakdeep Singh
861ee65113 perf(library): decode covers at thumbnail resolution to cut image-cache RAM
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
2026-05-09 23:37:44 -07:00
NBA2K1
0672d1de67 Reduce Code Duplication 2026-05-07 19:14:50 +02:00
NBA2K1
07470c08c7 Add Copilot suggested change (3/3)
https://github.com/kodjodevf/mangayomi/pull/705#discussion_r3112086148
2026-04-20 18:47:05 +02:00
NBA2K1
233ffa1b2c Update manga_image_card_widget.dart 2026-04-19 04:57:36 +02:00
Whiskas101
232ae8ea86 change: switch to async fetch for isar due to lag in large libraries 2026-04-19 02:19:41 +02:00
NBA2K1
525eeea3ac Use shared library index for manga cards
Replace per-widget Isar StreamBuilder usage with a single shared
library index managed in MangaHomeScreen.

- Subscribe once to manga updates and build a name -> Manga map
- Pass libraryManga down to card widgets instead of querying per item
- Remove StreamBuilder logic from MangaImageCardWidget and list tile
- Use library data for cover, tracker image, and favorite state
- Add favorite overlay indicator based on libraryManga
- Clean up redundant filtering and improve performance

This reduces rebuild overhead and avoids multiple database listeners
per list/grid item.
2026-04-19 01:48:39 +02:00
NBA2K1
d8ff9fb01d performance+
Change Clip.antiAliasWithSaveLayer to Clip.antiAlias
2026-04-12 23:03:07 +02:00
NBA2K1
9efd76581f Group related functions using an extension
- new file item_type_filters.dart for the hiddenItemTypes function.
- reduces code duplication in statistics_screen, categories_screen and base_library_tab_screen
2025-12-29 23:19:31 +01:00
NBA2K1
42f1dcff92 Reduce Code Duplication
- Extract localizedItemType() from `base_library_tab_screen.dart`
- Add localizedSources() and localizedExtensions() for browse_screen.dart
- Reduce if-statements in statistics_screen.dart
- Reduce if-statements in categories_screen.dart
- Reduce if-statements in browse_screen.dart
2025-12-29 04:59:06 +01:00
NBA2K1
86fb19ecb2 Refactor tabbed screens into base class
Reduce duplication
2025-12-29 03:28:04 +01:00
NBA2K1
0f83899bac remove unnecessary calls
.trimLeft().trimRight() after trim() is unnecessary.
2025-12-17 21:34:45 +01:00
NBA2K1
0ed8ee2cd2 Move cacheDir creation to storage_provider
- Move the cacheDir creation to storage_provider from `others.dart`, `custom_extended_image_provider.dart` and `storage_usage.dart`.

- Use the correct directory, `getApplicationCacheDirectory()` instead of the `getTemporaryDirectory()` (which is being deleted by the OS regularly) for cache files.

- remove the `_cacheDownloadPath` from `storage_usage.dart` as the path is never being created in the first place, so using that path in `clearCache()` and `_getTotalDiskSpace()` is unnecessary.
2025-12-17 20:55:41 +01:00
Moustapha Kodjo Amadou
b8fffca2b3 Refactor an fix 2025-11-09 01:15:27 +01:00
NBA2K1
1b64f2650e Merge remote-tracking branch 'upstream/main' into Correct-directory 2025-11-08 14:59:23 +01:00
Moustapha Kodjo Amadou
1569c1bcd1 Implement LRU caching for image data and optimize network requests with exponential backoff retry logic 2025-11-07 14:34:09 +01:00
NBA2K1
a307e9d049 Merge remote-tracking branch 'upstream/main' into Correct-directory 2025-10-29 18:30:50 +01:00
Moustapha Kodjo Amadou
430e81e021 Refactor and update dependencies for Isar and Riverpod 2025-10-29 13:08:42 +01:00
NBA2K1
462e9b5fe7 Merge remote-tracking branch 'upstream/main' into Correct-directory 2025-10-09 19:13:22 +02:00
Schnitzel5
05d0ddf0d6 reworked local source
- allow multiple local folders
- added support for scanning .epub novels
- added metadata,json support
- scanned entries now appear in browse screen instead of the default library category (can be added to library)
2025-09-04 23:02:27 +02:00
NBA2K1
e6b6fd6a92 Merge remote-tracking branch 'upstream/main' into Correct-directory 2025-08-30 00:33:31 +02:00
Moustapha Kodjo Amadou
e7b55b4eca fix 2025-08-28 12:43:16 +01:00
Moustapha Kodjo Amadou
7e74fba9bc fix 2025-08-28 12:25:46 +01:00