diff --git a/android/app/build.gradle b/android/app/build.gradle index d0dccaa..d8c6dc1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,8 +26,8 @@ def alistVersion = rootProject.file("../alist_version").readLines()[0] android { namespace "com.github.jing332.alistflutter" - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion + compileSdkVersion 34 + ndkVersion "25.1.8937393" signingConfigs { release { diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 634800e..e3e5d2b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ xmlns:tools="http://schemas.android.com/tools"> - + diff --git a/android/app/src/main/java/com/github/jing332/pigeon/GeneratedApi.java b/android/app/src/main/java/com/github/jing332/pigeon/GeneratedApi.java index 5f7fae7..0c91968 100644 --- a/android/app/src/main/java/com/github/jing332/pigeon/GeneratedApi.java +++ b/android/app/src/main/java/com/github/jing332/pigeon/GeneratedApi.java @@ -259,6 +259,9 @@ public interface Android { void setAdminPwd(@NonNull String pwd); + @NonNull + Long getAListHttpPort(); + @NonNull Boolean isRunning(); @@ -339,6 +342,28 @@ static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable Android ap api.setAdminPwd(pwdArg); wrapped.add(0, null); } + catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.alist_flutter.Android.getAListHttpPort", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + try { + Long output = api.getAListHttpPort(); + wrapped.add(0, output); + } catch (Throwable exception) { ArrayList wrappedError = wrapError(exception); wrapped = wrappedError; @@ -488,44 +513,6 @@ static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable Android ap } } /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ - public static class Flutter { - private final @NonNull BinaryMessenger binaryMessenger; - - public Flutter(@NonNull BinaryMessenger argBinaryMessenger) { - this.binaryMessenger = argBinaryMessenger; - } - - /** Public interface for sending reply. */ - /** The codec used by Flutter. */ - static @NonNull MessageCodec getCodec() { - return new StandardMessageCodec(); - } - public void getLocalIpAddress(@NonNull Result result) { - final String channelName = "dev.flutter.pigeon.alist_flutter.Flutter.getLocalIpAddress"; - BasicMessageChannel channel = - new BasicMessageChannel<>( - binaryMessenger, channelName, getCodec()); - channel.send( - null, - channelReply -> { - if (channelReply instanceof List) { - List listReply = (List) channelReply; - if (listReply.size() > 1) { - result.error(new FlutterError((String) listReply.get(0), (String) listReply.get(1), (String) listReply.get(2))); - } else if (listReply.get(0) == null) { - result.error(new FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")); - } else { - @SuppressWarnings("ConstantConditions") - String output = (String) listReply.get(0); - result.success(output); - } - } else { - result.error(createConnectionError(channelName)); - } - }); - } - } - /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ public static class Event { private final @NonNull BinaryMessenger binaryMessenger; diff --git a/android/app/src/main/kotlin/com/github/jing332/alistflutter/bridge/AndroidBridge.kt b/android/app/src/main/kotlin/com/github/jing332/alistflutter/bridge/AndroidBridge.kt index b4da51e..4af496e 100644 --- a/android/app/src/main/kotlin/com/github/jing332/alistflutter/bridge/AndroidBridge.kt +++ b/android/app/src/main/kotlin/com/github/jing332/alistflutter/bridge/AndroidBridge.kt @@ -31,6 +31,10 @@ class AndroidBridge(private val context: Context) : GeneratedApi.Android { AList.setAdminPassword(pwd) } + override fun getAListHttpPort(): Long { + return AList.getHttpPort().toLong() + } + override fun isRunning() = AListService.isRunning override fun getAListVersion() = BuildConfig.ALIST_VERSION override fun getVersionName() = BuildConfig.VERSION_NAME diff --git a/android/app/src/main/kotlin/com/github/jing332/alistflutter/model/alist/AList.kt b/android/app/src/main/kotlin/com/github/jing332/alistflutter/model/alist/AList.kt index 8b184a6..913d27b 100644 --- a/android/app/src/main/kotlin/com/github/jing332/alistflutter/model/alist/AList.kt +++ b/android/app/src/main/kotlin/com/github/jing332/alistflutter/model/alist/AList.kt @@ -53,7 +53,7 @@ object AList { private var mProcess: Process? = null - private fun handleLog(log:String){ + private fun handleLog(log: String) { log.removeAnsiCodes().evalLog()?.let { Logger.log(level = it.level, time = it.time, msg = it.message) } ?: run { @@ -112,4 +112,8 @@ object AList { return ProcessBuilder(*cmdline).redirectErrorStream(redirect).start() ?: throw IOException("Process is null!") } + + fun getHttpPort(): Int { + return AListConfigManager.config().scheme.httpPort + } } \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 671773a..c585661 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -13,7 +13,7 @@ buildscript { } dependencies { - classpath "com.android.tools.build:gradle:3.5.3" + classpath "com.android.tools.build:gradle:$agp_version" // classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/lib/generated_api.dart b/lib/generated_api.dart index 6553d40..fa2c858 100644 --- a/lib/generated_api.dart +++ b/lib/generated_api.dart @@ -259,6 +259,33 @@ class Android { } } + Future getAListHttpPort() async { + const String __pigeon_channelName = 'dev.flutter.pigeon.alist_flutter.Android.getAListHttpPort'; + final BasicMessageChannel __pigeon_channel = BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send(null) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as int?)!; + } + } + Future isRunning() async { const String __pigeon_channelName = 'dev.flutter.pigeon.alist_flutter.Android.isRunning'; final BasicMessageChannel __pigeon_channel = BasicMessageChannel( @@ -412,34 +439,6 @@ class Android { } } -abstract class Flutter { - static const MessageCodec pigeonChannelCodec = StandardMessageCodec(); - - String getLocalIpAddress(); - - static void setup(Flutter? api, {BinaryMessenger? binaryMessenger}) { - { - final BasicMessageChannel __pigeon_channel = BasicMessageChannel( - 'dev.flutter.pigeon.alist_flutter.Flutter.getLocalIpAddress', pigeonChannelCodec, - binaryMessenger: binaryMessenger); - if (api == null) { - __pigeon_channel.setMessageHandler(null); - } else { - __pigeon_channel.setMessageHandler((Object? message) async { - try { - final String output = api.getLocalIpAddress(); - return wrapResponse(result: output); - } on PlatformException catch (e) { - return wrapResponse(error: e); - } catch (e) { - return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); - } - }); - } - } - } -} - abstract class Event { static const MessageCodec pigeonChannelCodec = StandardMessageCodec(); diff --git a/lib/main.dart b/lib/main.dart index e6d5c99..9b1f693 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,14 +1,21 @@ -import 'dart:async'; - -import 'package:alist_flutter/generated_api.dart'; -import 'package:alist_flutter/pages/alist.dart'; +import 'package:alist_flutter/pages/alist/alist.dart'; import 'package:alist_flutter/pages/settings/settings.dart'; -import 'package:alist_flutter/pages/web.dart'; +import 'package:alist_flutter/pages/web/web.dart'; import 'package:alist_flutter/router.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; -void main() { +void main() async { + WidgetsFlutterBinding.ensureInitialized(); + // Android + if (!kIsWeb && + kDebugMode && + defaultTargetPlatform == TargetPlatform.android) { + await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode); + } + runApp(const MyApp()); } diff --git a/lib/pages/alist.dart b/lib/pages/alist/alist.dart similarity index 97% rename from lib/pages/alist.dart rename to lib/pages/alist/alist.dart index b45cd02..e6f52ef 100644 --- a/lib/pages/alist.dart +++ b/lib/pages/alist/alist.dart @@ -1,12 +1,12 @@ import 'dart:developer'; import 'package:alist_flutter/generated_api.dart'; -import 'package:alist_flutter/pages/pwd_edit_dialog.dart'; +import 'package:alist_flutter/pages/alist/pwd_edit_dialog.dart'; import 'package:alist_flutter/widgets/switch_floating_action_button.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'alist/log_list_view.dart'; +import 'log_list_view.dart'; class AListScreen extends StatelessWidget { const AListScreen({Key? key}) : super(key: key); diff --git a/lib/pages/pwd_edit_dialog.dart b/lib/pages/alist/pwd_edit_dialog.dart similarity index 100% rename from lib/pages/pwd_edit_dialog.dart rename to lib/pages/alist/pwd_edit_dialog.dart diff --git a/lib/pages/web.dart b/lib/pages/web.dart deleted file mode 100644 index 362ba0b..0000000 --- a/lib/pages/web.dart +++ /dev/null @@ -1,12 +0,0 @@ -import 'package:flutter/material.dart'; - -class WebScreen extends StatelessWidget { - const WebScreen({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Scaffold( - - ); - } -} diff --git a/lib/pages/web/web.dart b/lib/pages/web/web.dart new file mode 100644 index 0000000..bbcd8f3 --- /dev/null +++ b/lib/pages/web/web.dart @@ -0,0 +1,127 @@ +import 'package:alist_flutter/generated_api.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; +import 'package:get/get.dart'; + +class WebScreen extends StatefulWidget { + const WebScreen({Key? key}) : super(key: key); + + @override + State createState() { + return _WebScreenState(); + } +} + +class _WebScreenState extends State { + InAppWebViewController? _webViewController; + double _progress = 0; + String _url = "http://localhost:5244"; + + @override + void initState() { + Android() + .getAListHttpPort() + .then((port) => {_url = "http://localhost:$port"}); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return PopScope( + onPopInvoked: (b) { + _webViewController?.canGoBack().then((value) => { + if (value) {_webViewController?.goBack()} else {Get.back()} + }); + }, + child: Scaffold( + body: Column(children: [ + SizedBox(height: MediaQuery.of(context).padding.top), + LinearProgressIndicator( + value: _progress, + backgroundColor: Colors.grey[200], + valueColor: const AlwaysStoppedAnimation(Colors.blue), + ), + Expanded( + child: InAppWebView( + initialUrlRequest: URLRequest(url: WebUri(_url)), + onWebViewCreated: (InAppWebViewController controller) { + _webViewController = controller; + }, + onLoadStart: (InAppWebViewController controller, Uri? url) { + setState(() { + _progress = 0; + }); + }, + shouldOverrideUrlLoading: (controller, navigationAction) async { + if (navigationAction.request.url?.scheme.startsWith("http") == + true) { + return NavigationActionPolicy.ALLOW; + } + Get.showSnackbar(GetSnackBar( + message: + "shouldOverrideUrlLoading ${navigationAction.request.url}", + duration: const Duration(seconds: 3), + mainButton: TextButton( + onPressed: () {}, + child: const Text('前往'), + ))); + + return NavigationActionPolicy.CANCEL; + }, + onDownloadStartRequest: (controller, url) async { + Get.showSnackbar(GetSnackBar( + message: "是否下载文件? ${url.contentDisposition}", + duration: const Duration(seconds: 3), + mainButton: TextButton( + onPressed: () {}, + child: const Text('下载'), + ))); + }, + onLoadStop: + (InAppWebViewController controller, Uri? url) async { + setState(() { + _progress = 0; + }); + }, + onProgressChanged: + (InAppWebViewController controller, int progress) { + setState(() { + _progress = progress / 100; + if (_progress == 1) _progress = 0; + }); + }, + ), + ), + ButtonBar( + alignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + child: const Icon(Icons.arrow_back), + onPressed: () { + if (_webViewController != null) { + _webViewController!.goBack(); + } + }, + ), + ElevatedButton( + child: const Icon(Icons.arrow_forward), + onPressed: () { + if (_webViewController != null) { + _webViewController!.goForward(); + } + }, + ), + ElevatedButton( + child: const Icon(Icons.refresh), + onPressed: () { + if (_webViewController != null) { + _webViewController!.reload(); + } + }, + ), + ], + ), + ]), + )); + } +} diff --git a/lib/router.dart b/lib/router.dart index 780d295..7e7fb42 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,6 +1,6 @@ -import 'package:alist_flutter/pages/alist.dart'; +import 'package:alist_flutter/pages/alist/alist.dart'; import 'package:alist_flutter/pages/settings/settings.dart'; -import 'package:alist_flutter/pages/web.dart'; +import 'package:alist_flutter/pages/web/web.dart'; import 'package:flutter/material.dart'; abstract class AppRouter { diff --git a/pigeons/pigeon.dart b/pigeons/pigeon.dart index 221eb9b..524f490 100644 --- a/pigeons/pigeon.dart +++ b/pigeons/pigeon.dart @@ -23,6 +23,8 @@ abstract class Android { void setAdminPwd(String pwd); + int getAListHttpPort(); + bool isRunning(); String getAListVersion(); @@ -36,10 +38,6 @@ abstract class Android { void longToast(String msg); } -@FlutterApi() -abstract class Flutter { - String getLocalIpAddress(); -} @FlutterApi() abstract class Event { diff --git a/pubspec.lock b/pubspec.lock index 41c1d98..ac31d0a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -110,6 +110,62 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "3e9a443a18ecef966fb930c3a76ca5ab6a7aafc0c7b5e14a4a850cf107b09959" + url: "https://pub.dev" + source: hosted + version: "6.0.0" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: fd4db51e46f49b140d83a3206851432c54ea920b381137c0ba82d0cf59be1dee + url: "https://pub.dev" + source: hosted + version: "1.0.12" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: f363577208b97b10b319cd0c428555cd8493e88b468019a8c5635a0e4312bd0f + url: "https://pub.dev" + source: hosted + version: "1.0.13" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: b55b9e506c549ce88e26580351d2c71d54f4825901666bd6cfa4be9415bb2636 + url: "https://pub.dev" + source: hosted + version: "1.0.11" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: "545fd4c25a07d2775f7d5af05a979b2cac4fbf79393b0a7f5d33ba39ba4f6187" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: d8c680abfb6fec71609a700199635d38a744df0febd5544c5a020bd73de8ee07 + url: "https://pub.dev" + source: hosted + version: "1.0.8" flutter_lints: dependency: "direct dev" description: @@ -123,6 +179,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" get: dependency: "direct main" description: @@ -139,6 +200,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" lints: dependency: transitive description: @@ -195,6 +264,14 @@ packages: url: "https://pub.dev" source: hosted version: "16.0.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index f8492cd..1cb3062 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: cupertino_icons: ^1.0.2 get: ^4.6.6 pigeon: ^16.0.0 + flutter_inappwebview: ^6.0.0 dev_dependencies: