From dfd82b32f684fdb4f7a057cb8aa7baaf8acaa21e Mon Sep 17 00:00:00 2001
From: kodjomoustapha <107993382+kodjodevf@users.noreply.github.com>
Date: Sat, 27 May 2023 20:34:05 +0100
Subject: [PATCH] feature: pinned , last used source + fix
---
lib/models/settings.dart | 2 +-
lib/models/source.dart | 6 +
lib/models/source.g.dart | 170 ++++++++++-
lib/modules/browse/browse_screen.dart | 2 +-
.../browse/extension/extension_screen.dart | 2 +-
.../refresh_source_list_data.dart | 1 +
.../refresh_source_list_data.g.dart | 2 +-
.../global_search/global_search_screen.dart | 126 ++++++---
.../browse/sources/sources_screen.dart | 263 ++++++++++--------
.../sources/widgets/source_list_tile.dart | 95 +++++++
.../appearance/widgets/dark_mode_button.dart | 10 +-
.../widgets/manga_image_card_widget.dart | 55 +++-
.../cloudflare/cloudflare_bypass.dart | 2 +-
.../multisrc/madara/madara_source_list.dart | 18 +-
lib/sources/multisrc/mmrcms/src/mmrcms.dart | 2 -
.../src/all/comick/comick_source_list.dart | 19 +-
lib/sources/src/all/comick/src/comick.dart | 16 +-
.../comick/src/model/search_manga_cimick.dart | 1 +
.../src/fr/mangakawaii/src/mangakawaii.dart | 8 +-
19 files changed, 586 insertions(+), 214 deletions(-)
rename lib/modules/browse/extension/{ => providers}/refresh_source_list_data.dart (97%)
rename lib/modules/browse/extension/{ => providers}/refresh_source_list_data.g.dart (95%)
create mode 100644 lib/modules/browse/sources/widgets/source_list_tile.dart
diff --git a/lib/models/settings.dart b/lib/models/settings.dart
index b0ea833..2ec8eec 100644
--- a/lib/models/settings.dart
+++ b/lib/models/settings.dart
@@ -94,7 +94,7 @@ class Settings {
this.dateFormat = "M/d/y",
this.relativeTimesTamps = 2,
this.flexSchemeColorIndex = 2,
- this.themeIsDark = true,
+ this.themeIsDark = false,
this.incognitoMode = false,
this.chapterPageUrlsList,
this.showPagesNumber = true,
diff --git a/lib/models/source.dart b/lib/models/source.dart
index d98a82c..6603c83 100644
--- a/lib/models/source.dart
+++ b/lib/models/source.dart
@@ -16,6 +16,8 @@ class Source {
bool? isAdded;
+ bool? isPinned;
+
bool? isNsfw;
@enumerated
@@ -27,6 +29,8 @@ class Source {
bool? isCloudflare;
+ bool? lastUsed;
+
String? dateFormat;
String? dateFormatLocale;
@@ -47,6 +51,8 @@ class Source {
this.isNsfw = false,
this.isFullData = false,
this.isCloudflare = false,
+ this.isPinned = false,
+ this.lastUsed = false,
this.apiUrl = "",
});
}
diff --git a/lib/models/source.g.dart b/lib/models/source.g.dart
index de6c3af..5914fb3 100644
--- a/lib/models/source.g.dart
+++ b/lib/models/source.g.dart
@@ -62,23 +62,33 @@ const SourceSchema = CollectionSchema(
name: r'isNsfw',
type: IsarType.bool,
),
- r'lang': PropertySchema(
+ r'isPinned': PropertySchema(
id: 9,
+ name: r'isPinned',
+ type: IsarType.bool,
+ ),
+ r'lang': PropertySchema(
+ id: 10,
name: r'lang',
type: IsarType.string,
),
+ r'lastUsed': PropertySchema(
+ id: 11,
+ name: r'lastUsed',
+ type: IsarType.bool,
+ ),
r'logoUrl': PropertySchema(
- id: 10,
+ id: 12,
name: r'logoUrl',
type: IsarType.string,
),
r'sourceName': PropertySchema(
- id: 11,
+ id: 13,
name: r'sourceName',
type: IsarType.string,
),
r'typeSource': PropertySchema(
- id: 12,
+ id: 14,
name: r'typeSource',
type: IsarType.byte,
enumMap: _SourcetypeSourceEnumValueMap,
@@ -164,10 +174,12 @@ void _sourceSerialize(
writer.writeBool(offsets[6], object.isCloudflare);
writer.writeBool(offsets[7], object.isFullData);
writer.writeBool(offsets[8], object.isNsfw);
- writer.writeString(offsets[9], object.lang);
- writer.writeString(offsets[10], object.logoUrl);
- writer.writeString(offsets[11], object.sourceName);
- writer.writeByte(offsets[12], object.typeSource.index);
+ writer.writeBool(offsets[9], object.isPinned);
+ writer.writeString(offsets[10], object.lang);
+ writer.writeBool(offsets[11], object.lastUsed);
+ writer.writeString(offsets[12], object.logoUrl);
+ writer.writeString(offsets[13], object.sourceName);
+ writer.writeByte(offsets[14], object.typeSource.index);
}
Source _sourceDeserialize(
@@ -187,11 +199,13 @@ Source _sourceDeserialize(
isCloudflare: reader.readBoolOrNull(offsets[6]),
isFullData: reader.readBoolOrNull(offsets[7]),
isNsfw: reader.readBoolOrNull(offsets[8]),
- lang: reader.readStringOrNull(offsets[9]),
- logoUrl: reader.readStringOrNull(offsets[10]),
- sourceName: reader.readStringOrNull(offsets[11]),
+ isPinned: reader.readBoolOrNull(offsets[9]),
+ lang: reader.readStringOrNull(offsets[10]),
+ lastUsed: reader.readBoolOrNull(offsets[11]),
+ logoUrl: reader.readStringOrNull(offsets[12]),
+ sourceName: reader.readStringOrNull(offsets[13]),
typeSource:
- _SourcetypeSourceValueEnumMap[reader.readByteOrNull(offsets[12])] ??
+ _SourcetypeSourceValueEnumMap[reader.readByteOrNull(offsets[14])] ??
TypeSource.single,
);
return object;
@@ -223,12 +237,16 @@ P _sourceDeserializeProp
(
case 8:
return (reader.readBoolOrNull(offset)) as P;
case 9:
- return (reader.readStringOrNull(offset)) as P;
+ return (reader.readBoolOrNull(offset)) as P;
case 10:
return (reader.readStringOrNull(offset)) as P;
case 11:
- return (reader.readStringOrNull(offset)) as P;
+ return (reader.readBoolOrNull(offset)) as P;
case 12:
+ return (reader.readStringOrNull(offset)) as P;
+ case 13:
+ return (reader.readStringOrNull(offset)) as P;
+ case 14:
return (_SourcetypeSourceValueEnumMap[reader.readByteOrNull(offset)] ??
TypeSource.single) as P;
default:
@@ -1128,6 +1146,32 @@ extension SourceQueryFilter on QueryBuilder {
});
}
+ QueryBuilder isPinnedIsNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNull(
+ property: r'isPinned',
+ ));
+ });
+ }
+
+ QueryBuilder isPinnedIsNotNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNotNull(
+ property: r'isPinned',
+ ));
+ });
+ }
+
+ QueryBuilder isPinnedEqualTo(
+ bool? value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'isPinned',
+ value: value,
+ ));
+ });
+ }
+
QueryBuilder langIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@@ -1273,6 +1317,32 @@ extension SourceQueryFilter on QueryBuilder {
});
}
+ QueryBuilder lastUsedIsNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNull(
+ property: r'lastUsed',
+ ));
+ });
+ }
+
+ QueryBuilder lastUsedIsNotNull() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(const FilterCondition.isNotNull(
+ property: r'lastUsed',
+ ));
+ });
+ }
+
+ QueryBuilder lastUsedEqualTo(
+ bool? value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'lastUsed',
+ value: value,
+ ));
+ });
+ }
+
QueryBuilder logoUrlIsNull() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(const FilterCondition.isNull(
@@ -1732,6 +1802,18 @@ extension SourceQuerySortBy on QueryBuilder {
});
}
+ QueryBuilder sortByIsPinned() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isPinned', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByIsPinnedDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isPinned', Sort.desc);
+ });
+ }
+
QueryBuilder sortByLang() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc);
@@ -1744,6 +1826,18 @@ extension SourceQuerySortBy on QueryBuilder {
});
}
+ QueryBuilder sortByLastUsed() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'lastUsed', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByLastUsedDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'lastUsed', Sort.desc);
+ });
+ }
+
QueryBuilder sortByLogoUrl() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'logoUrl', Sort.asc);
@@ -1902,6 +1996,18 @@ extension SourceQuerySortThenBy on QueryBuilder {
});
}
+ QueryBuilder thenByIsPinned() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isPinned', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByIsPinnedDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isPinned', Sort.desc);
+ });
+ }
+
QueryBuilder thenByLang() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'lang', Sort.asc);
@@ -1914,6 +2020,18 @@ extension SourceQuerySortThenBy on QueryBuilder {
});
}
+ QueryBuilder thenByLastUsed() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'lastUsed', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByLastUsedDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'lastUsed', Sort.desc);
+ });
+ }
+
QueryBuilder thenByLogoUrl() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'logoUrl', Sort.asc);
@@ -2011,6 +2129,12 @@ extension SourceQueryWhereDistinct on QueryBuilder {
});
}
+ QueryBuilder distinctByIsPinned() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'isPinned');
+ });
+ }
+
QueryBuilder distinctByLang(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@@ -2018,6 +2142,12 @@ extension SourceQueryWhereDistinct on QueryBuilder {
});
}
+ QueryBuilder distinctByLastUsed() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'lastUsed');
+ });
+ }
+
QueryBuilder distinctByLogoUrl(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
@@ -2100,12 +2230,24 @@ extension SourceQueryProperty on QueryBuilder {
});
}
+ QueryBuilder isPinnedProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'isPinned');
+ });
+ }
+
QueryBuilder langProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'lang');
});
}
+ QueryBuilder lastUsedProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'lastUsed');
+ });
+ }
+
QueryBuilder logoUrlProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'logoUrl');
diff --git a/lib/modules/browse/browse_screen.dart b/lib/modules/browse/browse_screen.dart
index c1c0f52..ca0cc41 100644
--- a/lib/modules/browse/browse_screen.dart
+++ b/lib/modules/browse/browse_screen.dart
@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
+import 'package:mangayomi/modules/browse/extension/providers/refresh_source_list_data.dart';
import 'package:mangayomi/providers/storage_provider.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/modules/browse/extension/extension_screen.dart';
-import 'package:mangayomi/modules/browse/extension/refresh_source_list_data.dart';
import 'package:mangayomi/modules/browse/migrate_screen.dart';
import 'package:mangayomi/modules/browse/sources/sources_screen.dart';
import 'package:mangayomi/modules/library/search_text_form_field.dart';
diff --git a/lib/modules/browse/extension/extension_screen.dart b/lib/modules/browse/extension/extension_screen.dart
index f07ecaf..fad423c 100644
--- a/lib/modules/browse/extension/extension_screen.dart
+++ b/lib/modules/browse/extension/extension_screen.dart
@@ -43,7 +43,7 @@ class ExtensionScreen extends ConsumerWidget {
Text(
groupByValue,
style: const TextStyle(
- fontWeight: FontWeight.w300, fontSize: 12),
+ fontWeight: FontWeight.bold, fontSize: 13),
),
],
),
diff --git a/lib/modules/browse/extension/refresh_source_list_data.dart b/lib/modules/browse/extension/providers/refresh_source_list_data.dart
similarity index 97%
rename from lib/modules/browse/extension/refresh_source_list_data.dart
rename to lib/modules/browse/extension/providers/refresh_source_list_data.dart
index 4a9c7c9..b0bded4 100644
--- a/lib/modules/browse/extension/refresh_source_list_data.dart
+++ b/lib/modules/browse/extension/providers/refresh_source_list_data.dart
@@ -28,6 +28,7 @@ refreshSourceListData(RefreshSourceListDataRef ref) {
..typeSource = source.typeSource
..isFullData = source.isFullData
..lang = source.lang
+ ..isNsfw = source.isNsfw
..sourceName = source.sourceName);
}
}
diff --git a/lib/modules/browse/extension/refresh_source_list_data.g.dart b/lib/modules/browse/extension/providers/refresh_source_list_data.g.dart
similarity index 95%
rename from lib/modules/browse/extension/refresh_source_list_data.g.dart
rename to lib/modules/browse/extension/providers/refresh_source_list_data.g.dart
index e7960d1..03df1be 100644
--- a/lib/modules/browse/extension/refresh_source_list_data.g.dart
+++ b/lib/modules/browse/extension/providers/refresh_source_list_data.g.dart
@@ -7,7 +7,7 @@ part of 'refresh_source_list_data.dart';
// **************************************************************************
String _$refreshSourceListDataHash() =>
- r'f77838cebad50f030d2038d07584199b4509f407';
+ r'c6ab103b0519d79afc8530ab7027a988203de5d3';
/// See also [refreshSourceListData].
@ProviderFor(refreshSourceListData)
diff --git a/lib/modules/browse/global_search/global_search_screen.dart b/lib/modules/browse/global_search/global_search_screen.dart
index fbc94f4..c70a067 100644
--- a/lib/modules/browse/global_search/global_search_screen.dart
+++ b/lib/modules/browse/global_search/global_search_screen.dart
@@ -3,12 +3,14 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
+import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/services/get_manga_detail.dart';
import 'package:mangayomi/services/search_manga.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/sources/service.dart';
import 'package:mangayomi/sources/source_list.dart';
import 'package:mangayomi/utils/cached_network.dart';
+import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/modules/library/search_text_form_field.dart';
@@ -31,7 +33,7 @@ class _GlobalSearchScreenState extends ConsumerState {
@override
Widget build(BuildContext context) {
final sourceList = ref.watch(onlyIncludePinnedSourceStateProvider)
- ? isar.sources.filter().isAddedEqualTo(true).findAllSync()
+ ? isar.sources.filter().isPinnedEqualTo(true).findAllSync()
: sourcesList;
return Scaffold(
appBar: AppBar(
@@ -62,7 +64,7 @@ class _GlobalSearchScreenState extends ConsumerState {
children: [
for (var i = 0; i < sourceList.length; i++)
SizedBox(
- height: 230,
+ height: 260,
child: SourceSearchScreen(
query: query,
source: sourceList[i],
@@ -91,7 +93,7 @@ class SourceSearchScreen extends ConsumerWidget {
.watch(searchMangaProvider(source: source.sourceName!, query: query));
return Scaffold(
body: SizedBox(
- height: 240,
+ height: 260,
child: Column(
children: [
ListTile(
@@ -175,43 +177,93 @@ class _MangaGlobalImageCardState extends ConsumerState
pushToMangaReaderDetail(
context: context, getManga: data, lang: widget.lang);
},
- child: SizedBox(
- width: 90,
- child: Column(children: [
- cachedNetworkImage(
- headers: ref.watch(headersProvider(source: data.source!)),
- imageUrl: data.imageUrl!,
- width: 80,
- height: 120,
- fit: BoxFit.fill),
- BottomTextWidget(
- fontSize: 12.0,
- text: widget.manga.name!,
- isLoading: true,
- isComfortableGrid: true,
- )
- ]),
- ),
+ child: StreamBuilder(
+ stream: isar.mangas
+ .filter()
+ .langEqualTo(widget.lang)
+ .nameEqualTo(data.name)
+ .sourceEqualTo(data.source)
+ .favoriteEqualTo(true)
+ .watch(fireImmediately: true),
+ builder: (context, snapshot) {
+ return Padding(
+ padding: const EdgeInsets.only(left: 10),
+ child: Stack(
+ children: [
+ SizedBox(
+ width: 100,
+ child: Column(children: [
+ ClipRRect(
+ borderRadius: BorderRadius.circular(2),
+ child: cachedNetworkImage(
+ headers: ref.watch(
+ headersProvider(source: data.source!)),
+ imageUrl: data.imageUrl!,
+ width: 100,
+ height: 140,
+ fit: BoxFit.fill),
+ ),
+ BottomTextWidget(
+ fontSize: 12.0,
+ text: widget.manga.name!,
+ isLoading: true,
+ isComfortableGrid: true,
+ )
+ ]),
+ ),
+ Container(
+ width: 100,
+ height: 140,
+ color: snapshot.hasData && snapshot.data!.isNotEmpty
+ ? Colors.black.withOpacity(0.7)
+ : null,
+ ),
+ if (snapshot.hasData && snapshot.data!.isNotEmpty)
+ Positioned(
+ top: 0,
+ left: 0,
+ child: Padding(
+ padding: const EdgeInsets.all(4),
+ child: Container(
+ decoration: BoxDecoration(
+ color: primaryColor(context),
+ borderRadius: BorderRadius.circular(5)),
+ child: const Padding(
+ padding: EdgeInsets.all(2),
+ child: Text(
+ "In library",
+ style: TextStyle(fontSize: 10),
+ ),
+ ),
+ ),
+ )),
+ ],
+ ),
+ );
+ }),
);
},
- loading: () => SizedBox(
- width: 60,
- child: Column(children: [
- ClipRRect(
- borderRadius: BorderRadius.circular(5),
- child: Container(
- color: Theme.of(context).cardColor,
- width: 80,
- height: 120,
+ loading: () => Padding(
+ padding: const EdgeInsets.only(left: 10),
+ child: SizedBox(
+ width: 100,
+ child: Column(children: [
+ ClipRRect(
+ borderRadius: BorderRadius.circular(5),
+ child: Container(
+ color: Theme.of(context).cardColor,
+ width: 100,
+ height: 140,
+ ),
),
- ),
- BottomTextWidget(
- fontSize: 12.0,
- text: widget.manga.name!,
- isLoading: true,
- isComfortableGrid: true,
- )
- ]),
+ BottomTextWidget(
+ fontSize: 12.0,
+ text: widget.manga.name!,
+ isLoading: true,
+ isComfortableGrid: true,
+ )
+ ]),
+ ),
),
error: (error, stackTrace) => Center(child: Text(error.toString())),
);
diff --git a/lib/modules/browse/sources/sources_screen.dart b/lib/modules/browse/sources/sources_screen.dart
index e14ba33..c343de8 100644
--- a/lib/modules/browse/sources/sources_screen.dart
+++ b/lib/modules/browse/sources/sources_screen.dart
@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:go_router/go_router.dart';
import 'package:grouped_list/grouped_list.dart';
import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
-import 'package:mangayomi/models/manga_type.dart';
import 'package:mangayomi/models/source.dart';
+import 'package:mangayomi/modules/browse/sources/widgets/source_list_tile.dart';
import 'package:mangayomi/utils/lang.dart';
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
@@ -15,124 +14,156 @@ class SourcesScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
- padding: const EdgeInsets.only(top: 10),
- child: StreamBuilder(
- stream: isar.sources
- .filter()
- .idIsNotNull()
- .isAddedEqualTo(true)
- .and()
- .isActiveEqualTo(true)
- .watch(fireImmediately: true),
- builder: (context, snapshot) {
- if (!snapshot.hasData) {
- return const Center(child: Text("Empty"));
- }
- final entries = snapshot.data!
- .where((element) => ref.watch(showNSFWStateProvider)
- ? true
- : element.isNsfw == false)
- .toList();
- return GroupedListView(
- elements: entries,
- groupBy: (element) => completeLang(element.lang!.toLowerCase()),
- groupSeparatorBuilder: (String groupByValue) => Padding(
- padding: const EdgeInsets.only(left: 12),
- child: Row(
- children: [
- Text(
- groupByValue,
- style: const TextStyle(
- fontWeight: FontWeight.w300, fontSize: 12),
- ),
- ],
- ),
- ),
- itemBuilder: (context, Source element) {
- return ListTile(
- onTap: () {
- context.push('/mangaHome',
- extra: MangaType(
- isFullData: element.isFullData,
- lang: element.lang,
- source: element.sourceName));
- },
- leading: Container(
- height: 37,
- width: 37,
- decoration: BoxDecoration(
- color: Theme.of(context)
- .secondaryHeaderColor
- .withOpacity(0.5),
- borderRadius: BorderRadius.circular(5)),
- child:
- // element.logoUrl!.isEmpty
- // ?
- const Icon(Icons.source_outlined)
- // : CachedNetworkImage(
- // httpHeaders: ref.watch(
- // headersProvider(source: element.sourceName!)),
- // imageUrl: element.logoUrl!,
- // fit: BoxFit.contain,
- // width: 37,
- // height: 37,
- // errorWidget: (context, url, error) {
- // return const SizedBox(
- // width: 37,
- // height: 37,
- // child: Center(
- // child: Icon(Icons.source_outlined),
- // ),
- // );
- // },
- // ),
- ),
- subtitle: Row(
- children: [
- Text(
- completeLang(element.lang!.toLowerCase()),
- style: const TextStyle(
- fontWeight: FontWeight.w300, fontSize: 12),
- ),
- if (element.isNsfw!)
- Row(
+ padding: const EdgeInsets.only(top: 10),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ StreamBuilder(
+ stream: isar.sources
+ .filter()
+ .idIsNotNull()
+ .isAddedEqualTo(true)
+ .and()
+ .isActiveEqualTo(true)
+ .and()
+ .lastUsedEqualTo(true)
+ .watch(fireImmediately: true),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const Center(child: Text(""));
+ }
+ final entries = snapshot.data!
+ .where((element) => ref.watch(showNSFWStateProvider)
+ ? true
+ : element.isNsfw == false)
+ .toList();
+ return GroupedListView(
+ elements: entries,
+ groupBy: (element) => "",
+ groupSeparatorBuilder: (String groupByValue) =>
+ const Padding(
+ padding: EdgeInsets.only(left: 12),
+ child: Row(
children: [
- const SizedBox(
- width: 2,
- ),
Text(
- "18+",
+ "Last used",
style: TextStyle(
- fontWeight: FontWeight.w300,
- fontSize: 10,
- color: Colors.redAccent
- .withBlue(5)
- .withOpacity(0.8)),
+ fontWeight: FontWeight.bold, fontSize: 13),
),
],
- )
- ],
- ),
- title: Text(element.sourceName!),
- trailing: const SizedBox(
- width: 110,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Icon(
- Icons.push_pin_outlined,
- color: Colors.black,
- )
- ],
- )),
- );
- },
- groupComparator: (group1, group2) => group1.compareTo(group2),
- itemComparator: (item1, item2) =>
- item1.sourceName!.compareTo(item2.sourceName!),
- order: GroupedListOrder.ASC,
- );
- }),
- );
+ ),
+ ),
+ itemBuilder: (context, Source element) {
+ return SourceListTile(
+ source: element,
+ );
+ },
+ shrinkWrap: true,
+ groupComparator: (group1, group2) =>
+ group1.compareTo(group2),
+ itemComparator: (item1, item2) =>
+ item1.sourceName!.compareTo(item2.sourceName!),
+ order: GroupedListOrder.ASC,
+ );
+ }),
+ StreamBuilder(
+ stream: isar.sources
+ .filter()
+ .idIsNotNull()
+ .isAddedEqualTo(true)
+ .and()
+ .isActiveEqualTo(true)
+ .and()
+ .isPinnedEqualTo(true)
+ .watch(fireImmediately: true),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const Center(child: Text(""));
+ }
+ final entries = snapshot.data!
+ .where((element) => ref.watch(showNSFWStateProvider)
+ ? true
+ : element.isNsfw == false)
+ .toList();
+ return GroupedListView(
+ elements: entries,
+ groupBy: (element) => "",
+ groupSeparatorBuilder: (String groupByValue) =>
+ const Padding(
+ padding: EdgeInsets.only(left: 12),
+ child: Row(
+ children: [
+ Text(
+ "Pinned",
+ style: TextStyle(
+ fontWeight: FontWeight.bold, fontSize: 13),
+ ),
+ ],
+ ),
+ ),
+ itemBuilder: (context, Source element) {
+ return SourceListTile(
+ source: element,
+ );
+ },
+ shrinkWrap: true,
+ groupComparator: (group1, group2) =>
+ group1.compareTo(group2),
+ itemComparator: (item1, item2) =>
+ item1.sourceName!.compareTo(item2.sourceName!),
+ order: GroupedListOrder.ASC,
+ );
+ }),
+ StreamBuilder(
+ stream: isar.sources
+ .filter()
+ .idIsNotNull()
+ .isAddedEqualTo(true)
+ .and()
+ .isActiveEqualTo(true)
+ .and()
+ .isPinnedEqualTo(false)
+ .watch(fireImmediately: true),
+ builder: (context, snapshot) {
+ if (!snapshot.hasData) {
+ return const Center(child: Text("Empty"));
+ }
+ final entries = snapshot.data!
+ .where((element) => ref.watch(showNSFWStateProvider)
+ ? true
+ : element.isNsfw == false)
+ .toList();
+ return GroupedListView(
+ elements: entries,
+ groupBy: (element) =>
+ completeLang(element.lang!.toLowerCase()),
+ groupSeparatorBuilder: (String groupByValue) => Padding(
+ padding: const EdgeInsets.only(left: 12),
+ child: Row(
+ children: [
+ Text(
+ groupByValue,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold, fontSize: 13),
+ ),
+ ],
+ ),
+ ),
+ itemBuilder: (context, Source element) {
+ return SourceListTile(
+ source: element,
+ );
+ },
+ shrinkWrap: true,
+ groupComparator: (group1, group2) =>
+ group1.compareTo(group2),
+ itemComparator: (item1, item2) =>
+ item1.sourceName!.compareTo(item2.sourceName!),
+ order: GroupedListOrder.ASC,
+ );
+ }),
+ ],
+ ),
+ ));
}
}
diff --git a/lib/modules/browse/sources/widgets/source_list_tile.dart b/lib/modules/browse/sources/widgets/source_list_tile.dart
new file mode 100644
index 0000000..6c52546
--- /dev/null
+++ b/lib/modules/browse/sources/widgets/source_list_tile.dart
@@ -0,0 +1,95 @@
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+import 'package:isar/isar.dart';
+import 'package:mangayomi/main.dart';
+import 'package:mangayomi/models/manga_type.dart';
+import 'package:mangayomi/models/source.dart';
+import 'package:mangayomi/utils/colors.dart';
+import 'package:mangayomi/utils/lang.dart';
+
+class SourceListTile extends StatelessWidget {
+ final Source source;
+ const SourceListTile({super.key, required this.source});
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ onTap: () {
+ final sources = isar.sources.filter().idIsNotNull().findAllSync();
+ isar.writeTxnSync(() {
+ for (var src in sources) {
+ isar.sources
+ .putSync(src..lastUsed = src.id == source.id ? true : false);
+ }
+ });
+
+ context.push('/mangaHome',
+ extra: MangaType(
+ isFullData: source.isFullData,
+ lang: source.lang,
+ source: source.sourceName));
+ },
+ leading: Container(
+ height: 37,
+ width: 37,
+ decoration: BoxDecoration(
+ color: Theme.of(context).secondaryHeaderColor.withOpacity(0.5),
+ borderRadius: BorderRadius.circular(5)),
+ child:
+ // source.logoUrl!.isEmpty
+ // ?
+ const Icon(Icons.source_outlined)
+ // : CachedNetworkImage(
+ // httpHeaders: ref.watch(
+ // headersProvider(source: source.sourceName!)),
+ // imageUrl: source.logoUrl!,
+ // fit: BoxFit.contain,
+ // width: 37,
+ // height: 37,
+ // errorWidget: (context, url, error) {
+ // return const SizedBox(
+ // width: 37,
+ // height: 37,
+ // child: Center(
+ // child: Icon(Icons.source_outlined),
+ // ),
+ // );
+ // },
+ // ),
+ ),
+ subtitle: Row(
+ children: [
+ Text(
+ completeLang(source.lang!.toLowerCase()),
+ style: const TextStyle(fontWeight: FontWeight.w300, fontSize: 12),
+ ),
+ if (source.isNsfw!)
+ Row(
+ children: [
+ const SizedBox(
+ width: 2,
+ ),
+ Text(
+ "18+",
+ style: TextStyle(
+ fontWeight: FontWeight.w300,
+ fontSize: 10,
+ color: Colors.redAccent.withBlue(5).withOpacity(0.8)),
+ ),
+ ],
+ )
+ ],
+ ),
+ title: Text(source.sourceName!),
+ trailing: IconButton(
+ onPressed: () {
+ isar.writeTxnSync(() =>
+ isar.sources.putSync(source..isPinned = !source.isPinned!));
+ },
+ icon: Icon(
+ Icons.push_pin_outlined,
+ color: source.isPinned! ? primaryColor(context) : null,
+ )),
+ );
+ }
+}
diff --git a/lib/modules/more/settings/appearance/widgets/dark_mode_button.dart b/lib/modules/more/settings/appearance/widgets/dark_mode_button.dart
index 4bd3df0..52fbee2 100644
--- a/lib/modules/more/settings/appearance/widgets/dark_mode_button.dart
+++ b/lib/modules/more/settings/appearance/widgets/dark_mode_button.dart
@@ -16,13 +16,13 @@ class DarkModeButton extends ConsumerStatefulWidget {
class _DarkModeButtonState extends ConsumerState {
@override
Widget build(BuildContext context) {
- bool isLight = ref.watch(themeModeStateProvider);
+ bool isDark = ref.watch(themeModeStateProvider);
return SwitchListTile(
onChanged: (value) {
if (value) {
- ref.read(themeModeStateProvider.notifier).setLightTheme();
- } else {
ref.read(themeModeStateProvider.notifier).setDarkTheme();
+ } else {
+ ref.read(themeModeStateProvider.notifier).setLightTheme();
}
},
title: const Text(
@@ -30,10 +30,10 @@ class _DarkModeButtonState extends ConsumerState {
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(
- isLight ? 'Off' : 'On',
+ !isDark ? 'Off' : 'On',
style: TextStyle(fontSize: 11, color: secondaryColor(context)),
),
- value: isLight,
+ value: !isDark,
);
}
}
diff --git a/lib/modules/widgets/manga_image_card_widget.dart b/lib/modules/widgets/manga_image_card_widget.dart
index a9811f4..5c3f4b7 100644
--- a/lib/modules/widgets/manga_image_card_widget.dart
+++ b/lib/modules/widgets/manga_image_card_widget.dart
@@ -8,6 +8,7 @@ import 'package:mangayomi/models/manga.dart';
import 'package:mangayomi/models/settings.dart';
import 'package:mangayomi/sources/service.dart';
import 'package:mangayomi/utils/cached_network.dart';
+import 'package:mangayomi/utils/colors.dart';
import 'package:mangayomi/utils/headers.dart';
import 'package:mangayomi/modules/widgets/bottom_text_widget.dart';
import 'package:mangayomi/modules/widgets/cover_view_widget.dart';
@@ -30,16 +31,50 @@ class MangaImageCardWidget extends ConsumerWidget {
pushToMangaReaderDetail(
context: context, getManga: getMangaDetail!, lang: lang);
},
- child: CoverViewWidget(children: [
- cachedNetworkImage(
- headers:
- ref.watch(headersProvider(source: getMangaDetail!.source!)),
- imageUrl: getMangaDetail!.imageUrl!,
- width: 200,
- height: 270,
- fit: BoxFit.cover),
- BottomTextWidget(text: getMangaDetail!.name!)
- ]),
+ child: StreamBuilder(
+ stream: isar.mangas
+ .filter()
+ .langEqualTo(lang)
+ .nameEqualTo(getMangaDetail!.name)
+ .sourceEqualTo(getMangaDetail!.source)
+ .favoriteEqualTo(true)
+ .watch(fireImmediately: true),
+ builder: (context, snapshot) {
+ return CoverViewWidget(children: [
+ cachedNetworkImage(
+ headers: ref
+ .watch(headersProvider(source: getMangaDetail!.source!)),
+ imageUrl: getMangaDetail!.imageUrl!,
+ width: 200,
+ height: 270,
+ fit: BoxFit.cover),
+ Container(
+ color: snapshot.hasData && snapshot.data!.isNotEmpty
+ ? Colors.black.withOpacity(0.7)
+ : null,
+ ),
+ if (snapshot.hasData && snapshot.data!.isNotEmpty)
+ Positioned(
+ top: 0,
+ left: 0,
+ child: Padding(
+ padding: const EdgeInsets.all(4),
+ child: Container(
+ decoration: BoxDecoration(
+ color: primaryColor(context),
+ borderRadius: BorderRadius.circular(5)),
+ child: const Padding(
+ padding: EdgeInsets.all(2),
+ child: Text(
+ "In library",
+ style: TextStyle(fontSize: 12),
+ ),
+ ),
+ ),
+ )),
+ BottomTextWidget(text: getMangaDetail!.name!)
+ ]);
+ }),
);
}
}
diff --git a/lib/services/http_service/cloudflare/cloudflare_bypass.dart b/lib/services/http_service/cloudflare/cloudflare_bypass.dart
index 1a193d7..655706e 100644
--- a/lib/services/http_service/cloudflare/cloudflare_bypass.dart
+++ b/lib/services/http_service/cloudflare/cloudflare_bypass.dart
@@ -151,7 +151,7 @@ Future cloudflareBypassHtml(CloudflareBypassHtmlRef ref,
}
return false;
});
- await Future.delayed(Duration(seconds: 10));
+ await Future.delayed(const Duration(seconds: 10));
html = await controller.evaluateJavascript(
source:
"window.document.getElementsByTagName('html')[0].outerHTML;");
diff --git a/lib/sources/multisrc/madara/madara_source_list.dart b/lib/sources/multisrc/madara/madara_source_list.dart
index 46d1651..fe5f315 100644
--- a/lib/sources/multisrc/madara/madara_source_list.dart
+++ b/lib/sources/multisrc/madara/madara_source_list.dart
@@ -84,19 +84,11 @@ List _madaraSourcesList = [
dateFormat: "MMMM dd, yyyy",
dateFormatLocale: "tr",
),
- Source(
- sourceName: "Comictoon",
- baseUrl: "https://comictoonthaith-new.com",
- lang: "th",
- typeSource: TypeSource.madara,
- logoUrl: '',
- dateFormat: "MMMMM dd, yyyy",
- dateFormatLocale: "th",
- ),
+
Source(
sourceName: "CookieToon",
baseUrl: "https://cookietoon.online",
- lang: "pt-BR",
+ lang: "pt-br",
typeSource: TypeSource.madara,
logoUrl: '',
dateFormat: "dd/MM/yyyy",
@@ -105,7 +97,7 @@ List _madaraSourcesList = [
Source(
sourceName: "Drope Scan",
baseUrl: "https://dropescan.com",
- lang: "pt-BR",
+ lang: "pt-br",
typeSource: TypeSource.madara,
logoUrl: '',
dateFormat: "dd/MM/yyyy",
@@ -123,7 +115,7 @@ List _madaraSourcesList = [
Source(
sourceName: "Final Scans",
baseUrl: "https://finalscans.com",
- lang: "pt-BR",
+ lang: "pt-br",
typeSource: TypeSource.madara,
logoUrl: '',
isNsfw: true,
@@ -190,7 +182,7 @@ List _madaraSourcesList = [
Source(
sourceName: "Kami Sama Explorer",
baseUrl: "https://leitor.kamisama.com.br",
- lang: "pt-BR",
+ lang: "pt-br",
typeSource: TypeSource.madara,
logoUrl: '',
dateFormat: "dd 'de' MMMM 'de' yyyy",
diff --git a/lib/sources/multisrc/mmrcms/src/mmrcms.dart b/lib/sources/multisrc/mmrcms/src/mmrcms.dart
index 43775ea..ad23049 100644
--- a/lib/sources/multisrc/mmrcms/src/mmrcms.dart
+++ b/lib/sources/multisrc/mmrcms/src/mmrcms.dart
@@ -1,6 +1,4 @@
import 'dart:convert';
-import 'dart:developer';
-
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:html/dom.dart';
import 'package:mangayomi/models/chapter.dart';
diff --git a/lib/sources/src/all/comick/comick_source_list.dart b/lib/sources/src/all/comick/comick_source_list.dart
index a5bd042..d1bfdae 100644
--- a/lib/sources/src/all/comick/comick_source_list.dart
+++ b/lib/sources/src/all/comick/comick_source_list.dart
@@ -4,7 +4,7 @@ const logoUrl =
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75';
const apiUrl = 'https://api.comick.fun';
const baseUrl = 'https://comick.app';
-
+const isNsfw = true;
List get comickSourcesList => _comickSourcesList;
List _comickSourcesList = [
Source(
@@ -15,6 +15,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -24,6 +25,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -33,6 +35,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -42,6 +45,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -51,6 +55,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -60,6 +65,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -69,6 +75,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -78,6 +85,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -87,6 +95,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -96,6 +105,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -105,6 +115,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -114,6 +125,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -123,6 +135,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -132,6 +145,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -141,6 +155,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -150,6 +165,7 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
Source(
sourceName: 'Comick',
@@ -159,5 +175,6 @@ List _comickSourcesList = [
typeSource: TypeSource.comick,
logoUrl: logoUrl,
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
+ isNsfw: isNsfw,
dateFormatLocale: "en"),
];
diff --git a/lib/sources/src/all/comick/src/comick.dart b/lib/sources/src/all/comick/src/comick.dart
index 8198d76..68735f6 100644
--- a/lib/sources/src/all/comick/src/comick.dart
+++ b/lib/sources/src/all/comick/src/comick.dart
@@ -103,18 +103,18 @@ class Comick extends MangaYomiServices {
required AutoDisposeFutureProviderRef ref}) async {
final response = await ref.watch(httpGetProvider(
url:
- 'https://api.comick.fun/search?q=${query.trim()}&tachiyomi=true&page=1',
+ '${getMangaAPIUrl(source)}/v1.0/search?q=${query.trim()}&tachiyomi=true&limit=50&page=1',
source: source,
resDom: false)
.future) as String?;
- var popularManga = jsonDecode(response!) as List;
- var popularMangaList =
- popularManga.map((e) => MangaSearchModelComick.fromJson(e)).toList();
+ var search = jsonDecode(response!) as List;
+ var searchList =
+ search.map((e) => MangaSearchModelComick.fromJson(e)).toList();
- for (var popular in popularMangaList) {
- url.add("/comic/${popular.slug}");
- name.add(popular.title);
- image.add(popular.coverUrl);
+ for (var search in searchList) {
+ url.add("/comic/${search.hid}#");
+ name.add(search.title);
+ image.add(search.coverUrl);
}
return mangaRes();
diff --git a/lib/sources/src/all/comick/src/model/search_manga_cimick.dart b/lib/sources/src/all/comick/src/model/search_manga_cimick.dart
index 7b0b308..102cc3c 100644
--- a/lib/sources/src/all/comick/src/model/search_manga_cimick.dart
+++ b/lib/sources/src/all/comick/src/model/search_manga_cimick.dart
@@ -32,6 +32,7 @@ class MangaSearchModelComick {
title = json['title'];
slug = json['slug'];
+ hid = json['hid'];
coverUrl = json['cover_url'];
}
diff --git a/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart b/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart
index 686793f..8d2ac49 100644
--- a/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart
+++ b/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart
@@ -212,10 +212,12 @@ class MangaKawaii extends MangaYomiServices {
}
return pageUrls;
}
-
+
@override
- Future> getLatestUpdatesManga({required String source, required int page, required AutoDisposeFutureProviderRef ref}) {
- // TODO: implement getLatestUpdatesManga
+ Future> getLatestUpdatesManga(
+ {required String source,
+ required int page,
+ required AutoDisposeFutureProviderRef ref}) {
throw UnimplementedError();
}
}