mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 23:22:07 +00:00
co-written with @Schnitzel5 : update source fetching methods to utilize repositories
This commit is contained in:
parent
f125f442c7
commit
8384bcad51
21 changed files with 2507 additions and 522 deletions
|
|
@ -209,10 +209,24 @@
|
|||
"sync_upload_failed": "Hochladen fehlgeschlagen",
|
||||
"sync_download_failed": "Herunterladen fehlgeschlagen",
|
||||
"sync_button_sync": "Jetzt synchronisieren",
|
||||
"sync_button_snapshot": "Snapshot erstellen",
|
||||
"sync_button_upload": "Alles hochladen",
|
||||
"sync_button_download": "Alles herunterladen",
|
||||
"sync_confirm_snapshot": "Erstelle eine Kopie des derzeiten Backups auf den Server!",
|
||||
"sync_confirm_upload": "Deine Daten auf dem Server werden jetzt durch deinen lokalen Daten ersetzt!",
|
||||
"sync_confirm_download": "Deine lokalen Daten werden jetzt durch den Daten vom Server ersetzt!",
|
||||
"sync_on": "Sync aktivieren",
|
||||
"sync_pending_manga": "Ausstehende Änderungen für Manga",
|
||||
"sync_pending_category": "Ausstehende Änderungen für Kategorien",
|
||||
"sync_pending_chapter": "Ausstehende Änderungen für Kapiteln",
|
||||
"sync_pending_history": "Ausstehende Änderungen für Fortschritte",
|
||||
"sync_pending_update": "Ausstehende Änderungen für Updates",
|
||||
"sync_pending_extension": "Ausstehende Änderungen für Erweiterungen",
|
||||
"sync_pending_track": "Ausstehende Änderungen für Trackings",
|
||||
"sync_snapshot_creating": "Erstelle Snapshot...",
|
||||
"sync_snapshot_created": "Snapshot wurde erstellt!",
|
||||
"sync_snapshot_no_data": "Keine Daten zum Sichern! Lade erstmal alles hoch!",
|
||||
"server_error": "Server error!",
|
||||
"dialog_confirm": "Fortfahren",
|
||||
"description": "Beschreibung",
|
||||
"full_screen_player": "Vollbildmodus aktivieren",
|
||||
|
|
@ -311,8 +325,6 @@
|
|||
"default_skip_intro_length": "Standardlänge für Intro überspringen",
|
||||
"default_playback_speed_length": "Standardlänge für Wiedergabegeschwindigkeit",
|
||||
"updateProgressAfterReading": "Fortschritt nach dem Lesen aktualisieren",
|
||||
"syncAfterReading": "Nach dem Lesen oder Anschauen synchronisieren",
|
||||
"syncOnAppLaunch": "Beim Öffnen der App synchronisieren",
|
||||
"no_sources_installed": "Keine Quellen installiert!",
|
||||
"show_extensions": "Erweiterungen anzeigen",
|
||||
"default_skip_forward_skip_length": "Standardmäßige Länge des Vorwärtsspringens",
|
||||
|
|
@ -389,8 +401,6 @@
|
|||
"reorder_navigation_description": "Du kannst die Anordnung und Sichbarheit der Navigation für dich selber anpassen.",
|
||||
"novel_sources": "Novel-Quellen",
|
||||
"novel_extensions": "Novel-Erweiterungen",
|
||||
"sync_after_reading": "Nach dem Lesen oder Ansehen synchronisieren",
|
||||
"sync_on_app_launch": "Beim Starten der App synchronisieren",
|
||||
"data_and_storage": "Daten und Speicher",
|
||||
"download_location_info": "Wird für Kapitel-Downloads verwendet",
|
||||
"storage": "Speicher",
|
||||
|
|
@ -400,5 +410,11 @@
|
|||
"app_settings": "App-Einstellungen",
|
||||
"sources_settings": "Quellen-Einstellungen",
|
||||
"include_sensitive_settings": "Sensible Einstellungen einbeziehen (z. B. Tracker-Login-Tokens)",
|
||||
"create": "Erstellen"
|
||||
"create": "Erstellen",
|
||||
"empty_extensions_repo": "Du hast derzeit keinen Repository-Link hier. Klicke auf das Plus-Symbol, um einen hinzuzufügen!",
|
||||
"add_extensions_repo": "Repository-Link hinzufügen",
|
||||
"remove_extensions_repo": "Repository-Link entfernen",
|
||||
"manage_manga_repo_url": "Verwalte Repository-Links für Manga",
|
||||
"manage_anime_repo_url": "Verwalte Repository-Links für Anime",
|
||||
"manage_novel_repo_url": "Verwalte Repository-Links für Novellen"
|
||||
}
|
||||
|
|
@ -209,10 +209,24 @@
|
|||
"sync_upload_failed": "Upload failed",
|
||||
"sync_download_failed": "Download failed",
|
||||
"sync_button_sync": "Sync progress",
|
||||
"sync_button_snapshot": "Create snapshot",
|
||||
"sync_button_upload": "Full upload",
|
||||
"sync_button_download": "Full download",
|
||||
"sync_confirm_snapshot": "Request the server to create a remote copy of the current backup!",
|
||||
"sync_confirm_upload": "A full upload will completely replace the remote data with your current one!",
|
||||
"sync_confirm_download": "A full download will completely replace your current data with the remote one!",
|
||||
"sync_on": "Enable sync",
|
||||
"sync_pending_manga": "Manga changes pending",
|
||||
"sync_pending_category": "Category changes pending",
|
||||
"sync_pending_chapter": "Chapter changes pending",
|
||||
"sync_pending_history": "History changes pending",
|
||||
"sync_pending_update": "Update changes pending",
|
||||
"sync_pending_extension": "Extension changes pending",
|
||||
"sync_pending_track": "Track changes pending",
|
||||
"sync_snapshot_creating": "Creating snapshot...",
|
||||
"sync_snapshot_created": "Snapshot created!",
|
||||
"sync_snapshot_no_data": "No data to create a snapshot! Do a full upload first!",
|
||||
"server_error": "Server error!",
|
||||
"dialog_confirm": "Confirm",
|
||||
"description": "Description",
|
||||
"reorder_navigation": "Customize navigation",
|
||||
|
|
@ -315,8 +329,6 @@
|
|||
"default_skip_intro_length": "Default Skip intro length",
|
||||
"default_playback_speed_length": "Default Playback speed length",
|
||||
"updateProgressAfterReading": "Update progress after reading",
|
||||
"sync_after_reading": "Sync after reading or watching",
|
||||
"sync_on_app_launch": "Sync when opening the app",
|
||||
"no_sources_installed": "No sources installed!",
|
||||
"show_extensions": "Show extensions",
|
||||
"default_skip_forward_skip_length": "Default skip forward skip length",
|
||||
|
|
@ -399,5 +411,22 @@
|
|||
"sources_settings": "Sources settings",
|
||||
"include_sensitive_settings": "Include sensitive settings (e.g., tracker login tokens)",
|
||||
"create": "Create",
|
||||
"downloads_are_limited_to_wifi": "Downloads are limited to Wi-Fi only"
|
||||
"downloads_are_limited_to_wifi": "Downloads are limited to Wi-Fi only",
|
||||
"manga_extensions_repo": "Manga extensions repo",
|
||||
"anime_extensions_repo": "Anime extensions repo",
|
||||
"novel_extensions_repo": "Novel extensions repo",
|
||||
"undefined": "undefined",
|
||||
"empty_extensions_repo": "You don't have any repository urls here. Click on the plus button to add one!",
|
||||
"add_extensions_repo": "Add repo URL",
|
||||
"remove_extensions_repo": "Remove repo URL",
|
||||
"manage_manga_repo_urls": "Manage Manga Repo URLs",
|
||||
"manage_anime_repo_urls": "Manage Anime Repo URLs",
|
||||
"manage_novel_repo_urls": "Manage Novel Repo URLs",
|
||||
"url_cannot_be_empty": "URL cannot be empty",
|
||||
"url_must_end_with_dot_json": "URL must end with .json",
|
||||
"repo_url": "Repo URL",
|
||||
"invalid_url_format": "Invalid URL format",
|
||||
"clear_all_sources": "Clear all sources",
|
||||
"clear_all_sources_msg": "This will completely erase all sources of the application. Are you sure you want to continue?",
|
||||
"sources_cleared": "Sources cleared!!!"
|
||||
}
|
||||
|
|
@ -185,6 +185,12 @@ class Settings {
|
|||
|
||||
int? novelGridSize;
|
||||
|
||||
List<Repo>? mangaExtensionsRepo;
|
||||
|
||||
List<Repo>? animeExtensionsRepo;
|
||||
|
||||
List<Repo>? novelExtensionsRepo;
|
||||
|
||||
@enumerated
|
||||
late SectionType disableSectionType;
|
||||
|
||||
|
|
@ -325,7 +331,10 @@ class Settings {
|
|||
this.novelTextAlign = NovelTextAlign.left,
|
||||
this.navigationOrder,
|
||||
this.hideItems,
|
||||
this.clearChapterCacheOnAppLaunch = false});
|
||||
this.clearChapterCacheOnAppLaunch = false,
|
||||
this.mangaExtensionsRepo,
|
||||
this.animeExtensionsRepo,
|
||||
this.novelExtensionsRepo});
|
||||
|
||||
Settings.fromJson(Map<String, dynamic> json) {
|
||||
animatePageTransitions = json['animatePageTransitions'];
|
||||
|
|
@ -507,6 +516,21 @@ class Settings {
|
|||
hideItems = (json['hideItems'] as List).cast<String>();
|
||||
}
|
||||
clearChapterCacheOnAppLaunch = json['clearChapterCacheOnAppLaunch'];
|
||||
if (json['mangaExtensionsRepo'] != null) {
|
||||
mangaExtensionsRepo = (json['mangaExtensionsRepo'] as List)
|
||||
.map((e) => Repo.fromJson(json))
|
||||
.toList();
|
||||
}
|
||||
if (json['animeExtensionsRepo'] != null) {
|
||||
animeExtensionsRepo = (json['animeExtensionsRepo'] as List)
|
||||
.map((e) => Repo.fromJson(json))
|
||||
.toList();
|
||||
}
|
||||
if (json['novelExtensionsRepo'] != null) {
|
||||
novelExtensionsRepo = (json['novelExtensionsRepo'] as List)
|
||||
.map((e) => Repo.fromJson(json))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
|
@ -623,7 +647,13 @@ class Settings {
|
|||
'novelTextAlign': novelTextAlign.index,
|
||||
'navigationOrder': navigationOrder,
|
||||
'hideItems': hideItems,
|
||||
'clearChapterCacheOnAppLaunch': clearChapterCacheOnAppLaunch
|
||||
'clearChapterCacheOnAppLaunch': clearChapterCacheOnAppLaunch,
|
||||
'mangaExtensionsRepo':
|
||||
mangaExtensionsRepo?.map((e) => e.toJson()).toList(),
|
||||
'animeExtensionsRepo':
|
||||
animeExtensionsRepo?.map((e) => e.toJson()).toList(),
|
||||
'novelExtensionsRepo':
|
||||
novelExtensionsRepo?.map((e) => e.toJson()).toList()
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -796,6 +826,24 @@ class AutoScrollPages {
|
|||
{'mangaId': mangaId, 'pageOffset': pageOffset, 'autoScroll': autoScroll};
|
||||
}
|
||||
|
||||
@embedded
|
||||
class Repo {
|
||||
String? name;
|
||||
String? website;
|
||||
String? jsonUrl;
|
||||
|
||||
Repo({this.name, this.website, this.jsonUrl});
|
||||
|
||||
Repo.fromJson(Map<String, dynamic> json) {
|
||||
name = json['name'];
|
||||
website = json['website'];
|
||||
jsonUrl = json['jsonUrl'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() =>
|
||||
{'name': name, 'website': website, 'jsonUrl': jsonUrl};
|
||||
}
|
||||
|
||||
@embedded
|
||||
class PersonalPageMode {
|
||||
int? mangaId;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:isar/isar.dart';
|
||||
import 'package:mangayomi/eval/model/m_source.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
part 'source.g.dart';
|
||||
|
||||
@collection
|
||||
|
|
@ -64,6 +65,8 @@ class Source {
|
|||
@enumerated
|
||||
SourceCodeLanguage sourceCodeLanguage = SourceCodeLanguage.dart;
|
||||
|
||||
Repo? repo;
|
||||
|
||||
Source(
|
||||
{this.id = 0,
|
||||
this.name = '',
|
||||
|
|
@ -91,7 +94,8 @@ class Source {
|
|||
this.appMinVerReq = "",
|
||||
this.additionalParams = "",
|
||||
this.isLocal = false,
|
||||
this.isObsolete = false});
|
||||
this.isObsolete = false,
|
||||
this.repo});
|
||||
|
||||
Source.fromJson(Map<String, dynamic> json) {
|
||||
apiUrl = json['apiUrl'];
|
||||
|
|
@ -123,6 +127,7 @@ class Source {
|
|||
isLocal = json['isLocal'];
|
||||
sourceCodeLanguage =
|
||||
SourceCodeLanguage.values[json['sourceCodeLanguage'] ?? 0];
|
||||
repo = json['repo'] != null ? Repo.fromJson(json['repo']) : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
|
|
@ -153,7 +158,8 @@ class Source {
|
|||
'additionalParams': additionalParams,
|
||||
'sourceCodeLanguage': sourceCodeLanguage.index,
|
||||
'isObsolete': isObsolete,
|
||||
'isLocal': isLocal
|
||||
'isLocal': isLocal,
|
||||
'repo': repo?.toJson()
|
||||
};
|
||||
|
||||
bool get isTorrent => (typeSource?.toLowerCase() ?? "") == "torrent";
|
||||
|
|
|
|||
|
|
@ -128,34 +128,40 @@ const SourceSchema = CollectionSchema(
|
|||
name: r'name',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCode': PropertySchema(
|
||||
r'repo': PropertySchema(
|
||||
id: 22,
|
||||
name: r'repo',
|
||||
type: IsarType.object,
|
||||
target: r'Repo',
|
||||
),
|
||||
r'sourceCode': PropertySchema(
|
||||
id: 23,
|
||||
name: r'sourceCode',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'sourceCodeLanguage': PropertySchema(
|
||||
id: 23,
|
||||
id: 24,
|
||||
name: r'sourceCodeLanguage',
|
||||
type: IsarType.byte,
|
||||
enumMap: _SourcesourceCodeLanguageEnumValueMap,
|
||||
),
|
||||
r'sourceCodeUrl': PropertySchema(
|
||||
id: 24,
|
||||
id: 25,
|
||||
name: r'sourceCodeUrl',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'typeSource': PropertySchema(
|
||||
id: 25,
|
||||
id: 26,
|
||||
name: r'typeSource',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'version': PropertySchema(
|
||||
id: 26,
|
||||
id: 27,
|
||||
name: r'version',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'versionLast': PropertySchema(
|
||||
id: 27,
|
||||
id: 28,
|
||||
name: r'versionLast',
|
||||
type: IsarType.string,
|
||||
)
|
||||
|
|
@ -167,7 +173,7 @@ const SourceSchema = CollectionSchema(
|
|||
idName: r'id',
|
||||
indexes: {},
|
||||
links: {},
|
||||
embeddedSchemas: {},
|
||||
embeddedSchemas: {r'Repo': RepoSchema},
|
||||
getId: _sourceGetId,
|
||||
getLinks: _sourceGetLinks,
|
||||
attach: _sourceAttach,
|
||||
|
|
@ -240,6 +246,13 @@ int _sourceEstimateSize(
|
|||
bytesCount += 3 + value.length * 3;
|
||||
}
|
||||
}
|
||||
{
|
||||
final value = object.repo;
|
||||
if (value != null) {
|
||||
bytesCount +=
|
||||
3 + RepoSchema.estimateSize(value, allOffsets[Repo]!, allOffsets);
|
||||
}
|
||||
}
|
||||
{
|
||||
final value = object.sourceCode;
|
||||
if (value != null) {
|
||||
|
|
@ -301,12 +314,18 @@ void _sourceSerialize(
|
|||
writer.writeString(offsets[19], object.lang);
|
||||
writer.writeBool(offsets[20], object.lastUsed);
|
||||
writer.writeString(offsets[21], object.name);
|
||||
writer.writeString(offsets[22], object.sourceCode);
|
||||
writer.writeByte(offsets[23], object.sourceCodeLanguage.index);
|
||||
writer.writeString(offsets[24], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[25], object.typeSource);
|
||||
writer.writeString(offsets[26], object.version);
|
||||
writer.writeString(offsets[27], object.versionLast);
|
||||
writer.writeObject<Repo>(
|
||||
offsets[22],
|
||||
allOffsets,
|
||||
RepoSchema.serialize,
|
||||
object.repo,
|
||||
);
|
||||
writer.writeString(offsets[23], object.sourceCode);
|
||||
writer.writeByte(offsets[24], object.sourceCodeLanguage.index);
|
||||
writer.writeString(offsets[25], object.sourceCodeUrl);
|
||||
writer.writeString(offsets[26], object.typeSource);
|
||||
writer.writeString(offsets[27], object.version);
|
||||
writer.writeString(offsets[28], object.versionLast);
|
||||
}
|
||||
|
||||
Source _sourceDeserialize(
|
||||
|
|
@ -339,14 +358,19 @@ Source _sourceDeserialize(
|
|||
lang: reader.readStringOrNull(offsets[19]),
|
||||
lastUsed: reader.readBoolOrNull(offsets[20]),
|
||||
name: reader.readStringOrNull(offsets[21]),
|
||||
sourceCode: reader.readStringOrNull(offsets[22]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[24]),
|
||||
typeSource: reader.readStringOrNull(offsets[25]),
|
||||
version: reader.readStringOrNull(offsets[26]),
|
||||
versionLast: reader.readStringOrNull(offsets[27]),
|
||||
repo: reader.readObjectOrNull<Repo>(
|
||||
offsets[22],
|
||||
RepoSchema.deserialize,
|
||||
allOffsets,
|
||||
),
|
||||
sourceCode: reader.readStringOrNull(offsets[23]),
|
||||
sourceCodeUrl: reader.readStringOrNull(offsets[25]),
|
||||
typeSource: reader.readStringOrNull(offsets[26]),
|
||||
version: reader.readStringOrNull(offsets[27]),
|
||||
versionLast: reader.readStringOrNull(offsets[28]),
|
||||
);
|
||||
object.sourceCodeLanguage = _SourcesourceCodeLanguageValueEnumMap[
|
||||
reader.readByteOrNull(offsets[23])] ??
|
||||
reader.readByteOrNull(offsets[24])] ??
|
||||
SourceCodeLanguage.dart;
|
||||
return object;
|
||||
}
|
||||
|
|
@ -404,19 +428,25 @@ P _sourceDeserializeProp<P>(
|
|||
case 21:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 22:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
return (reader.readObjectOrNull<Repo>(
|
||||
offset,
|
||||
RepoSchema.deserialize,
|
||||
allOffsets,
|
||||
)) as P;
|
||||
case 23:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 24:
|
||||
return (_SourcesourceCodeLanguageValueEnumMap[
|
||||
reader.readByteOrNull(offset)] ??
|
||||
SourceCodeLanguage.dart) as P;
|
||||
case 24:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 25:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 26:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 27:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 28:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
|
@ -2388,6 +2418,22 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> repoIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
property: r'repo',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> repoIsNotNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNotNull(
|
||||
property: r'repo',
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> sourceCodeIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
|
@ -3175,7 +3221,14 @@ extension SourceQueryFilter on QueryBuilder<Source, Source, QFilterCondition> {
|
|||
}
|
||||
}
|
||||
|
||||
extension SourceQueryObject on QueryBuilder<Source, Source, QFilterCondition> {}
|
||||
extension SourceQueryObject on QueryBuilder<Source, Source, QFilterCondition> {
|
||||
QueryBuilder<Source, Source, QAfterFilterCondition> repo(
|
||||
FilterQuery<Repo> q) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.object(q, r'repo');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SourceQueryLinks on QueryBuilder<Source, Source, QFilterCondition> {}
|
||||
|
||||
|
|
@ -4194,6 +4247,12 @@ extension SourceQueryProperty on QueryBuilder<Source, Source, QQueryProperty> {
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, Repo?, QQueryOperations> repoProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'repo');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Source, String?, QQueryOperations> sourceCodeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'sourceCode');
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:mangayomi/services/http/m_client.dart';
|
|||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/utils/language.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class ExtensionDetail extends ConsumerStatefulWidget {
|
||||
final Source source;
|
||||
|
|
@ -24,19 +25,36 @@ class ExtensionDetail extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
|
||||
late Source source = widget.source;
|
||||
late Source source = isar.sources.getSync(widget.source.id!)!;
|
||||
late List<SourcePreference> sourcePreference =
|
||||
getSourcePreference(source: source)
|
||||
.map((e) => getSourcePreferenceEntry(e.key!, source.id!))
|
||||
.toList();
|
||||
Future<void> _launchInBrowser(Uri url) async {
|
||||
if (!await launchUrl(
|
||||
url,
|
||||
mode: LaunchMode.externalApplication,
|
||||
)) {
|
||||
throw 'Could not launch $url';
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(l10n.extension_detail),
|
||||
leading: BackButton(onPressed: () => Navigator.pop(context, source))),
|
||||
title: Text(l10n.extension_detail),
|
||||
leading: BackButton(onPressed: () => Navigator.pop(context, source)),
|
||||
actions: [
|
||||
if (source.repo?.website != null)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
_launchInBrowser(Uri.parse(source.repo!.website!));
|
||||
},
|
||||
icon: Icon(Icons.open_in_new_outlined))
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'ef2f5195c42fa8e17fc3d8cd5ffecc67f82472e9';
|
||||
String _$downloadChapterHash() => r'08a7196ae7da5d980629ef80d04ab9b251006eaf';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
|
|
@ -36,6 +41,39 @@ class BrowseSScreen extends ConsumerWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
context.push("/SourceRepositories",
|
||||
extra: ItemType.manga);
|
||||
},
|
||||
title: Text(l10n.manga_extensions_repo),
|
||||
subtitle: Text(
|
||||
l10n.manage_manga_repo_urls,
|
||||
style: TextStyle(
|
||||
fontSize: 11, color: context.secondaryColor),
|
||||
)),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
context.push("/SourceRepositories",
|
||||
extra: ItemType.anime);
|
||||
},
|
||||
title: Text(l10n.anime_extensions_repo),
|
||||
subtitle: Text(
|
||||
l10n.manage_anime_repo_urls,
|
||||
style: TextStyle(
|
||||
fontSize: 11, color: context.secondaryColor),
|
||||
)),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
context.push("/SourceRepositories",
|
||||
extra: ItemType.novel);
|
||||
},
|
||||
title: Text(l10n.novel_extensions_repo),
|
||||
subtitle: Text(
|
||||
l10n.manage_novel_repo_urls,
|
||||
style: TextStyle(
|
||||
fontSize: 11, color: context.secondaryColor),
|
||||
)),
|
||||
SwitchListTile(
|
||||
value: checkForExtensionUpdates,
|
||||
title: Text(l10n.check_for_extension_updates),
|
||||
|
|
@ -45,6 +83,28 @@ class BrowseSScreen extends ConsumerWidget {
|
|||
checkForExtensionsUpdateStateProvider.notifier)
|
||||
.set(value);
|
||||
}),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
|
||||
child: SizedBox(
|
||||
width: context.width(1),
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
_showClearAllSourcesDialog(context, l10n),
|
||||
child: Text(
|
||||
l10n.clear_all_sources,
|
||||
style: const TextStyle(
|
||||
fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (checkForExtensionUpdates)
|
||||
SwitchListTile(
|
||||
value: autoUpdateExtensions,
|
||||
|
|
@ -91,3 +151,41 @@ class BrowseSScreen extends ConsumerWidget {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _showClearAllSourcesDialog(BuildContext context, dynamic l10n) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.clear_all_sources,
|
||||
),
|
||||
content: Text(l10n.clear_all_sources_msg),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
child: Text(l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
isar.writeTxnSync(() {
|
||||
isar.sources.clearSync();
|
||||
});
|
||||
|
||||
Navigator.pop(ctx);
|
||||
botToast(l10n.sources_cleared);
|
||||
},
|
||||
child: Text(l10n.ok)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/services/fetch_anime_sources.dart';
|
||||
import 'package:mangayomi/services/fetch_manga_sources.dart';
|
||||
import 'package:mangayomi/services/fetch_novel_sources.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'browse_state_provider.g.dart';
|
||||
|
||||
|
|
@ -18,6 +25,46 @@ class OnlyIncludePinnedSourceState extends _$OnlyIncludePinnedSourceState {
|
|||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ExtensionsRepoState extends _$ExtensionsRepoState {
|
||||
@override
|
||||
List<Repo> build(ItemType itemType) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
return switch (itemType) {
|
||||
ItemType.manga => settings.mangaExtensionsRepo,
|
||||
ItemType.anime => settings.animeExtensionsRepo,
|
||||
_ => settings.novelExtensionsRepo,
|
||||
} ??
|
||||
[];
|
||||
}
|
||||
|
||||
void set(List<Repo> value) {
|
||||
final settings = isar.settings.getSync(227)!;
|
||||
state = value;
|
||||
isar.writeTxnSync(() {
|
||||
final a = switch (itemType) {
|
||||
ItemType.manga =>
|
||||
isar.settings.putSync(settings..mangaExtensionsRepo = value),
|
||||
ItemType.anime =>
|
||||
isar.settings.putSync(settings..animeExtensionsRepo = value),
|
||||
_ => isar.settings.putSync(settings..novelExtensionsRepo = value),
|
||||
};
|
||||
a;
|
||||
});
|
||||
try {
|
||||
final a = switch (itemType) {
|
||||
ItemType.manga => ref.refresh(
|
||||
fetchMangaSourcesListProvider(id: null, reFresh: false).future),
|
||||
ItemType.anime => ref.refresh(
|
||||
fetchAnimeSourcesListProvider(id: null, reFresh: false).future),
|
||||
_ => ref.refresh(
|
||||
fetchNovelSourcesListProvider(id: null, reFresh: false).future),
|
||||
};
|
||||
Future.wait([a]);
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class AutoUpdateExtensionsState extends _$AutoUpdateExtensionsState {
|
||||
@override
|
||||
|
|
@ -47,3 +94,22 @@ class CheckForExtensionsUpdateState extends _$CheckForExtensionsUpdateState {
|
|||
isar.settings.putSync(settings!..checkForExtensionUpdates = value));
|
||||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<Repo> getRepoInfos(Ref ref, {required String jsonUrl}) async {
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
|
||||
Map<String, dynamic> infos = {};
|
||||
final match = RegExp(r'^(.*)/[^/]+\.json$').firstMatch(jsonUrl);
|
||||
|
||||
if (match != null) {
|
||||
String url = match.group(1)!;
|
||||
final req = await http.get(Uri.parse("$url/repo.json"));
|
||||
if (req.statusCode == 200) {
|
||||
infos.addAll(jsonDecode(req.body));
|
||||
}
|
||||
}
|
||||
|
||||
infos["jsonUrl"] = jsonUrl;
|
||||
return Repo.fromJson(infos);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,157 @@ part of 'browse_state_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getRepoInfosHash() => r'd5d5eca9fd23accd515bf51b470edb99a5d58733';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
/// See also [getRepoInfos].
|
||||
@ProviderFor(getRepoInfos)
|
||||
const getRepoInfosProvider = GetRepoInfosFamily();
|
||||
|
||||
/// See also [getRepoInfos].
|
||||
class GetRepoInfosFamily extends Family<AsyncValue<Repo>> {
|
||||
/// See also [getRepoInfos].
|
||||
const GetRepoInfosFamily();
|
||||
|
||||
/// See also [getRepoInfos].
|
||||
GetRepoInfosProvider call({
|
||||
required String jsonUrl,
|
||||
}) {
|
||||
return GetRepoInfosProvider(
|
||||
jsonUrl: jsonUrl,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
GetRepoInfosProvider getProviderOverride(
|
||||
covariant GetRepoInfosProvider provider,
|
||||
) {
|
||||
return call(
|
||||
jsonUrl: provider.jsonUrl,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'getRepoInfosProvider';
|
||||
}
|
||||
|
||||
/// See also [getRepoInfos].
|
||||
class GetRepoInfosProvider extends AutoDisposeFutureProvider<Repo> {
|
||||
/// See also [getRepoInfos].
|
||||
GetRepoInfosProvider({
|
||||
required String jsonUrl,
|
||||
}) : this._internal(
|
||||
(ref) => getRepoInfos(
|
||||
ref as GetRepoInfosRef,
|
||||
jsonUrl: jsonUrl,
|
||||
),
|
||||
from: getRepoInfosProvider,
|
||||
name: r'getRepoInfosProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$getRepoInfosHash,
|
||||
dependencies: GetRepoInfosFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
GetRepoInfosFamily._allTransitiveDependencies,
|
||||
jsonUrl: jsonUrl,
|
||||
);
|
||||
|
||||
GetRepoInfosProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.jsonUrl,
|
||||
}) : super.internal();
|
||||
|
||||
final String jsonUrl;
|
||||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Repo> Function(GetRepoInfosRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: GetRepoInfosProvider._internal(
|
||||
(ref) => create(ref as GetRepoInfosRef),
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
jsonUrl: jsonUrl,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeFutureProviderElement<Repo> createElement() {
|
||||
return _GetRepoInfosProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is GetRepoInfosProvider && other.jsonUrl == jsonUrl;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, jsonUrl.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin GetRepoInfosRef on AutoDisposeFutureProviderRef<Repo> {
|
||||
/// The parameter `jsonUrl` of this provider.
|
||||
String get jsonUrl;
|
||||
}
|
||||
|
||||
class _GetRepoInfosProviderElement
|
||||
extends AutoDisposeFutureProviderElement<Repo> with GetRepoInfosRef {
|
||||
_GetRepoInfosProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
String get jsonUrl => (origin as GetRepoInfosProvider).jsonUrl;
|
||||
}
|
||||
|
||||
String _$onlyIncludePinnedSourceStateHash() =>
|
||||
r'77c4bff96e186c4bce0a5c312871ceec88a269d0';
|
||||
|
||||
|
|
@ -23,6 +174,153 @@ final onlyIncludePinnedSourceStateProvider =
|
|||
);
|
||||
|
||||
typedef _$OnlyIncludePinnedSourceState = AutoDisposeNotifier<bool>;
|
||||
String _$extensionsRepoStateHash() =>
|
||||
r'9e59b257433ed7f999dd4800f6ecb8c13c8b2c6a';
|
||||
|
||||
abstract class _$ExtensionsRepoState
|
||||
extends BuildlessAutoDisposeNotifier<List<Repo>> {
|
||||
late final ItemType itemType;
|
||||
|
||||
List<Repo> build(
|
||||
ItemType itemType,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [ExtensionsRepoState].
|
||||
@ProviderFor(ExtensionsRepoState)
|
||||
const extensionsRepoStateProvider = ExtensionsRepoStateFamily();
|
||||
|
||||
/// See also [ExtensionsRepoState].
|
||||
class ExtensionsRepoStateFamily extends Family<List<Repo>> {
|
||||
/// See also [ExtensionsRepoState].
|
||||
const ExtensionsRepoStateFamily();
|
||||
|
||||
/// See also [ExtensionsRepoState].
|
||||
ExtensionsRepoStateProvider call(
|
||||
ItemType itemType,
|
||||
) {
|
||||
return ExtensionsRepoStateProvider(
|
||||
itemType,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ExtensionsRepoStateProvider getProviderOverride(
|
||||
covariant ExtensionsRepoStateProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.itemType,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'extensionsRepoStateProvider';
|
||||
}
|
||||
|
||||
/// See also [ExtensionsRepoState].
|
||||
class ExtensionsRepoStateProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ExtensionsRepoState, List<Repo>> {
|
||||
/// See also [ExtensionsRepoState].
|
||||
ExtensionsRepoStateProvider(
|
||||
ItemType itemType,
|
||||
) : this._internal(
|
||||
() => ExtensionsRepoState()..itemType = itemType,
|
||||
from: extensionsRepoStateProvider,
|
||||
name: r'extensionsRepoStateProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$extensionsRepoStateHash,
|
||||
dependencies: ExtensionsRepoStateFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ExtensionsRepoStateFamily._allTransitiveDependencies,
|
||||
itemType: itemType,
|
||||
);
|
||||
|
||||
ExtensionsRepoStateProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.itemType,
|
||||
}) : super.internal();
|
||||
|
||||
final ItemType itemType;
|
||||
|
||||
@override
|
||||
List<Repo> runNotifierBuild(
|
||||
covariant ExtensionsRepoState notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
itemType,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(ExtensionsRepoState Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: ExtensionsRepoStateProvider._internal(
|
||||
() => create()..itemType = itemType,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<ExtensionsRepoState, List<Repo>>
|
||||
createElement() {
|
||||
return _ExtensionsRepoStateProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ExtensionsRepoStateProvider && other.itemType == itemType;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, itemType.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin ExtensionsRepoStateRef on AutoDisposeNotifierProviderRef<List<Repo>> {
|
||||
/// The parameter `itemType` of this provider.
|
||||
ItemType get itemType;
|
||||
}
|
||||
|
||||
class _ExtensionsRepoStateProviderElement
|
||||
extends AutoDisposeNotifierProviderElement<ExtensionsRepoState, List<Repo>>
|
||||
with ExtensionsRepoStateRef {
|
||||
_ExtensionsRepoStateProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
ItemType get itemType => (origin as ExtensionsRepoStateProvider).itemType;
|
||||
}
|
||||
|
||||
String _$autoUpdateExtensionsStateHash() =>
|
||||
r'30ce3c558504e005f9c85e2fc969ab7a581510cd';
|
||||
|
||||
|
|
|
|||
308
lib/modules/more/settings/browse/source_repositories.dart
Normal file
308
lib/modules/more/settings/browse/source_repositories.dart
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/eval/model/m_bridge.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
||||
class SourceRepositories extends ConsumerStatefulWidget {
|
||||
final ItemType itemType;
|
||||
const SourceRepositories({required this.itemType, super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<SourceRepositories> createState() => _SourceRepositoriesState();
|
||||
}
|
||||
|
||||
class _SourceRepositoriesState extends ConsumerState<SourceRepositories> {
|
||||
List<Repo> _entries = [];
|
||||
String urlInput = "";
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = l10nLocalizations(context)!;
|
||||
final repositories =
|
||||
ref.watch(extensionsRepoStateProvider(widget.itemType));
|
||||
final data = AsyncValue.data(repositories);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: switch (widget.itemType) {
|
||||
ItemType.manga => Text(l10n.manage_manga_repo_urls),
|
||||
ItemType.anime => Text(l10n.manage_anime_repo_urls),
|
||||
_ => Text(l10n.manage_novel_repo_urls)
|
||||
},
|
||||
),
|
||||
body: data.when(
|
||||
data: (data) {
|
||||
if (data.isEmpty) {
|
||||
_entries = [];
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
l10n.empty_extensions_repo,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
_entries = data;
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: _entries.length,
|
||||
itemBuilder: (context, index) {
|
||||
final repo = _entries[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: Card(
|
||||
child: Column(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(0),
|
||||
bottomRight: Radius.circular(0),
|
||||
topRight: Radius.circular(10),
|
||||
topLeft: Radius.circular(10)))),
|
||||
onPressed: () {},
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
const Icon(Icons.label_outline_rounded),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Expanded(child: Text(repo.name ?? repo.jsonUrl!))
|
||||
],
|
||||
)),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
l10n.remove_extensions_repo,
|
||||
),
|
||||
content: Text(l10n
|
||||
.remove_extensions_repo),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context);
|
||||
},
|
||||
child: Text(
|
||||
l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
final mangaRepos = ref
|
||||
.read(extensionsRepoStateProvider(
|
||||
widget
|
||||
.itemType))
|
||||
.toList();
|
||||
mangaRepos.removeWhere(
|
||||
(url) =>
|
||||
url ==
|
||||
_entries[
|
||||
index]);
|
||||
ref
|
||||
.read(extensionsRepoStateProvider(
|
||||
widget
|
||||
.itemType)
|
||||
.notifier)
|
||||
.set(
|
||||
mangaRepos);
|
||||
ref.watch(
|
||||
extensionsRepoStateProvider(
|
||||
widget
|
||||
.itemType));
|
||||
if (context
|
||||
.mounted) {
|
||||
Navigator.pop(
|
||||
context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.ok,
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.delete_outlined))
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
error: (Object error, StackTrace stackTrace) {
|
||||
_entries = [];
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
l10n.empty_extensions_repo,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
loading: () {
|
||||
return const ProgressCenter();
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () {
|
||||
final controller = TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return SizedBox(
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return AlertDialog(
|
||||
title: Text(l10n.add_extensions_repo),
|
||||
content: TextFormField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
keyboardType: TextInputType.url,
|
||||
onChanged: (value) => setState(() {}),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return l10n.url_cannot_be_empty;
|
||||
}
|
||||
if (!value.endsWith('.json')) {
|
||||
return l10n.url_must_end_with_dot_json;
|
||||
}
|
||||
try {
|
||||
final uri = Uri.parse(value);
|
||||
if (!uri.isAbsolute) {
|
||||
return l10n.invalid_url_format;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
return l10n.invalid_url_format;
|
||||
}
|
||||
},
|
||||
autovalidateMode:
|
||||
AutovalidateMode.onUserInteraction,
|
||||
decoration: InputDecoration(
|
||||
hintText: l10n.url_must_end_with_dot_json,
|
||||
filled: false,
|
||||
contentPadding: const EdgeInsets.all(12),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(width: 0.4),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(),
|
||||
borderRadius: BorderRadius.circular(5)),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
borderSide: const BorderSide()))),
|
||||
actions: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(l10n.cancel)),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: controller.text.isEmpty ||
|
||||
!controller.text.endsWith(".json")
|
||||
? null
|
||||
: () async {
|
||||
try {
|
||||
final mangaRepos = ref
|
||||
.read(
|
||||
extensionsRepoStateProvider(
|
||||
widget.itemType))
|
||||
.toList();
|
||||
final repo = await ref.read(
|
||||
getRepoInfosProvider(
|
||||
jsonUrl:
|
||||
controller.text)
|
||||
.future);
|
||||
mangaRepos.add(repo);
|
||||
ref
|
||||
.read(
|
||||
extensionsRepoStateProvider(
|
||||
widget.itemType)
|
||||
.notifier)
|
||||
.set(mangaRepos);
|
||||
ref.invalidate(
|
||||
extensionsRepoStateProvider(
|
||||
widget.itemType));
|
||||
} catch (e) {
|
||||
botToast(e.toString());
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
l10n.add,
|
||||
style: TextStyle(
|
||||
color: controller.text.isEmpty ||
|
||||
!controller.text
|
||||
.endsWith(".json")
|
||||
? Theme.of(context)
|
||||
.primaryColor
|
||||
.withValues(alpha: 0.2)
|
||||
: null),
|
||||
)),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
label: Row(
|
||||
children: [
|
||||
const Icon(Icons.add),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(l10n.add)
|
||||
],
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@ import 'package:mangayomi/modules/browse/sources/sources_filter_screen.dart';
|
|||
import 'package:mangayomi/modules/more/data_and_storage/create_backup.dart';
|
||||
import 'package:mangayomi/modules/more/data_and_storage/data_and_storage.dart';
|
||||
import 'package:mangayomi/modules/more/settings/appearance/custom_navigation_settings.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/source_repositories.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart';
|
||||
import 'package:mangayomi/modules/novel/novel_reader_view.dart';
|
||||
import 'package:mangayomi/modules/updates/updates_screen.dart';
|
||||
import 'package:mangayomi/modules/more/categories/categories_screen.dart';
|
||||
|
|
@ -49,10 +51,11 @@ final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
|||
@riverpod
|
||||
GoRouter router(Ref ref) {
|
||||
final router = RouterNotifier();
|
||||
final initLocation = ref.watch(navigationOrderStateProvider).first;
|
||||
|
||||
return GoRouter(
|
||||
observers: [BotToastNavigatorObserver()],
|
||||
initialLocation: '/MangaLibrary',
|
||||
initialLocation: initLocation,
|
||||
debugLogDiagnostics: kDebugMode,
|
||||
refreshListenable: router,
|
||||
routes: router._routes,
|
||||
|
|
@ -487,6 +490,25 @@ class RouterNotifier extends ChangeNotifier {
|
|||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/SourceRepositories",
|
||||
name: "SourceRepositories",
|
||||
builder: (context, state) {
|
||||
final itemType = state.extra as ItemType;
|
||||
return SourceRepositories(
|
||||
itemType: itemType,
|
||||
);
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
final itemType = state.extra as ItemType;
|
||||
return transitionPage(
|
||||
key: state.pageKey,
|
||||
child: SourceRepositories(
|
||||
itemType: itemType,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/downloads",
|
||||
name: "downloads",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'router.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$routerHash() => r'898ce90fa3d611eeb9ada09b0b29672c5accb22a';
|
||||
String _$routerHash() => r'7a4e8651b0f12561ff4be5ca85a0142ab64a3da3';
|
||||
|
||||
/// See also [router].
|
||||
@ProviderFor(router)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/services/fetch_sources_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -6,14 +7,17 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
part 'fetch_anime_sources.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future fetchAnimeSourcesList(Ref ref, {int? id, required bool reFresh}) async {
|
||||
Future<void> fetchAnimeSourcesList(Ref ref,
|
||||
{int? id, required bool reFresh}) async {
|
||||
if (ref.watch(checkForExtensionsUpdateStateProvider) || reFresh) {
|
||||
await fetchSourcesList(
|
||||
sourcesIndexUrl:
|
||||
"",
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.anime);
|
||||
final repos = ref.watch(extensionsRepoStateProvider(ItemType.anime));
|
||||
for (Repo repo in repos) {
|
||||
await fetchSourcesList(
|
||||
repo: repo,
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.anime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'fetch_anime_sources.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$fetchAnimeSourcesListHash() =>
|
||||
r'34db8fac67fb2d445645e62adc68b6d13d481897';
|
||||
r'e7f673d37239c74f3403de3a234bbc1d6e171332';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -35,7 +35,7 @@ class _SystemHash {
|
|||
const fetchAnimeSourcesListProvider = FetchAnimeSourcesListFamily();
|
||||
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
class FetchAnimeSourcesListFamily extends Family<AsyncValue> {
|
||||
class FetchAnimeSourcesListFamily extends Family<AsyncValue<void>> {
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
const FetchAnimeSourcesListFamily();
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ class FetchAnimeSourcesListFamily extends Family<AsyncValue> {
|
|||
}
|
||||
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
class FetchAnimeSourcesListProvider extends FutureProvider<Object?> {
|
||||
class FetchAnimeSourcesListProvider extends FutureProvider<void> {
|
||||
/// See also [fetchAnimeSourcesList].
|
||||
FetchAnimeSourcesListProvider({
|
||||
int? id,
|
||||
|
|
@ -116,7 +116,7 @@ class FetchAnimeSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Object?> Function(FetchAnimeSourcesListRef provider) create,
|
||||
FutureOr<void> Function(FetchAnimeSourcesListRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
|
|
@ -134,7 +134,7 @@ class FetchAnimeSourcesListProvider extends FutureProvider<Object?> {
|
|||
}
|
||||
|
||||
@override
|
||||
FutureProviderElement<Object?> createElement() {
|
||||
FutureProviderElement<void> createElement() {
|
||||
return _FetchAnimeSourcesListProviderElement(this);
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ class FetchAnimeSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin FetchAnimeSourcesListRef on FutureProviderRef<Object?> {
|
||||
mixin FetchAnimeSourcesListRef on FutureProviderRef<void> {
|
||||
/// The parameter `id` of this provider.
|
||||
int? get id;
|
||||
|
||||
|
|
@ -165,8 +165,8 @@ mixin FetchAnimeSourcesListRef on FutureProviderRef<Object?> {
|
|||
bool get reFresh;
|
||||
}
|
||||
|
||||
class _FetchAnimeSourcesListProviderElement
|
||||
extends FutureProviderElement<Object?> with FetchAnimeSourcesListRef {
|
||||
class _FetchAnimeSourcesListProviderElement extends FutureProviderElement<void>
|
||||
with FetchAnimeSourcesListRef {
|
||||
_FetchAnimeSourcesListProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/services/fetch_sources_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -6,14 +7,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
part 'fetch_manga_sources.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future fetchMangaSourcesList(Ref ref, {int? id, required reFresh}) async {
|
||||
Future<void> fetchMangaSourcesList(Ref ref, {int? id, required reFresh}) async {
|
||||
if (ref.watch(checkForExtensionsUpdateStateProvider) || reFresh) {
|
||||
await fetchSourcesList(
|
||||
sourcesIndexUrl:
|
||||
"",
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.manga);
|
||||
final repos = ref.watch(extensionsRepoStateProvider(ItemType.manga));
|
||||
for (Repo repo in repos) {
|
||||
await fetchSourcesList(
|
||||
repo: repo,
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.manga);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'fetch_manga_sources.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$fetchMangaSourcesListHash() =>
|
||||
r'b56d2a229f2d0a2ef4dc93d9f06cc8485dcd2285';
|
||||
r'176206caf5c51a94b100866d5cdb612d2a5c2fb7';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -35,7 +35,7 @@ class _SystemHash {
|
|||
const fetchMangaSourcesListProvider = FetchMangaSourcesListFamily();
|
||||
|
||||
/// See also [fetchMangaSourcesList].
|
||||
class FetchMangaSourcesListFamily extends Family<AsyncValue> {
|
||||
class FetchMangaSourcesListFamily extends Family<AsyncValue<void>> {
|
||||
/// See also [fetchMangaSourcesList].
|
||||
const FetchMangaSourcesListFamily();
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ class FetchMangaSourcesListFamily extends Family<AsyncValue> {
|
|||
}
|
||||
|
||||
/// See also [fetchMangaSourcesList].
|
||||
class FetchMangaSourcesListProvider extends FutureProvider<Object?> {
|
||||
class FetchMangaSourcesListProvider extends FutureProvider<void> {
|
||||
/// See also [fetchMangaSourcesList].
|
||||
FetchMangaSourcesListProvider({
|
||||
int? id,
|
||||
|
|
@ -116,7 +116,7 @@ class FetchMangaSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Object?> Function(FetchMangaSourcesListRef provider) create,
|
||||
FutureOr<void> Function(FetchMangaSourcesListRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
|
|
@ -134,7 +134,7 @@ class FetchMangaSourcesListProvider extends FutureProvider<Object?> {
|
|||
}
|
||||
|
||||
@override
|
||||
FutureProviderElement<Object?> createElement() {
|
||||
FutureProviderElement<void> createElement() {
|
||||
return _FetchMangaSourcesListProviderElement(this);
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ class FetchMangaSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin FetchMangaSourcesListRef on FutureProviderRef<Object?> {
|
||||
mixin FetchMangaSourcesListRef on FutureProviderRef<void> {
|
||||
/// The parameter `id` of this provider.
|
||||
int? get id;
|
||||
|
||||
|
|
@ -165,8 +165,8 @@ mixin FetchMangaSourcesListRef on FutureProviderRef<Object?> {
|
|||
dynamic get reFresh;
|
||||
}
|
||||
|
||||
class _FetchMangaSourcesListProviderElement
|
||||
extends FutureProviderElement<Object?> with FetchMangaSourcesListRef {
|
||||
class _FetchMangaSourcesListProviderElement extends FutureProviderElement<void>
|
||||
with FetchMangaSourcesListRef {
|
||||
_FetchMangaSourcesListProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/services/fetch_sources_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
|
@ -6,14 +7,16 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
part 'fetch_novel_sources.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
Future fetchNovelSourcesList(Ref ref, {int? id, required reFresh}) async {
|
||||
Future<void> fetchNovelSourcesList(Ref ref, {int? id, required reFresh}) async {
|
||||
if (ref.watch(checkForExtensionsUpdateStateProvider) || reFresh) {
|
||||
await fetchSourcesList(
|
||||
sourcesIndexUrl:
|
||||
"",
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.novel);
|
||||
final repos = ref.watch(extensionsRepoStateProvider(ItemType.novel));
|
||||
for (Repo repo in repos) {
|
||||
await fetchSourcesList(
|
||||
repo: repo,
|
||||
refresh: reFresh,
|
||||
id: id,
|
||||
ref: ref,
|
||||
itemType: ItemType.novel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'fetch_novel_sources.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$fetchNovelSourcesListHash() =>
|
||||
r'9a7afa9c301d2f4be51c074e5a81117f6d01352a';
|
||||
r'882ee56332290a6fe71d38a8378de847e4386e3a';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -35,7 +35,7 @@ class _SystemHash {
|
|||
const fetchNovelSourcesListProvider = FetchNovelSourcesListFamily();
|
||||
|
||||
/// See also [fetchNovelSourcesList].
|
||||
class FetchNovelSourcesListFamily extends Family<AsyncValue> {
|
||||
class FetchNovelSourcesListFamily extends Family<AsyncValue<void>> {
|
||||
/// See also [fetchNovelSourcesList].
|
||||
const FetchNovelSourcesListFamily();
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ class FetchNovelSourcesListFamily extends Family<AsyncValue> {
|
|||
}
|
||||
|
||||
/// See also [fetchNovelSourcesList].
|
||||
class FetchNovelSourcesListProvider extends FutureProvider<Object?> {
|
||||
class FetchNovelSourcesListProvider extends FutureProvider<void> {
|
||||
/// See also [fetchNovelSourcesList].
|
||||
FetchNovelSourcesListProvider({
|
||||
int? id,
|
||||
|
|
@ -116,7 +116,7 @@ class FetchNovelSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@override
|
||||
Override overrideWith(
|
||||
FutureOr<Object?> Function(FetchNovelSourcesListRef provider) create,
|
||||
FutureOr<void> Function(FetchNovelSourcesListRef provider) create,
|
||||
) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
|
|
@ -134,7 +134,7 @@ class FetchNovelSourcesListProvider extends FutureProvider<Object?> {
|
|||
}
|
||||
|
||||
@override
|
||||
FutureProviderElement<Object?> createElement() {
|
||||
FutureProviderElement<void> createElement() {
|
||||
return _FetchNovelSourcesListProviderElement(this);
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ class FetchNovelSourcesListProvider extends FutureProvider<Object?> {
|
|||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin FetchNovelSourcesListRef on FutureProviderRef<Object?> {
|
||||
mixin FetchNovelSourcesListRef on FutureProviderRef<void> {
|
||||
/// The parameter `id` of this provider.
|
||||
int? get id;
|
||||
|
||||
|
|
@ -165,8 +165,8 @@ mixin FetchNovelSourcesListRef on FutureProviderRef<Object?> {
|
|||
dynamic get reFresh;
|
||||
}
|
||||
|
||||
class _FetchNovelSourcesListProviderElement
|
||||
extends FutureProviderElement<Object?> with FetchNovelSourcesListRef {
|
||||
class _FetchNovelSourcesListProviderElement extends FutureProviderElement<void>
|
||||
with FetchNovelSourcesListRef {
|
||||
_FetchNovelSourcesListProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import 'package:isar/isar.dart';
|
|||
import 'package:mangayomi/eval/lib.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
|
|
@ -12,11 +13,14 @@ import 'package:package_info_plus/package_info_plus.dart';
|
|||
Future<void> fetchSourcesList(
|
||||
{int? id,
|
||||
required bool refresh,
|
||||
required String sourcesIndexUrl,
|
||||
required Ref ref,
|
||||
required ItemType itemType}) async {
|
||||
required ItemType itemType,
|
||||
required Repo? repo}) async {
|
||||
final http = MClient.init(reqcopyWith: {'useDartHttpClient': true});
|
||||
final req = await http.get(Uri.parse(sourcesIndexUrl));
|
||||
final url = repo?.jsonUrl;
|
||||
if (url == null) return;
|
||||
|
||||
final req = await http.get(Uri.parse(url));
|
||||
|
||||
final sourceList =
|
||||
(jsonDecode(req.body) as List).map((e) => Source.fromJson(e)).toList();
|
||||
|
|
@ -35,30 +39,33 @@ Future<void> fetchSourcesList(
|
|||
getExtensionService(source..sourceCode = req.body)
|
||||
.getHeaders();
|
||||
isar.writeTxnSync(() {
|
||||
isar.sources.putSync(sourc
|
||||
..headers = jsonEncode(headers)
|
||||
..isAdded = true
|
||||
..sourceCode = req.body
|
||||
..sourceCodeUrl = source.sourceCodeUrl
|
||||
..id = id
|
||||
..apiUrl = source.apiUrl
|
||||
..baseUrl = source.baseUrl
|
||||
..dateFormat = source.dateFormat
|
||||
..dateFormatLocale = source.dateFormatLocale
|
||||
..hasCloudflare = source.hasCloudflare
|
||||
..iconUrl = source.iconUrl
|
||||
..typeSource = source.typeSource
|
||||
..lang = source.lang
|
||||
..isNsfw = source.isNsfw
|
||||
..name = source.name
|
||||
..version = source.version
|
||||
..versionLast = source.version
|
||||
..itemType = itemType
|
||||
..isFullData = source.isFullData ?? false
|
||||
..appMinVerReq = source.appMinVerReq
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
..additionalParams = source.additionalParams ?? ""
|
||||
..isObsolete = false);
|
||||
isar.sources.putSync(
|
||||
sourc
|
||||
..headers = jsonEncode(headers)
|
||||
..isAdded = true
|
||||
..sourceCode = req.body
|
||||
..sourceCodeUrl = source.sourceCodeUrl
|
||||
..id = id
|
||||
..apiUrl = source.apiUrl
|
||||
..baseUrl = source.baseUrl
|
||||
..dateFormat = source.dateFormat
|
||||
..dateFormatLocale = source.dateFormatLocale
|
||||
..hasCloudflare = source.hasCloudflare
|
||||
..iconUrl = source.iconUrl
|
||||
..typeSource = source.typeSource
|
||||
..lang = source.lang
|
||||
..isNsfw = source.isNsfw
|
||||
..name = source.name
|
||||
..version = source.version
|
||||
..versionLast = source.version
|
||||
..itemType = itemType
|
||||
..isFullData = source.isFullData ?? false
|
||||
..appMinVerReq = source.appMinVerReq
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
..additionalParams = source.additionalParams ?? ""
|
||||
..isObsolete = false
|
||||
..repo = repo,
|
||||
);
|
||||
});
|
||||
// log("successfully installed or updated");
|
||||
}
|
||||
|
|
@ -98,7 +105,8 @@ Future<void> fetchSourcesList(
|
|||
..appMinVerReq = source.appMinVerReq
|
||||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
..additionalParams = source.additionalParams ?? ""
|
||||
..isObsolete = false);
|
||||
..isObsolete = false
|
||||
..repo = repo);
|
||||
});
|
||||
} else {
|
||||
// log("update aivalable");
|
||||
|
|
@ -127,7 +135,8 @@ Future<void> fetchSourcesList(
|
|||
..sourceCodeLanguage = source.sourceCodeLanguage
|
||||
..isFullData = source.isFullData ?? false
|
||||
..appMinVerReq = source.appMinVerReq
|
||||
..isObsolete = false);
|
||||
..isObsolete = false
|
||||
..repo = repo);
|
||||
// log("new source");
|
||||
}
|
||||
}
|
||||
|
|
@ -153,21 +162,6 @@ void checkIfSourceIsObsolete(List<Source> sourceList, ItemType itemType) {
|
|||
}
|
||||
}
|
||||
}
|
||||
removeNsfwObsoleteSources();
|
||||
}
|
||||
|
||||
void removeNsfwObsoleteSources() {
|
||||
final ids = isar.sources
|
||||
.filter()
|
||||
.idIsNotNull()
|
||||
.isNsfwEqualTo(true)
|
||||
.isObsoleteEqualTo(true)
|
||||
.findAllSync()
|
||||
.map((e) => e.id!)
|
||||
.toList();
|
||||
isar.writeTxnSync(() {
|
||||
isar.sources.deleteAllSync(ids);
|
||||
});
|
||||
}
|
||||
|
||||
int compareVersions(String version1, String version2) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue