mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 20:12:00 +00:00
add chapter download module
This commit is contained in:
parent
054fa0642c
commit
35b01b51c3
23 changed files with 1021 additions and 100 deletions
|
|
@ -47,7 +47,7 @@ android {
|
||||||
applicationId "com.kodjodevf.mangayomi"
|
applicationId "com.kodjodevf.mangayomi"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdkVersion 21
|
minSdkVersion 24
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdkVersion flutter.targetSdkVersion
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.kodjodevf.mangayomi">
|
package="com.kodjodevf.mangayomi">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||||
<application
|
<application
|
||||||
android:label="mangayomi"
|
android:label="mangayomi"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.10'
|
ext.kotlin_version = '1.8.0'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import 'package:mangayomi/models/manga_history.dart';
|
||||||
import 'package:mangayomi/models/model_manga.dart';
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
import 'package:mangayomi/router/router.dart';
|
import 'package:mangayomi/router/router.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/source/source_model.dart';
|
||||||
|
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||||
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
||||||
import 'package:mangayomi/views/more/settings/appearance/providers/blend_level_state_provider.dart';
|
import 'package:mangayomi/views/more/settings/appearance/providers/blend_level_state_provider.dart';
|
||||||
import 'views/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
import 'views/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
||||||
|
|
@ -35,10 +36,12 @@ void main() async {
|
||||||
Hive.registerAdapter(SourceModelAdapter());
|
Hive.registerAdapter(SourceModelAdapter());
|
||||||
Hive.registerAdapter(ReaderModeAdapter());
|
Hive.registerAdapter(ReaderModeAdapter());
|
||||||
Hive.registerAdapter(TypeSourceAdapter());
|
Hive.registerAdapter(TypeSourceAdapter());
|
||||||
|
Hive.registerAdapter(DownloadModelAdapter());
|
||||||
await Hive.openBox<ModelManga>(HiveConstant.hiveBoxManga);
|
await Hive.openBox<ModelManga>(HiveConstant.hiveBoxManga);
|
||||||
await Hive.openBox<MangaHistoryModel>(HiveConstant.hiveBoxMangaHistory);
|
await Hive.openBox<MangaHistoryModel>(HiveConstant.hiveBoxMangaHistory);
|
||||||
await Hive.openBox<ReaderMode>(HiveConstant.hiveBoxReaderMode);
|
await Hive.openBox<ReaderMode>(HiveConstant.hiveBoxReaderMode);
|
||||||
await Hive.openBox<SourceModel>(HiveConstant.hiveBoxMangaSource);
|
await Hive.openBox<SourceModel>(HiveConstant.hiveBoxMangaSource);
|
||||||
|
await Hive.openBox<DownloadModel>(HiveConstant.hiveBoxDownloads);
|
||||||
await Hive.openBox(HiveConstant.hiveBoxMangaInfo);
|
await Hive.openBox(HiveConstant.hiveBoxMangaInfo);
|
||||||
await Hive.openBox(HiveConstant.hiveBoxMangaFilter);
|
await Hive.openBox(HiveConstant.hiveBoxMangaFilter);
|
||||||
await Hive.openBox(HiveConstant.hiveBoxAppSettings);
|
await Hive.openBox(HiveConstant.hiveBoxAppSettings);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'package:mangayomi/utils/constant.dart';
|
||||||
import 'package:mangayomi/models/manga_history.dart';
|
import 'package:mangayomi/models/manga_history.dart';
|
||||||
import 'package:mangayomi/models/model_manga.dart';
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/source/source_model.dart';
|
||||||
|
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||||
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
||||||
|
|
||||||
final hiveBoxManga = Provider<Box<ModelManga>>((ref) {
|
final hiveBoxManga = Provider<Box<ModelManga>>((ref) {
|
||||||
|
|
@ -27,6 +28,10 @@ final hiveBoxMangaFilterProvider = Provider<Box>((ref) {
|
||||||
final hiveBoxMangaSourceProvider = Provider<Box<SourceModel>>((ref) {
|
final hiveBoxMangaSourceProvider = Provider<Box<SourceModel>>((ref) {
|
||||||
return Hive.box<SourceModel>(HiveConstant.hiveBoxMangaSource);
|
return Hive.box<SourceModel>(HiveConstant.hiveBoxMangaSource);
|
||||||
});
|
});
|
||||||
|
final hiveBoxMangaDownloads = Provider<Box<DownloadModel>>((ref) {
|
||||||
|
return Hive.box<DownloadModel>(HiveConstant.hiveBoxDownloads);
|
||||||
|
});
|
||||||
|
|
||||||
final hiveBoxSettings = Provider<Box>((ref) {
|
final hiveBoxSettings = Provider<Box>((ref) {
|
||||||
return Hive.box(HiveConstant.hiveBoxAppSettings);
|
return Hive.box(HiveConstant.hiveBoxAppSettings);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
49
lib/providers/storage_provider.dart
Normal file
49
lib/providers/storage_provider.dart
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
// ignore_for_file: depend_on_referenced_packages
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
class StorageProvider {
|
||||||
|
Future<bool> requestPermission() async {
|
||||||
|
Permission permission = Permission.manageExternalStorage;
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
|
if (await permission.isGranted) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
final result = await permission.request();
|
||||||
|
if (result == PermissionStatus.granted) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Directory?> getDirectory() async {
|
||||||
|
Directory? directory;
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
directory = Directory("/storage/emulated/0/Mangayomi/");
|
||||||
|
} else {
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
directory = Directory("${dir.path}/Mangayomi");
|
||||||
|
}
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Directory?> getMangaChapterDirectory(
|
||||||
|
ModelManga modelManga, index) async {
|
||||||
|
final dir = await getDirectory();
|
||||||
|
return Directory(
|
||||||
|
"${dir!.path}/downloads/${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${modelManga.chapterTitle![index].replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Directory?> getMangaMainDirectory(ModelManga modelManga, index) async {
|
||||||
|
final dir = await getDirectory();
|
||||||
|
return Directory(
|
||||||
|
"${dir!.path}/downloads/${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -8,11 +8,11 @@ import 'package:html/dom.dart' as dom;
|
||||||
import 'package:mangayomi/models/comick/chapter_page_comick.dart';
|
import 'package:mangayomi/models/comick/chapter_page_comick.dart';
|
||||||
import 'package:mangayomi/models/model_manga.dart';
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
import 'package:mangayomi/providers/hive_provider.dart';
|
import 'package:mangayomi/providers/hive_provider.dart';
|
||||||
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||||
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
import 'package:mangayomi/services/http_res_to_dom_html.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/source/source_model.dart';
|
||||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:flutter_js/flutter_js.dart';
|
import 'package:flutter_js/flutter_js.dart';
|
||||||
part 'get_manga_chapter_url.g.dart';
|
part 'get_manga_chapter_url.g.dart';
|
||||||
|
|
@ -36,15 +36,7 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
||||||
"${modelManga.source}/${modelManga.name}/${modelManga.chapterTitle![index]}-pageurl",
|
"${modelManga.source}/${modelManga.name}/${modelManga.chapterTitle![index]}-pageurl",
|
||||||
defaultValue: []);
|
defaultValue: []);
|
||||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||||
Directory? pathh;
|
path = await StorageProvider().getMangaChapterDirectory(modelManga, index);
|
||||||
if (Platform.isAndroid || Platform.isIOS) {
|
|
||||||
pathh = await getExternalStorageDirectory();
|
|
||||||
} else {
|
|
||||||
pathh = await getApplicationDocumentsDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
path = Directory(
|
|
||||||
"${pathh!.path}/${modelManga.source}/${modelManga.name}/${modelManga.chapterTitle![index]}/");
|
|
||||||
|
|
||||||
if (hiveUrl.isNotEmpty) {
|
if (hiveUrl.isNotEmpty) {
|
||||||
urll = hiveUrl;
|
urll = hiveUrl;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'search_manga.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$searchMangaHash() => r'e84374580686773aa67deb76ab91c00e2e6fab8b';
|
String _$searchMangaHash() => r'6cb4c0eaa232a0c2b54a2c8f4841d3acfffacd40';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ class HiveConstant {
|
||||||
static String get hiveBoxMangaSource => "_manga_box_source_";
|
static String get hiveBoxMangaSource => "_manga_box_source_";
|
||||||
static String get hiveBoxMangaFilter => "_manga_box_filter_";
|
static String get hiveBoxMangaFilter => "_manga_box_filter_";
|
||||||
static String get hiveBoxAppSettings => "_app_box_settings_";
|
static String get hiveBoxAppSettings => "_app_box_settings_";
|
||||||
|
static String get hiveBoxDownloads => "_manga_box_downloads_";
|
||||||
static String get hiveBoxReaderSettings => "_reader_box_settings_";
|
static String get hiveBoxReaderSettings => "_reader_box_settings_";
|
||||||
static String get hiveBoxReaderMode =>
|
static String get hiveBoxReaderMode => "_readerMode_box_settings_";
|
||||||
"_readerMode_box_settings_";
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Map<String, String>? headers(String source) {
|
Map<String, String> headers(String source) {
|
||||||
return source == 'mangakawaii'
|
return source == 'mangakawaii'
|
||||||
? {
|
? {
|
||||||
'Referer': 'https://www.mangakawaii.io/',
|
'Referer': 'https://www.mangakawaii.io/',
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/source/source_model.dart';
|
||||||
import 'package:mangayomi/views/browse/extension/extension_screen.dart';
|
import 'package:mangayomi/views/browse/extension/extension_screen.dart';
|
||||||
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
||||||
|
|
@ -22,16 +23,22 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||||
_tabBarController = TabController(length: 3, vsync: this);
|
_tabBarController = TabController(length: 3, vsync: this);
|
||||||
_tabBarController.animateTo(0);
|
_tabBarController.animateTo(0);
|
||||||
_tabBarController.addListener(() {
|
_tabBarController.addListener(() {
|
||||||
|
_chekPermission();
|
||||||
setState(() {
|
setState(() {
|
||||||
_textEditingController.clear();
|
_textEditingController.clear();
|
||||||
|
_entriesFilter = [];
|
||||||
_isSearch = false;
|
_isSearch = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SourceModel> entries = [];
|
_chekPermission() async {
|
||||||
List<SourceModel> entriesFilter = [];
|
await StorageProvider().requestPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SourceModel> _entries = [];
|
||||||
|
List<SourceModel> _entriesFilter = [];
|
||||||
final _textEditingController = TextEditingController();
|
final _textEditingController = TextEditingController();
|
||||||
bool _isSearch = false;
|
bool _isSearch = false;
|
||||||
@override
|
@override
|
||||||
|
|
@ -52,7 +59,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||||
? SeachFormTextField(
|
? SeachFormTextField(
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
entriesFilter = entries
|
_entriesFilter = _entries
|
||||||
.where((element) => element.sourceName
|
.where((element) => element.sourceName
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.contains(value.toLowerCase()))
|
.contains(value.toLowerCase()))
|
||||||
|
|
@ -67,7 +74,7 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||||
_isSearch = false;
|
_isSearch = false;
|
||||||
});
|
});
|
||||||
_textEditingController.clear();
|
_textEditingController.clear();
|
||||||
entriesFilter = entries;
|
_entriesFilter = _entries;
|
||||||
},
|
},
|
||||||
controller: _textEditingController,
|
controller: _textEditingController,
|
||||||
)
|
)
|
||||||
|
|
@ -122,9 +129,9 @@ class _BrowseScreenState extends State<BrowseScreen>
|
||||||
const SourcesScreen(),
|
const SourcesScreen(),
|
||||||
ExtensionScreen(
|
ExtensionScreen(
|
||||||
entriesData: (val) {
|
entriesData: (val) {
|
||||||
entries = val as List<SourceModel>;
|
_entries = val as List<SourceModel>;
|
||||||
},
|
},
|
||||||
entriesFilter: entriesFilter,
|
entriesFilter: _entriesFilter,
|
||||||
),
|
),
|
||||||
const MigrateScreen()
|
const MigrateScreen()
|
||||||
]),
|
]),
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@ import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:mangayomi/models/manga_reader.dart';
|
import 'package:mangayomi/models/manga_reader.dart';
|
||||||
import 'package:mangayomi/models/model_manga.dart';
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
import 'package:mangayomi/utils/cached_network.dart';
|
import 'package:mangayomi/utils/cached_network.dart';
|
||||||
import 'package:mangayomi/utils/media_query.dart';
|
import 'package:mangayomi/utils/media_query.dart';
|
||||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||||
import 'package:mangayomi/views/manga/detail/readmore.dart';
|
import 'package:mangayomi/views/manga/detail/readmore.dart';
|
||||||
|
import 'package:mangayomi/views/manga/download/download_page_widget.dart';
|
||||||
|
|
||||||
class MangaDetailView extends ConsumerStatefulWidget {
|
class MangaDetailView extends ConsumerStatefulWidget {
|
||||||
final Function(bool) isExtended;
|
final Function(bool) isExtended;
|
||||||
|
|
@ -169,13 +169,12 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
||||||
modelManga: widget.modelManga!,
|
modelManga: widget.modelManga!,
|
||||||
index: reverse ? reverseIndex : finalIndex);
|
index: reverse ? reverseIndex : finalIndex);
|
||||||
},
|
},
|
||||||
trailing: const Icon(
|
trailing: ref.watch(ChapterPageDownloadsProvider(
|
||||||
FontAwesomeIcons.circleDown,
|
index: reverse ? reverseIndex : finalIndex,
|
||||||
size: 20,
|
modelManga: widget.modelManga!)),
|
||||||
),
|
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
chapterDate[finalIndex],
|
chapterDate[finalIndex],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 11),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
chapterTitle[finalIndex],
|
chapterTitle[finalIndex],
|
||||||
|
|
|
||||||
32
lib/views/manga/download/download_model.dart
Normal file
32
lib/views/manga/download/download_model.dart
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
|
part 'download_model.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: 6)
|
||||||
|
class DownloadModel {
|
||||||
|
@HiveField(0)
|
||||||
|
final ModelManga modelManga;
|
||||||
|
@HiveField(1)
|
||||||
|
final int index;
|
||||||
|
@HiveField(2)
|
||||||
|
final int succeeded;
|
||||||
|
@HiveField(3)
|
||||||
|
final int failed;
|
||||||
|
@HiveField(4)
|
||||||
|
final int total;
|
||||||
|
@HiveField(6)
|
||||||
|
final bool isDownload;
|
||||||
|
@HiveField(7)
|
||||||
|
final List taskIds;
|
||||||
|
@HiveField(8)
|
||||||
|
final bool isStartDownload;
|
||||||
|
DownloadModel(
|
||||||
|
{required this.modelManga,
|
||||||
|
required this.succeeded,
|
||||||
|
required this.failed,
|
||||||
|
required this.index,
|
||||||
|
required this.total,
|
||||||
|
required this.isDownload,
|
||||||
|
required this.taskIds,
|
||||||
|
required this.isStartDownload});
|
||||||
|
}
|
||||||
62
lib/views/manga/download/download_model.g.dart
Normal file
62
lib/views/manga/download/download_model.g.dart
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'download_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// TypeAdapterGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
class DownloadModelAdapter extends TypeAdapter<DownloadModel> {
|
||||||
|
@override
|
||||||
|
final int typeId = 6;
|
||||||
|
|
||||||
|
@override
|
||||||
|
DownloadModel read(BinaryReader reader) {
|
||||||
|
final numOfFields = reader.readByte();
|
||||||
|
final fields = <int, dynamic>{
|
||||||
|
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
||||||
|
};
|
||||||
|
return DownloadModel(
|
||||||
|
modelManga: fields[0] as ModelManga,
|
||||||
|
succeeded: fields[2] as int,
|
||||||
|
failed: fields[3] as int,
|
||||||
|
index: fields[1] as int,
|
||||||
|
total: fields[4] as int,
|
||||||
|
isDownload: fields[6] as bool,
|
||||||
|
taskIds: (fields[7] as List).cast<dynamic>(),
|
||||||
|
isStartDownload: fields[8] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void write(BinaryWriter writer, DownloadModel obj) {
|
||||||
|
writer
|
||||||
|
..writeByte(8)
|
||||||
|
..writeByte(0)
|
||||||
|
..write(obj.modelManga)
|
||||||
|
..writeByte(1)
|
||||||
|
..write(obj.index)
|
||||||
|
..writeByte(2)
|
||||||
|
..write(obj.succeeded)
|
||||||
|
..writeByte(3)
|
||||||
|
..write(obj.failed)
|
||||||
|
..writeByte(4)
|
||||||
|
..write(obj.total)
|
||||||
|
..writeByte(6)
|
||||||
|
..write(obj.isDownload)
|
||||||
|
..writeByte(7)
|
||||||
|
..write(obj.taskIds)
|
||||||
|
..writeByte(8)
|
||||||
|
..write(obj.isStartDownload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => typeId.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) =>
|
||||||
|
identical(this, other) ||
|
||||||
|
other is DownloadModelAdapter &&
|
||||||
|
runtimeType == other.runtimeType &&
|
||||||
|
typeId == other.typeId;
|
||||||
|
}
|
||||||
489
lib/views/manga/download/download_page_widget.dart
Normal file
489
lib/views/manga/download/download_page_widget.dart
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
// ignore_for_file: implementation_imports, depend_on_referenced_packages
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
|
import 'package:mangayomi/models/model_manga.dart';
|
||||||
|
import 'package:mangayomi/providers/hive_provider.dart';
|
||||||
|
import 'package:mangayomi/services/get_manga_chapter_url.dart';
|
||||||
|
import 'package:mangayomi/utils/constant.dart';
|
||||||
|
import 'package:mangayomi/utils/headers.dart';
|
||||||
|
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
part 'download_page_widget.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
class ChapterPageDownloads extends _$ChapterPageDownloads {
|
||||||
|
@override
|
||||||
|
Widget build({required ModelManga modelManga, required int index}) {
|
||||||
|
return ChapterPageDownload(
|
||||||
|
index: index,
|
||||||
|
modelManga: modelManga,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChapterPageDownload extends ConsumerStatefulWidget {
|
||||||
|
final ModelManga modelManga;
|
||||||
|
final int index;
|
||||||
|
const ChapterPageDownload(
|
||||||
|
{super.key, required this.modelManga, required this.index});
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState createState() => _ChapterPageDownloadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
|
||||||
|
with AutomaticKeepAliveClientMixin<ChapterPageDownload> {
|
||||||
|
List _urll = [];
|
||||||
|
List<DownloadTask> tasks = [];
|
||||||
|
final StorageProvider _storageProvider = StorageProvider();
|
||||||
|
_startDownload() async {
|
||||||
|
await _storageProvider.requestPermission();
|
||||||
|
Directory? path;
|
||||||
|
bool isOk = false;
|
||||||
|
final path1 = await _storageProvider.getDirectory();
|
||||||
|
|
||||||
|
final finalPath =
|
||||||
|
"downloads/${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapterTitle![widget.index].replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}";
|
||||||
|
path = Directory(
|
||||||
|
"${path1!.path}downloads/${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapterTitle![widget.index].replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||||
|
ref
|
||||||
|
.read(getMangaChapterUrlProvider(
|
||||||
|
modelManga: widget.modelManga,
|
||||||
|
index: widget.index,
|
||||||
|
).future)
|
||||||
|
.then((value) {
|
||||||
|
if (value.urll.isNotEmpty) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_urll = value.urll;
|
||||||
|
isOk = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await Future.doWhile(() async {
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
if (isOk == true) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_urll.isNotEmpty) {
|
||||||
|
for (var index = 0; index < _urll.length; index++) {
|
||||||
|
final path2 = Directory("${path1.path}downloads/");
|
||||||
|
final path4 = Directory(
|
||||||
|
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/");
|
||||||
|
final path3 = Directory(
|
||||||
|
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||||
|
final path5 = Directory(
|
||||||
|
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapterTitle![widget.index].replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}");
|
||||||
|
|
||||||
|
if (!(await path1.exists())) {
|
||||||
|
path1.create();
|
||||||
|
}
|
||||||
|
if (!(await path2.exists())) {
|
||||||
|
path2.create();
|
||||||
|
}
|
||||||
|
if (!(await path4.exists())) {
|
||||||
|
path4.create();
|
||||||
|
}
|
||||||
|
if (!(await path3.exists())) {
|
||||||
|
path3.create();
|
||||||
|
}
|
||||||
|
if (!(await path5.exists())) {
|
||||||
|
path5.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((await path.exists())) {
|
||||||
|
if (await File("${path.path}" "${index + 1}.jpg").exists()) {
|
||||||
|
} else {
|
||||||
|
tasks.add(DownloadTask(
|
||||||
|
taskId: _urll[index],
|
||||||
|
headers: headers(widget.modelManga.source!),
|
||||||
|
url: _urll[index],
|
||||||
|
filename: "${index + 1}.jpg",
|
||||||
|
baseDirectory:
|
||||||
|
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||||
|
? BaseDirectory.applicationDocuments
|
||||||
|
: BaseDirectory.temporary,
|
||||||
|
directory:
|
||||||
|
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||||
|
? 'Mangayomi/$finalPath'
|
||||||
|
: finalPath,
|
||||||
|
updates: Updates.statusAndProgress,
|
||||||
|
allowPause: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path.create();
|
||||||
|
if (await File("${path.path}" "${index + 1}.jpg").exists()) {
|
||||||
|
} else {
|
||||||
|
tasks.add(DownloadTask(
|
||||||
|
taskId: _urll[index],
|
||||||
|
headers: headers(widget.modelManga.source!),
|
||||||
|
url: _urll[index],
|
||||||
|
filename: "${index + 1}.jpg",
|
||||||
|
baseDirectory:
|
||||||
|
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||||
|
? BaseDirectory.applicationDocuments
|
||||||
|
: BaseDirectory.temporary,
|
||||||
|
directory:
|
||||||
|
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||||
|
? 'Mangayomi/$finalPath'
|
||||||
|
: finalPath,
|
||||||
|
updates: Updates.statusAndProgress,
|
||||||
|
allowPause: true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tasks.isEmpty && _urll.isNotEmpty) {
|
||||||
|
final model = DownloadModel(
|
||||||
|
modelManga: widget.modelManga,
|
||||||
|
succeeded: 0,
|
||||||
|
failed: 0,
|
||||||
|
index: widget.index,
|
||||||
|
total: 0,
|
||||||
|
isDownload: true,
|
||||||
|
taskIds: _urll,
|
||||||
|
isStartDownload: false);
|
||||||
|
|
||||||
|
ref
|
||||||
|
.watch(hiveBoxMangaDownloads)
|
||||||
|
.put(widget.modelManga.chapterTitle![widget.index], model);
|
||||||
|
} else {
|
||||||
|
await FileDownloader().downloadBatch(
|
||||||
|
tasks,
|
||||||
|
batchProgressCallback: (succeeded, failed) {
|
||||||
|
final model = DownloadModel(
|
||||||
|
modelManga: widget.modelManga,
|
||||||
|
succeeded: succeeded,
|
||||||
|
failed: failed,
|
||||||
|
index: widget.index,
|
||||||
|
total: tasks.length,
|
||||||
|
isDownload: (succeeded == tasks.length) ? true : false,
|
||||||
|
taskIds: _urll,
|
||||||
|
isStartDownload: true);
|
||||||
|
|
||||||
|
Hive.box<DownloadModel>(HiveConstant.hiveBoxDownloads)
|
||||||
|
.put(widget.modelManga.chapterTitle![widget.index], model);
|
||||||
|
},
|
||||||
|
taskProgressCallback: (task, progress) async {
|
||||||
|
if (progress == 1.0) {
|
||||||
|
final downloadTask = DownloadTask(
|
||||||
|
creationTime: task.creationTime,
|
||||||
|
taskId: task.taskId,
|
||||||
|
headers: task.headers,
|
||||||
|
url: task.url,
|
||||||
|
filename: task.filename,
|
||||||
|
baseDirectory: task.baseDirectory,
|
||||||
|
directory: task.directory,
|
||||||
|
updates: task.updates,
|
||||||
|
allowPause: task.allowPause,
|
||||||
|
);
|
||||||
|
if (Platform.isAndroid || Platform.isIOS) {
|
||||||
|
await FileDownloader().moveToSharedStorage(
|
||||||
|
downloadTask, SharedStorage.external,
|
||||||
|
directory: finalPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_deleteFile(List pageUrl) async {
|
||||||
|
final path = await _storageProvider.getMangaChapterDirectory(
|
||||||
|
widget.modelManga, widget.index);
|
||||||
|
|
||||||
|
try {
|
||||||
|
path!.deleteSync(recursive: true);
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isStarted = false;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
|
return SizedBox(
|
||||||
|
height: 41,
|
||||||
|
width: 35,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 3),
|
||||||
|
child: ValueListenableBuilder<Box<DownloadModel>>(
|
||||||
|
valueListenable: ref.watch(hiveBoxMangaDownloads).listenable(),
|
||||||
|
builder: (context, val, child) {
|
||||||
|
final entries = val.values
|
||||||
|
.where((element) =>
|
||||||
|
element.modelManga.chapterTitle![element.index] ==
|
||||||
|
widget.modelManga.chapterTitle![widget.index])
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (entries.isNotEmpty) {
|
||||||
|
return entries.first.isDownload
|
||||||
|
? PopupMenuButton(
|
||||||
|
child: Icon(
|
||||||
|
size: 25,
|
||||||
|
Icons.check_circle,
|
||||||
|
color:
|
||||||
|
Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value.toString() == 'Delete') {
|
||||||
|
setState(() {
|
||||||
|
_isStarted = false;
|
||||||
|
});
|
||||||
|
_deleteFile(entries.first.taskIds);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
const PopupMenuItem(value: 'Send', child: Text("Send")),
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: 'Delete', child: Text('Delete')),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: entries.first.isStartDownload &&
|
||||||
|
entries.first.succeeded == 0
|
||||||
|
? SizedBox(
|
||||||
|
height: 41,
|
||||||
|
width: 35,
|
||||||
|
child: PopupMenuButton(
|
||||||
|
child: _downloadWidget(context, false),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value.toString() == 'Cancel') {
|
||||||
|
setState(() {
|
||||||
|
_isStarted = false;
|
||||||
|
});
|
||||||
|
List<String> taskIds = [];
|
||||||
|
for (var id in entries.first.taskIds) {
|
||||||
|
taskIds.add(id);
|
||||||
|
}
|
||||||
|
FileDownloader()
|
||||||
|
.cancelTasksWithIds(taskIds)
|
||||||
|
.then((value) async {
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(seconds: 2));
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga
|
||||||
|
.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: 'Cancel', child: Text("Cancel")),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
: entries.first.succeeded != 0
|
||||||
|
? SizedBox(
|
||||||
|
height: 41,
|
||||||
|
width: 35,
|
||||||
|
child: PopupMenuButton(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Icon(
|
||||||
|
Icons.arrow_downward_sharp,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.iconTheme
|
||||||
|
.color!
|
||||||
|
.withOpacity(0.7),
|
||||||
|
)),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: TweenAnimationBuilder<double>(
|
||||||
|
duration:
|
||||||
|
const Duration(milliseconds: 250),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
tween: Tween<double>(
|
||||||
|
begin: 0,
|
||||||
|
end: (entries.first.succeeded /
|
||||||
|
entries.first.total),
|
||||||
|
),
|
||||||
|
builder: (context, value, _) =>
|
||||||
|
SizedBox(
|
||||||
|
height: 2,
|
||||||
|
width: 2,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 19,
|
||||||
|
value: value,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.iconTheme
|
||||||
|
.color!
|
||||||
|
.withOpacity(0.7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Icon(
|
||||||
|
Icons.arrow_downward_sharp,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.scaffoldBackgroundColor,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value.toString() == 'Cancel') {
|
||||||
|
setState(() {
|
||||||
|
_isStarted = false;
|
||||||
|
});
|
||||||
|
List<String> taskIds = [];
|
||||||
|
for (var id in entries.first.taskIds) {
|
||||||
|
taskIds.add(id);
|
||||||
|
}
|
||||||
|
FileDownloader()
|
||||||
|
.cancelTasksWithIds(taskIds)
|
||||||
|
.then((value) async {
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(seconds: 2));
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga
|
||||||
|
.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: 'Cancel', child: Text("Cancel")),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
: entries.first.succeeded == 0
|
||||||
|
? IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
// _startDownload();
|
||||||
|
setState(() {
|
||||||
|
_isStarted = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
FontAwesomeIcons.circleDown,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.iconTheme
|
||||||
|
.color!
|
||||||
|
.withOpacity(0.7),
|
||||||
|
size: 25,
|
||||||
|
))
|
||||||
|
: SizedBox(
|
||||||
|
height: 50,
|
||||||
|
width: 50,
|
||||||
|
child: PopupMenuButton(
|
||||||
|
child: const Icon(
|
||||||
|
Icons.error_outline_outlined,
|
||||||
|
color: Colors.red,
|
||||||
|
size: 25,
|
||||||
|
),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value.toString() == 'Retry') {
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga
|
||||||
|
.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
_startDownload();
|
||||||
|
setState(() {
|
||||||
|
_isStarted = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: 'Retry', child: Text("Retry")),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return _isStarted
|
||||||
|
? SizedBox(
|
||||||
|
height: 50,
|
||||||
|
width: 50,
|
||||||
|
child: PopupMenuButton(
|
||||||
|
child: _downloadWidget(context, true),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value.toString() == 'Cancel') {
|
||||||
|
setState(() {
|
||||||
|
_isStarted = false;
|
||||||
|
});
|
||||||
|
List<String> taskIds = [];
|
||||||
|
for (var id in _urll) {
|
||||||
|
taskIds.add(id);
|
||||||
|
}
|
||||||
|
FileDownloader()
|
||||||
|
.cancelTasksWithIds(taskIds)
|
||||||
|
.then((value) async {
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
ref.watch(hiveBoxMangaDownloads).delete(
|
||||||
|
widget.modelManga.chapterTitle![widget.index],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (context) => [
|
||||||
|
const PopupMenuItem(
|
||||||
|
value: 'Cancel', child: Text("Cancel")),
|
||||||
|
],
|
||||||
|
))
|
||||||
|
: IconButton(
|
||||||
|
splashRadius: 5,
|
||||||
|
iconSize: 17,
|
||||||
|
onPressed: () {
|
||||||
|
_startDownload();
|
||||||
|
setState(() {
|
||||||
|
_isStarted = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: _downloadWidget(context, false),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _downloadWidget(BuildContext context, bool isLoading) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: Icon(
|
||||||
|
size: 18,
|
||||||
|
Icons.arrow_downward_sharp,
|
||||||
|
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||||
|
)),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 20,
|
||||||
|
width: 20,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
value: isLoading ? null : 1,
|
||||||
|
color: Theme.of(context).iconTheme.color!.withOpacity(0.7),
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
140
lib/views/manga/download/download_page_widget.g.dart
Normal file
140
lib/views/manga/download/download_page_widget.g.dart
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'download_page_widget.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
String _$chapterPageDownloadsHash() =>
|
||||||
|
r'0b3eaf9a3ca4786287616a87e5de62af24259b68';
|
||||||
|
|
||||||
|
/// 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _$ChapterPageDownloads
|
||||||
|
extends BuildlessAutoDisposeNotifier<Widget> {
|
||||||
|
late final ModelManga modelManga;
|
||||||
|
late final int index;
|
||||||
|
|
||||||
|
Widget build({
|
||||||
|
required ModelManga modelManga,
|
||||||
|
required int index,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
@ProviderFor(ChapterPageDownloads)
|
||||||
|
const chapterPageDownloadsProvider = ChapterPageDownloadsFamily();
|
||||||
|
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
class ChapterPageDownloadsFamily extends Family<Widget> {
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
const ChapterPageDownloadsFamily();
|
||||||
|
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
ChapterPageDownloadsProvider call({
|
||||||
|
required ModelManga modelManga,
|
||||||
|
required int index,
|
||||||
|
}) {
|
||||||
|
return ChapterPageDownloadsProvider(
|
||||||
|
modelManga: modelManga,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChapterPageDownloadsProvider getProviderOverride(
|
||||||
|
covariant ChapterPageDownloadsProvider provider,
|
||||||
|
) {
|
||||||
|
return call(
|
||||||
|
modelManga: provider.modelManga,
|
||||||
|
index: provider.index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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'chapterPageDownloadsProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
class ChapterPageDownloadsProvider
|
||||||
|
extends AutoDisposeNotifierProviderImpl<ChapterPageDownloads, Widget> {
|
||||||
|
/// See also [ChapterPageDownloads].
|
||||||
|
ChapterPageDownloadsProvider({
|
||||||
|
required this.modelManga,
|
||||||
|
required this.index,
|
||||||
|
}) : super.internal(
|
||||||
|
() => ChapterPageDownloads()
|
||||||
|
..modelManga = modelManga
|
||||||
|
..index = index,
|
||||||
|
from: chapterPageDownloadsProvider,
|
||||||
|
name: r'chapterPageDownloadsProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chapterPageDownloadsHash,
|
||||||
|
dependencies: ChapterPageDownloadsFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
ChapterPageDownloadsFamily._allTransitiveDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
|
final ModelManga modelManga;
|
||||||
|
final int index;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is ChapterPageDownloadsProvider &&
|
||||||
|
other.modelManga == modelManga &&
|
||||||
|
other.index == index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, index.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget runNotifierBuild(
|
||||||
|
covariant ChapterPageDownloads notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(
|
||||||
|
modelManga: modelManga,
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||||
|
|
@ -36,21 +36,53 @@ class ImageViewHorizontal extends StatefulWidget {
|
||||||
typedef DoubleClickAnimationListener = void Function();
|
typedef DoubleClickAnimationListener = void Function();
|
||||||
|
|
||||||
class _ImageViewHorizontalState extends State<ImageViewHorizontal> {
|
class _ImageViewHorizontalState extends State<ImageViewHorizontal> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_localCheck();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
_localCheck() async {
|
||||||
|
if (await File("${widget.path.path}" "${widget.index + 1}.jpg").exists()) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLocale = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLocale = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isLocale = false;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ExtendedImage.network(
|
return _isLocale
|
||||||
widget.url,
|
? ExtendedImage.file(
|
||||||
cache: true,
|
File("${widget.path.path}" "${widget.index + 1}.jpg"),
|
||||||
clearMemoryCacheWhenDispose: true,
|
clearMemoryCacheWhenDispose: true,
|
||||||
enableMemoryCache: false,
|
enableMemoryCache: false,
|
||||||
cacheMaxAge: const Duration(days: 7),
|
mode: ExtendedImageMode.gesture,
|
||||||
headers: headers(widget.source),
|
initGestureConfigHandler: widget.initGestureConfigHandler,
|
||||||
mode: ExtendedImageMode.gesture,
|
onDoubleTap: widget.onDoubleTap,
|
||||||
initGestureConfigHandler: widget.initGestureConfigHandler,
|
loadStateChanged: widget.loadStateChanged,
|
||||||
onDoubleTap: widget.onDoubleTap,
|
)
|
||||||
handleLoadingProgress: true,
|
: ExtendedImage.network(
|
||||||
loadStateChanged: widget.loadStateChanged,
|
widget.url,
|
||||||
);
|
cache: true,
|
||||||
|
clearMemoryCacheWhenDispose: true,
|
||||||
|
enableMemoryCache: false,
|
||||||
|
cacheMaxAge: const Duration(days: 7),
|
||||||
|
headers: headers(widget.source),
|
||||||
|
mode: ExtendedImageMode.gesture,
|
||||||
|
initGestureConfigHandler: widget.initGestureConfigHandler,
|
||||||
|
onDoubleTap: widget.onDoubleTap,
|
||||||
|
handleLoadingProgress: true,
|
||||||
|
loadStateChanged: widget.loadStateChanged,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,29 @@ class ImageViewVertical extends ConsumerStatefulWidget {
|
||||||
class _ImageViewVerticalState extends ConsumerState<ImageViewVertical>
|
class _ImageViewVerticalState extends ConsumerState<ImageViewVertical>
|
||||||
with AutomaticKeepAliveClientMixin<ImageViewVertical> {
|
with AutomaticKeepAliveClientMixin<ImageViewVertical> {
|
||||||
@override
|
@override
|
||||||
|
void initState() {
|
||||||
|
_localCheck();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
_localCheck() async {
|
||||||
|
if (await File("${widget.path.path}" "${widget.index + 1}.jpg").exists()) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLocale = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_isLocale = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isLocale = false;
|
||||||
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
return Container(
|
return Container(
|
||||||
|
|
@ -44,44 +67,57 @@ class _ImageViewVerticalState extends ConsumerState<ImageViewVertical>
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: MediaQuery.of(context).padding.top,
|
height: MediaQuery.of(context).padding.top,
|
||||||
),
|
),
|
||||||
ExtendedImage.network(widget.url,
|
_isLocale
|
||||||
headers: headers(widget.source),
|
? ExtendedImage.file(
|
||||||
handleLoadingProgress: true,
|
fit: BoxFit.contain,
|
||||||
fit: BoxFit.contain,
|
clearMemoryCacheWhenDispose: true,
|
||||||
cacheMaxAge: const Duration(days: 7),
|
enableMemoryCache: false,
|
||||||
clearMemoryCacheWhenDispose: true,
|
File('${widget.path.path}${widget.index + 1}.jpg'))
|
||||||
enableMemoryCache: false,
|
: ExtendedImage.network(widget.url,
|
||||||
loadStateChanged: (ExtendedImageState state) {
|
headers: headers(widget.source),
|
||||||
if (state.extendedImageLoadState == LoadState.loading) {
|
handleLoadingProgress: true,
|
||||||
final ImageChunkEvent? loadingProgress = state.loadingProgress;
|
fit: BoxFit.contain,
|
||||||
final double? progress =
|
cacheMaxAge: const Duration(days: 7),
|
||||||
loadingProgress?.expectedTotalBytes != null
|
clearMemoryCacheWhenDispose: true,
|
||||||
? loadingProgress!.cumulativeBytesLoaded /
|
enableMemoryCache: false,
|
||||||
loadingProgress.expectedTotalBytes!
|
loadStateChanged: (ExtendedImageState state) {
|
||||||
: null;
|
if (state.extendedImageLoadState == LoadState.loading) {
|
||||||
return SizedBox(
|
final ImageChunkEvent? loadingProgress =
|
||||||
height: mediaHeight(context, 0.5),
|
state.loadingProgress;
|
||||||
child: Center(
|
final double? progress =
|
||||||
child: CircularProgressIndicator(
|
loadingProgress?.expectedTotalBytes != null
|
||||||
value: progress,
|
? loadingProgress!.cumulativeBytesLoaded /
|
||||||
),
|
loadingProgress.expectedTotalBytes!
|
||||||
),
|
: null;
|
||||||
);
|
return Container(
|
||||||
}
|
color: Colors.black,
|
||||||
if (state.extendedImageLoadState == LoadState.failed) {
|
height: mediaHeight(context, 0.8),
|
||||||
return Center(
|
child: Center(
|
||||||
child: ElevatedButton(
|
child: CircularProgressIndicator(
|
||||||
onPressed: () {
|
value: progress,
|
||||||
state.reLoadImage();
|
),
|
||||||
},
|
),
|
||||||
child: const Icon(
|
);
|
||||||
Icons.replay_outlined,
|
}
|
||||||
size: 30,
|
if (state.extendedImageLoadState == LoadState.failed) {
|
||||||
)),
|
return Container(
|
||||||
);
|
color: Colors.black,
|
||||||
}
|
height: mediaHeight(context, 0.8),
|
||||||
return null;
|
child: Column(
|
||||||
}),
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
state.reLoadImage();
|
||||||
|
},
|
||||||
|
child: const Icon(
|
||||||
|
Icons.replay_outlined,
|
||||||
|
size: 30,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
if (widget.index + 1 == widget.length)
|
if (widget.index + 1 == widget.length)
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
|
|
@ -169,20 +169,20 @@ class _MangaChapterPageGalleryState
|
||||||
widget.readerController.setPageIndex(index);
|
widget.readerController.setPageIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAddButtonTapped(int ok, bool isPrev, {bool isSlide = false}) {
|
void _onAddButtonTapped(int index, bool isPrev, {bool isSlide = false}) {
|
||||||
if (isPrev) {
|
if (isPrev) {
|
||||||
if (_selectedValue == ReaderMode.verticalContinuous ||
|
if (_selectedValue == ReaderMode.verticalContinuous ||
|
||||||
_selectedValue == ReaderMode.webtoon) {
|
_selectedValue == ReaderMode.webtoon) {
|
||||||
if (ok != -1) {
|
if (index != -1) {
|
||||||
_itemScrollController.scrollTo(
|
_itemScrollController.scrollTo(
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
index: ok,
|
index: index,
|
||||||
duration: Duration(milliseconds: isSlide ? 2 : 150));
|
duration: Duration(milliseconds: isSlide ? 2 : 150));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ok != -1) {
|
if (index != -1) {
|
||||||
if (_extendedController.hasClients) {
|
if (_extendedController.hasClients) {
|
||||||
_extendedController.animateToPage(ok.toInt(),
|
_extendedController.animateToPage(index,
|
||||||
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
||||||
curve: Curves.ease);
|
curve: Curves.ease);
|
||||||
}
|
}
|
||||||
|
|
@ -191,16 +191,16 @@ class _MangaChapterPageGalleryState
|
||||||
} else {
|
} else {
|
||||||
if (_selectedValue == ReaderMode.verticalContinuous ||
|
if (_selectedValue == ReaderMode.verticalContinuous ||
|
||||||
_selectedValue == ReaderMode.webtoon) {
|
_selectedValue == ReaderMode.webtoon) {
|
||||||
if (widget.readerController.getPageLength(widget.url) != ok) {
|
if (widget.readerController.getPageLength(widget.url) != index) {
|
||||||
_itemScrollController.scrollTo(
|
_itemScrollController.scrollTo(
|
||||||
curve: Curves.ease,
|
curve: Curves.ease,
|
||||||
index: ok,
|
index: index,
|
||||||
duration: Duration(milliseconds: isSlide ? 2 : 150));
|
duration: Duration(milliseconds: isSlide ? 2 : 150));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (widget.readerController.getPageLength(widget.url) != ok) {
|
if (widget.readerController.getPageLength(widget.url) != index) {
|
||||||
if (_extendedController.hasClients) {
|
if (_extendedController.hasClients) {
|
||||||
_extendedController.animateToPage(ok.toInt(),
|
_extendedController.animateToPage(index.toInt(),
|
||||||
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
||||||
curve: Curves.ease);
|
curve: Curves.ease);
|
||||||
}
|
}
|
||||||
|
|
@ -923,7 +923,9 @@ class _MangaChapterPageGalleryState
|
||||||
reverse: _isReversHorizontal,
|
reverse: _isReversHorizontal,
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
canScrollPage: (GestureDetails? gestureDetails) {
|
canScrollPage: (GestureDetails? gestureDetails) {
|
||||||
return !(gestureDetails!.totalScale! > 1.0);
|
return gestureDetails != null
|
||||||
|
? !(gestureDetails.totalScale! > 1.0)
|
||||||
|
: true;
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return ImageViewHorizontal(
|
return ImageViewHorizontal(
|
||||||
|
|
@ -981,16 +983,21 @@ class _MangaChapterPageGalleryState
|
||||||
}
|
}
|
||||||
if (state.extendedImageLoadState ==
|
if (state.extendedImageLoadState ==
|
||||||
LoadState.failed) {
|
LoadState.failed) {
|
||||||
return Center(
|
return Container(
|
||||||
child: ElevatedButton(
|
color: Colors.black,
|
||||||
onPressed: () {
|
height: mediaHeight(context, 0.8),
|
||||||
state.reLoadImage();
|
child: Column(
|
||||||
},
|
children: [
|
||||||
child: const Icon(
|
ElevatedButton(
|
||||||
Icons.replay_outlined,
|
onPressed: () {
|
||||||
size: 30,
|
state.reLoadImage();
|
||||||
)),
|
},
|
||||||
);
|
child: const Icon(
|
||||||
|
Icons.replay_outlined,
|
||||||
|
size: 30,
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
));
|
||||||
}
|
}
|
||||||
return Container();
|
return Container();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
57
pubspec.lock
57
pubspec.lock
|
|
@ -41,6 +41,15 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.10.0"
|
version: "2.10.0"
|
||||||
|
background_downloader:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: HEAD
|
||||||
|
resolved-ref: "7b778222546d53fcd41a84f6aee90b87c2593930"
|
||||||
|
url: "https://github.com/kodjodevf/background_downloader.git"
|
||||||
|
source: git
|
||||||
|
version: "5.4.5"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -544,6 +553,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
|
localstore:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: localstore
|
||||||
|
sha256: "42a0afb7696cfab1b4bd7d08355b4ee01f975fd364553b28d51496eccaf11cce"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.5"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -688,6 +705,46 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.11.1"
|
version: "1.11.1"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
sha256: "33c6a1253d1f95fd06fa74b65b7ba907ae9811f9d5c1d3150e51417d04b8d6a8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.2.0"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
sha256: "8028362b40c4a45298f1cbfccd227c8dd6caf0e27088a69f2ba2ab15464159e2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.2.0"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
sha256: ee96ac32f5a8e6f80756e25b25b9f8e535816c8e6665a96b6d70681f8c4f7e85
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.8"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
sha256: "68abbc472002b5e6dfce47fe9898c6b7d8328d58b5d2524f75e277c07a97eb84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.9.0"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
sha256: f67cab14b4328574938ecea2db3475dad7af7ead6afab6338772c5f88963e38b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2"
|
||||||
photo_view:
|
photo_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,10 @@ dependencies:
|
||||||
# draggable_menu: ^0.2.0
|
# draggable_menu: ^0.2.0
|
||||||
url_launcher: ^6.1.10
|
url_launcher: ^6.1.10
|
||||||
package_info_plus: ^3.0.2
|
package_info_plus: ^3.0.2
|
||||||
|
background_downloader:
|
||||||
|
git:
|
||||||
|
url: https://github.com/kodjodevf/background_downloader.git
|
||||||
|
permission_handler: ^10.2.0
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,14 @@
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <flutter_js/flutter_js_plugin.h>
|
#include <flutter_js/flutter_js_plugin.h>
|
||||||
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
FlutterJsPluginRegisterWithRegistrar(
|
FlutterJsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterJsPlugin"));
|
registry->GetRegistrarForPlugin("FlutterJsPlugin"));
|
||||||
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
flutter_js
|
flutter_js
|
||||||
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue