added downloaded only mode

This commit is contained in:
Schnitzel5 2025-08-15 21:33:54 +02:00
parent 22087752f1
commit 56fc7f905a
10 changed files with 161 additions and 3 deletions

View file

@ -77,6 +77,8 @@
"clean_database_desc": "This will remove all items that are not added to the library!",
"incognito_mode": "Incognito Mode",
"incognito_mode_description": "Pauses reading history",
"downloaded_only": "Downloaded only",
"downloaded_only_description": "Only show downloaded entries in your library",
"download_queue": "Download Queue",
"categories": "Categories",
"statistics": "Statistics",

View file

@ -258,6 +258,8 @@ class Settings {
bool? rpcShowCoverImage;
bool? downloadedOnlyMode;
Settings({
this.id = 227,
this.updatedAt = 0,
@ -373,6 +375,7 @@ class Settings {
this.rpcShowReadingWatchingProgress = true,
this.rpcShowTitle = true,
this.rpcShowCoverImage = true,
this.downloadedOnlyMode = false,
});
Settings.fromJson(Map<String, dynamic> json) {
@ -594,6 +597,7 @@ class Settings {
rpcShowReadingWatchingProgress = json['rpcShowReadingWatchingProgress'];
rpcShowTitle = json['rpcShowTitle'];
rpcShowCoverImage = json['rpcShowCoverImage'];
downloadedOnlyMode = json['downloadedOnlyMode'];
}
Map<String, dynamic> toJson() => {
@ -732,6 +736,7 @@ class Settings {
'rpcShowReadingWatchingProgress': rpcShowReadingWatchingProgress,
'rpcShowTitle': rpcShowTitle,
'rpcShowCoverImage': rpcShowCoverImage,
'downloadedOnlyMode': downloadedOnlyMode,
};
}

View file

@ -20,6 +20,7 @@ import 'package:mangayomi/modules/library/providers/add_torrent.dart';
import 'package:mangayomi/modules/library/providers/local_archive.dart';
import 'package:mangayomi/modules/manga/detail/providers/update_manga_detail_providers.dart';
import 'package:mangayomi/modules/more/categories/providers/isar_providers.dart';
import 'package:mangayomi/modules/more/providers/downloaded_only_state_provider.dart';
import 'package:mangayomi/modules/more/settings/appearance/providers/theme_mode_state_provider.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/widgets/category_selection_dialog.dart';
@ -134,6 +135,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
final withoutCategories = ref.watch(
getAllMangaWithoutCategoriesStreamProvider(itemType: widget.itemType),
);
final downloadedOnly = ref.watch(downloadedOnlyStateProvider);
final mangaAll = ref.watch(
getAllMangaStreamProvider(
categoryId: null,
@ -247,6 +249,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref: ref,
localSource: localSource,
settings: settings,
downloadedOnly: downloadedOnly,
);
}
if (tabCount > 0 &&
@ -279,6 +282,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType,
downloadedOnly: downloadedOnly,
);
final withoutCategoryNumberOfItemsList =
_filterAndSortManga(
@ -288,6 +292,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType,
downloadedOnly: downloadedOnly,
);
return DefaultTabController(
@ -370,6 +375,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
categoryId:
entr[i - 1].id!,
settings: settings,
downloadedOnly:
downloadedOnly,
),
],
),
@ -396,6 +403,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
continueReaderBtn,
categoryId: entr[i].id!,
settings: settings,
downloadedOnly:
downloadedOnly,
),
],
),
@ -432,6 +441,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref: ref,
localSource: localSource,
settings: settings,
downloadedOnly:
downloadedOnly,
)
: _bodyWithCatories(
categoryId:
@ -454,6 +465,8 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref: ref,
localSource: localSource,
settings: settings,
downloadedOnly:
downloadedOnly,
),
if (withoutCategory.isEmpty)
for (
@ -481,6 +494,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref: ref,
localSource: localSource,
settings: settings,
downloadedOnly: downloadedOnly,
),
],
),
@ -501,6 +515,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType,
downloadedOnly: downloadedOnly,
);
return Scaffold(
appBar: _appBar(
@ -526,6 +541,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
ref: ref,
localSource: localSource,
settings: settings,
downloadedOnly: downloadedOnly,
),
);
},
@ -731,6 +747,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required bool continueReaderBtn,
required int categoryId,
required Settings settings,
required bool downloadedOnly,
}) {
final mangas = ref.watch(
getAllMangaStreamProvider(
@ -755,6 +772,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType!,
downloadedOnly: downloadedOnly,
);
return CircleAvatar(
backgroundColor: Theme.of(context).focusColor,
@ -791,6 +809,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required WidgetRef ref,
required DisplayType displayType,
required Settings settings,
required bool downloadedOnly,
}) {
final l10n = l10nLocalizations(context)!;
final mangas = ref.watch(
@ -818,6 +837,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType!,
downloadedOnly: downloadedOnly,
);
if (entries.isNotEmpty) {
final entriesManga = reverse ? entries.reversed.toList() : entries;
@ -875,6 +895,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required WidgetRef ref,
bool withoutCategories = false,
required Settings settings,
required bool downloadedOnly,
}) {
final sortType = ref
.watch(
@ -907,6 +928,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
startedFilterType: startedFilterType,
bookmarkedFilterType: bookmarkedFilterType,
sortType: sortType ?? 0,
downloadedOnly: downloadedOnly,
);
if (entries.isNotEmpty) {
final entriesManga = reverse ? entries.reversed.toList() : entries;
@ -970,6 +992,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
required int startedFilterType,
required int bookmarkedFilterType,
required int sortType,
bool downloadedOnly = false,
}) {
List<Manga>? mangas;
final searchQuery = _textEditingController.text;
@ -984,7 +1007,7 @@ class _LibraryScreenState extends ConsumerState<LibraryScreen>
.where((element) {
// Filter by download
List list = [];
if (downloadFilterType == 1) {
if (downloadFilterType == 1 || downloadedOnly) {
for (var chap in element.chapters) {
final modelChapDownload = isar.downloads
.filter()

View file

@ -11,6 +11,7 @@ import 'package:mangayomi/models/chapter.dart';
import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/update.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/more/providers/downloaded_only_state_provider.dart';
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
import 'package:mangayomi/modules/more/settings/sync/providers/sync_providers.dart';
import 'package:mangayomi/modules/widgets/loading_icon.dart';
@ -239,10 +240,16 @@ class _MainScreenState extends ConsumerState<MainScreen> {
}
final incognitoMode = ref.watch(incognitoModeStateProvider);
final downloadedOnly = ref.watch(downloadedOnlyStateProvider);
final isLongPressed = ref.watch(isLongPressedMangaStateProvider);
return Column(
children: [
if (!isReadingScreen)
_DownloadedOnlyBar(
downloadedOnly: downloadedOnly,
l10n: l10n,
),
if (!isReadingScreen)
_IncognitoModeBar(incognitoMode: incognitoMode, l10n: l10n),
Flexible(
@ -526,6 +533,45 @@ class _MainScreenState extends ConsumerState<MainScreen> {
}
}
class _DownloadedOnlyBar extends StatelessWidget {
const _DownloadedOnlyBar({required this.downloadedOnly, required this.l10n});
final bool downloadedOnly;
final dynamic l10n;
@override
Widget build(BuildContext context) {
return Material(
child: AnimatedContainer(
height: downloadedOnly
? Platform.isAndroid || Platform.isIOS
? MediaQuery.of(context).padding.top * 2
: 50
: 0,
curve: Curves.easeIn,
duration: const Duration(milliseconds: 150),
color: context.secondaryColor,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
l10n.downloaded_only,
style: TextStyle(
color: Colors.white,
fontFamily: GoogleFonts.aBeeZee().fontFamily,
),
),
),
],
),
),
);
}
}
class _IncognitoModeBar extends StatelessWidget {
const _IncognitoModeBar({required this.incognitoMode, required this.l10n});

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mangayomi/modules/more/widgets/downloaded_only_widget.dart';
import 'package:mangayomi/modules/more/widgets/incognito_mode_widget.dart';
import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
@ -37,6 +38,7 @@ class MoreScreen extends StatelessWidget {
// onChanged: (value) {},
// ),
// ),
const DownloadedOnlyWidget(),
const IncognitoModeWidget(),
const Divider(),
ListTileWidget(

View file

@ -0,0 +1,24 @@
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'downloaded_only_state_provider.g.dart';
@riverpod
class DownloadedOnlyState extends _$DownloadedOnlyState {
@override
bool build() {
return isar.settings.getSync(227)!.downloadedOnlyMode ?? false;
}
void setDownloadedOnly(bool value) {
final settings = isar.settings.getSync(227)!;
state = value;
isar.writeTxnSync(
() => isar.settings.putSync(
settings
..downloadedOnlyMode = state
..updatedAt = DateTime.now().millisecondsSinceEpoch,
),
);
}
}

View file

@ -0,0 +1,27 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'downloaded_only_state_provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$downloadedOnlyStateHash() =>
r'09c451617c435ca59554546f5d3090d20c961bfe';
/// See also [DownloadedOnlyState].
@ProviderFor(DownloadedOnlyState)
final downloadedOnlyStateProvider =
AutoDisposeNotifierProvider<DownloadedOnlyState, bool>.internal(
DownloadedOnlyState.new,
name: r'downloadedOnlyStateProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$downloadedOnlyStateHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef _$DownloadedOnlyState = AutoDisposeNotifier<bool>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View file

@ -7,7 +7,7 @@ part 'incognito_mode_state_provider.g.dart';
class IncognitoModeState extends _$IncognitoModeState {
@override
bool build() {
return isar.settings.getSync(227)!.incognitoMode!;
return isar.settings.getSync(227)!.incognitoMode ?? false;
}
void setIncognitoMode(bool value) {

View file

@ -7,7 +7,7 @@ part of 'incognito_mode_state_provider.dart';
// **************************************************************************
String _$incognitoModeStateHash() =>
r'149c4dcbc434fb6efc883e196392320bdc7c0821';
r'3858256a820eef632d3df57533f2aad14f555b22';
/// See also [IncognitoModeState].
@ProviderFor(IncognitoModeState)

View file

@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/modules/more/providers/downloaded_only_state_provider.dart';
import 'package:mangayomi/modules/more/widgets/list_tile_widget.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
class DownloadedOnlyWidget extends ConsumerWidget {
const DownloadedOnlyWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context);
final downloadedOnly = ref.watch(downloadedOnlyStateProvider);
return ListTileWidget(
onTap: () => ref
.read(downloadedOnlyStateProvider.notifier)
.setDownloadedOnly(!downloadedOnly),
icon: Icons.cloud_off_outlined,
subtitle: l10n!.downloaded_only_description,
title: l10n.downloaded_only,
trailing: Switch(
value: downloadedOnly,
onChanged: (value) => ref
.read(downloadedOnlyStateProvider.notifier)
.setDownloadedOnly(value),
),
);
}
}