Add configurable library-update download modes (disabled, next X unread, all)
with settings UI and enqueue downloads after chapter sync completes.
Co-authored-by: Cursor <cursoragent@cursor.com>
Extract a single ETA estimator, refresh library badges when history changes,
and expose a history revision stream for reactive updates.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce ReadingEtaPreferences and ReadingEtaLimits so library badges, reader series ETA, cross-manga history mining, and page-rate estimation share one configuration. Add reader settings sliders (EN/DE strings). Register preferences in PreferenceModule and wire GetCrossMangaPageRateHistorySamples.
Co-authored-by: Cursor <cursoragent@cursor.com>
Gitea may emit null for empty release notes or assets; enable
Json.coerceInputValues and defaults so update checks do not fail
deserialization (unrelated to release-note workflow length).
Co-authored-by: Cursor <cursoragent@cursor.com>
- Cap per-chapter samples used for averages at 45m (stats only).
- Prefer session ms/page extrapolation for current chapter so cumulative
DB read time over revisits no longer blows up duration/progress.
- Floor uncertain page rates using conservative ms/page until enough samples.
- Shared defaults in ReadingEtaDefaults for reader + library badge.
Co-authored-by: Cursor <cursoragent@cursor.com>
Persist per-session pages read in history, include it in backup/restore, and prefer a page-based ETA model so chapter-length variance (especially webtoons) is reflected more accurately.
Co-authored-by: Cursor <cursoragent@cursor.com>
Point in-app release checks/changelog links to the Forgejo fork and generate release notes against upstream komikku-app baseline commits for clearer fork-specific change visibility.
Co-authored-by: Cursor <cursoragent@cursor.com>
Register GetReadDurationEntriesByMangaIds in DomainModule so LibraryScreenModel can resolve it and the app no longer crashes on startup.
Co-authored-by: Cursor <cursoragent@cursor.com>
* use remember getUiModel
* update headerIndexes to use remember for state management
* Refactor LibraryUpdateErrorScreen to improve state management
* Move header index calculation from the screen model to the presentation layer.
* Optimize UI model and header index memoization using `remember(state)`.
* Remove redundant `LaunchedEffect` and simplify scroll-to-index logic.
* Refactor LibraryUpdateErrorScreen to enhance state management with derivedStateOf
* fix(trackers-mangadex): Handle nullability in `createMdListTrack`
* Return null instead of throwing exception in initial track creation
* Improve error handling in `createMdListTrack`
* Change exception to return null when track not found
* handle nullability in MangaDex tracking
* feat: split "sync on add" into separate metadata and chapter fetch preferences
* refactor: remove redundant SnackbarHostState and error snackbars when auto sync entries
* clean other languages strings
* feat(migration): Allow skipping smart search for single entry migration
Introduces a "Smart search" setting when migrating a single manga, allowing users to choose between an automated best-match search or manual selection directly.
* ensure manual migration is only triggered once
* Add UI toggle
* refactor pref
* Replace deprecated rememberPlainTooltipPositionProvider
* Remove superfluous when branch
This when is marked as exhaustive.
* Replace deprecated LibrariesContainer call
AboutLibraries now wants us to produce the libraries ourselves.
* Replace deprecated ClipboardManager with Clipboard
Clipboard uses suspend functions, hence the coroutine scope addition.
* Use multi-dollar strs to simplify GraphQL queries
These have been available since Kotlin 2.1.
* Remove various redundant casts & conversions
- WebViewScreenContent: loadingState is in the LoadingState.Loading
branch, no need to cast at all
- Bangumi: username is not modified, make val
- Kavita: token is already a String
- PagerViewerAdapter: insertPageLastPage is already null-checked
- PagerViewerAdapter: use reified filterIsInstance
- ReaderViewModel: chapter IDs are already Longs
- CloudflareInterceptor: webview is smart-cast to non-null here
* Replace deprecated MenuAnchorType
Literally just a typealias for ExposedDropdownMenuAnchorType anyway.
* OptimizeNonSkippingGroups is enabled by default
* Suppress shadowing warning
This is explicitly intentional according to the KDocs.
* Migrate Context Receivers to Context Parameters
Requires changing the compiler arg, but that is part of the migration:
https://blog.jetbrains.com/kotlin/2025/04/update-on-context-parameters
Apparently, the only visible change is that names are required now.
"_" can be used for anonymous context parameters.
* Fix expression bodies with explicit return
Naming conflict resolved by aliasing.
From 2.4/2.5 onward, these will only be allowed with explicit return
types, or have to be turned into a block body. I opted for the latter
since the function is reasonably dense already.
see: https://youtrack.jetbrains.com/issue/KTLC-288
* Suppress deprecation of non-AutoMirrored icons
We use these arrows for navigation in the Upcoming screen.
I strongly doubt the AutoMirrored versions would make sense for our
use-case.
* Explicitly opt-in to new annotation default rules
affects the following annotated value-parameters:
- Preference.SliderPreference.steps (`@IntRange`)
- ReaderViewModel.State.brightnessOverlayValue (`@IntRange`)
- ReadingMode.iconRes (`@DrawableRes`)
- MigrationListScreenModel.Dialog.Progress.progress (`@FloatRange`)
see: https://youtrack.jetbrains.com/issue/KT-73255
see: https://github.com/Kotlin/KEEP/blob/change-defaulting-rule/proposals/annotation-target-in-properties.md
Warning message was the following:
This annotation is currently applied to the value parameter only, but in the future it will also be applied to field.
- To opt in to applying to both value parameter and field, add '-Xannotation-default-target=param-property' to your compiler arguments.
- To keep applying to the value parameter only, use the '@param:' annotation target.
(cherry picked from commit b543bc089a442c5e93b0fb6c83bc4037740b1eb5)
Allows users to search for the exact source ID in their library.
Similar to the Browse > Migrate screen, but filtered in the Library,
where users can take all the usual actions.
Could be used in the future to change the search behaviour of tapping
the source name in the title info view to search by the ID with this
prefix.
(cherry picked from commit 4e4bdffdf38043418685ab42b177c8476842c83c)
* fix: add support for `EnhancedTracker` to merged sources
* ref: readability
* fix: use only sources specific to the merged title
* fix: don't match using name
* formatting
* don't block, suspend
* Move merged source out of EnhancedTracker
* Extract Injekt
* Return first accepted merged manga
* Move getMergedSources to SourceManager and update usages accordingly
* simplify code
---------
Co-authored-by: Cuong-Tran <cuongtran.tm@gmail.com>
Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
* feat(history): Allow multi-selection and batch reset for history items
* Use chapterId instead of history.id
* use remember getUiModel
* Toolbar selection mode
* cleanup History
* Replace selectedChapterIds with selection for chapter selection state
* Remove userSelected parameter from selection logic and related function signatures
* remove parentheses
* Fix range selection
* longclick on cover too
* disable clear-history button when none-selected
* Add Filters to Updates screen
Behaves basically like the filters in the library:
- Unread: Show/Don't show unread chapters
- Downloaded: Show/Don't show downloaded chapters
- Started: Show/Don't show chapters that have some progress but aren't
fully Read
- Bookmarked: Show/Don't show chapters that have been bookmarked
Started behaves differently from its Library counterpart because the
actual manga data is not available at this point in time and I thought
calling getManga for each entry without caching would be a pretty bad
idea.
I have modelled this closely on the filter control flow in the
Library, but I'm sure this can be simplified/adjusted in some way.
* Move most filtering logic to SQL
Unread, Started, and Bookmarked filters are now part of the SQL query.
Download state cannot be filtered in the database so it remains in
Kotlin.
Because the Downloaded filter has to be run in Kotlin, the combine
flow uses the preferences flow twice, once to get the SQL query params
and once for the Kotlin filters (only Downloaded at this time).
* Add "Hide excluded scanlators" to update filters
Based on the work done in mihonapp/mihon#1623 but integrated with the other filters
in this PR. Added the user as a co-author for credit.
Co-authored-by: Dani <17619547+shabnix@users.noreply.github.com>
---------
Co-authored-by: Dani <17619547+shabnix@users.noreply.github.com>
---------
* Merge Panorama toggle into Filter diaglog
* Make Panorama toggle persistent and share it with History
* Implement toggleSwitch method for preference management to avoid create new function on every composition
Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
(cherry picked from commit bbe9aa8561360f030072fbc49f79748e71c6535e)
* Include romanized titles of the original language in description
* Implement handling for `finalChapterInDesc` preference.
* Handle `preferExtensionLangTitle` preference when fetching manga details.
* Address some warnings, clean up unused code and spotless apply.
(cherry picked from commit 582d0ef1219ae2a2e1dd275d969b35a2e5511a73)
Co-authored-by: Cuong-Tran <16017808+cuong-tran@users.noreply.github.com>
* Support mass migration in 'Browse -> Migrate' (mihonapp/mihon#2338)
(cherry picked from commit 22f851173b1eca242645f328a46e6038c035d5ec)
Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>