diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6de00b03..91263606 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -46,6 +46,15 @@ + + + + + + + \ No newline at end of file diff --git a/lib/modules/more/about/providers/check_for_update.dart b/lib/modules/more/about/providers/check_for_update.dart index e2592cf7..1c7db29e 100644 --- a/lib/modules/more/about/providers/check_for_update.dart +++ b/lib/modules/more/about/providers/check_for_update.dart @@ -1,9 +1,9 @@ import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:mangayomi/modules/more/about/providers/download_file_screen.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/services/fetch_sources_list.dart'; import 'package:mangayomi/services/http/m_client.dart'; @@ -11,8 +11,6 @@ import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:device_info_plus/device_info_plus.dart'; part 'check_for_update.g.dart'; @riverpod @@ -30,14 +28,8 @@ Future checkForUpdate( if (kDebugMode) { log(info.data.toString()); } - if (Platform.isAndroid) { - final deviceInfo = DeviceInfoPlugin(); - final androidInfo = await deviceInfo.androidInfo; - print("DEBUG"); - print(androidInfo.supportedAbis.join(", ")); // x86_64, arm64-v8a - } final updateAvailable = await _checkUpdate(); - if (compareVersions(info.version, updateAvailable.$1) < 0) { + if (compareVersions(info.version, updateAvailable.$1) < 0 || true) { if (manualUpdate) { BotToast.showText(text: l10n.new_update_available); await Future.delayed(const Duration(seconds: 1)); @@ -46,32 +38,7 @@ Future checkForUpdate( showDialog( context: context, builder: (context) { - return AlertDialog( - title: Text(l10n.new_update_available), - content: Text( - "${l10n.app_version(updateAvailable.$1)}\n\n${updateAvailable.$2}", - ), - actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - onPressed: () { - Navigator.pop(context); - }, - child: Text(l10n.cancel), - ), - const SizedBox(width: 15), - ElevatedButton( - onPressed: () async { - _launchInBrowser(Uri.parse(updateAvailable.$3)); - }, - child: Text(l10n.download), - ), - ], - ), - ], - ); + return DownloadFileScreen(updateAvailable: updateAvailable); }, ); } @@ -82,13 +49,7 @@ Future checkForUpdate( } } -Future _launchInBrowser(Uri url) async { - if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { - throw 'Could not launch $url'; - } -} - -Future<(String, String, String)> _checkUpdate() async { +Future<(String, String, String, List)> _checkUpdate() async { final http = MClient.init(reqcopyWith: {'useDartHttpClient': true}); try { final res = await http.get( @@ -104,6 +65,10 @@ Future<(String, String, String)> _checkUpdate() async { .substringBefore('-'), resListJson.first["body"].toString(), resListJson.first["html_url"].toString(), + (resListJson.first["assets"] as List) + .map((asset) => asset["browser_download_url"]) + .toList() + as List, ); } catch (e) { rethrow; diff --git a/lib/modules/more/about/providers/download_file_screen.dart b/lib/modules/more/about/providers/download_file_screen.dart new file mode 100644 index 00000000..4cac9118 --- /dev/null +++ b/lib/modules/more/about/providers/download_file_screen.dart @@ -0,0 +1,119 @@ +import 'dart:io'; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_app_installer/flutter_app_installer.dart'; +import 'package:flutter_qjs/quickjs/ffi.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart' as http; +import 'package:mangayomi/providers/l10n_providers.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class DownloadFileScreen extends ConsumerStatefulWidget { + final (String, String, String, List) updateAvailable; + const DownloadFileScreen({required this.updateAvailable, super.key}); + + @override + ConsumerState createState() => _DownloadFileScreenState(); +} + +class _DownloadFileScreenState extends ConsumerState { + int _total = 0; + int _received = 0; + late http.StreamedResponse _response; + final List _bytes = []; + + @override + Widget build(BuildContext context) { + final l10n = l10nLocalizations(context)!; + final updateAvailable = widget.updateAvailable; + return AlertDialog( + title: Text(l10n.new_update_available), + content: Text( + "${l10n.app_version(updateAvailable.$1)}\n\n${updateAvailable.$2}", + ), + actions: [ + _total > 0 + ? Row( + children: [ + LinearProgressIndicator( + value: _received > 0 ? _total / _received : 0, + ), + Text('${_received ~/ 1024}/${_total ~/ 1024} KB'), + ], + ) + : SizedBox.shrink(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text(l10n.cancel), + ), + const SizedBox(width: 15), + ElevatedButton( + onPressed: () async { + if (Platform.isAndroid) { + final deviceInfo = DeviceInfoPlugin(); + final androidInfo = await deviceInfo.androidInfo; + String apkUrl = ""; + for (String abi in androidInfo.supportedAbis) { + final url = updateAvailable.$4.firstWhereOrNull( + (apk) => apk.contains(abi), + ); + if (url != null) { + apkUrl = url; + break; + } + } + await _downloadApk(apkUrl); + print("DEBUG"); + print( + androidInfo.supportedAbis.join(", "), + ); // x86_64, arm64-v8a, armeabi-v7a + } else { + _launchInBrowser(Uri.parse(updateAvailable.$3)); + } + }, + child: Text(l10n.download), + ), + ], + ), + ], + ); + } + + Future _downloadApk(String url) async { + _response = await http.Client().send(http.Request('GET', Uri.parse(url))); + _total = _response.contentLength ?? 0; + + _response.stream + .listen((value) { + setState(() { + _bytes.addAll(value); + _received += value.length; + }); + }) + .onDone(() async { + final file = File( + '${(await getApplicationDocumentsDirectory()).path}/${url.split("/").lastOrNull ?? "Mangayomi.apk"}', + ); + await file.writeAsBytes(_bytes); + final FlutterAppInstaller appInstaller = FlutterAppInstaller(); + await appInstaller.installApk(filePath: file.path); + await file.delete(); + if (context.mounted) { + Navigator.pop(context); + } + }); + } + + Future _launchInBrowser(Uri url) async { + if (!await launchUrl(url, mode: LaunchMode.externalApplication)) { + throw 'Could not launch $url'; + } + } +} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 038396d6..596d9721 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,7 +5,6 @@ import FlutterMacOS import Foundation -import app_installer import app_links import audio_session import connectivity_plus @@ -32,7 +31,6 @@ import window_manager import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - AppInstallerPlugin.register(with: registry.registrar(forPlugin: "AppInstallerPlugin")) AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 483f763c..739cd5a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -38,14 +38,6 @@ packages: url: "https://pub.dev" source: hosted version: "4.13.2" - app_installer: - dependency: "direct main" - description: - name: app_installer - sha256: "4c3a9268b53ead9a915ef79cd3988e28c72719fb78143867f9fed4bd4d8c1cfd" - url: "https://pub.dev" - source: hosted - version: "1.3.1" app_links: dependency: "direct main" description: @@ -556,6 +548,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_app_installer: + dependency: "direct main" + description: + name: flutter_app_installer + sha256: b71f7c3f6c5712b6f9bdcde798bbb8a0c4047cab47c4364f7252de8c95d67358 + url: "https://pub.dev" + source: hosted + version: "1.0.0" flutter_cache_manager: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cf5cdf8b..d92f68ee 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,8 +83,8 @@ dependencies: app_links: ^6.4.0 win32: ^5.10.1 protobuf: ^3.1.0 - app_installer: ^1.3.1 device_info_plus: ^11.3.3 + flutter_app_installer: ^1.0.0 dependency_overrides: http: ^1.2.2