diff --git a/lib/app.g.dart b/lib/app.g.dart index 1cd7f1e..6d87e98 100644 --- a/lib/app.g.dart +++ b/lib/app.g.dart @@ -6,7 +6,7 @@ part of 'app.dart'; // RiverpodGenerator // ************************************************************************** -String _$routerHash() => r'df314e6867c385ecf4f18f2cf485c7517bec9154'; +String _$routerHash() => r'6e1ddfd4fb004ca0c2262ab17a4b0882f12bcc3b'; /// See also [router]. @ProviderFor(router) @@ -20,7 +20,7 @@ final routerProvider = AutoDisposeProvider.internal( ); typedef RouterRef = AutoDisposeProviderRef; -String _$appGlobalModelHash() => r'1b454a5c8a776aa12a4f953b59b9670d8337840f'; +String _$appGlobalModelHash() => r'9c114910aed546bfd469c8bbfa50cdd4a5be5028'; /// See also [AppGlobalModel]. @ProviderFor(AppGlobalModel) diff --git a/lib/common/io/aria2c.dart b/lib/common/io/aria2c.dart deleted file mode 100644 index ca9dfa3..0000000 --- a/lib/common/io/aria2c.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'dart:io'; -import 'dart:math'; - -import 'package:aria2/aria2.dart'; -import 'package:flutter/foundation.dart'; -import 'package:hive/hive.dart'; -import 'package:starcitizen_doctor/api/api.dart'; -import 'package:starcitizen_doctor/common/helper/system_helper.dart'; - - -import 'package:starcitizen_doctor/common/utils/log.dart'; - -class Aria2cManager { - -} diff --git a/lib/provider/aria2c.dart b/lib/provider/aria2c.dart index c4b5f8a..b1263df 100644 --- a/lib/provider/aria2c.dart +++ b/lib/provider/aria2c.dart @@ -21,19 +21,35 @@ part 'aria2c.freezed.dart'; @freezed class Aria2cModelState with _$Aria2cModelState { const factory Aria2cModelState({ - required bool isDaemonRunning, required String aria2cDir, Aria2c? aria2c, + Aria2GlobalStat? aria2globalStat, }) = _Aria2cModelState; } +extension Aria2cModelExt on Aria2cModelState { + bool get isRunning => aria2c != null; + + bool get hasDownloadTask => aria2globalStat != null && aria2TotalTaskNum > 0; + + int get aria2TotalTaskNum => aria2globalStat == null + ? 0 + : ((aria2globalStat!.numActive ?? 0) + + (aria2globalStat!.numWaiting ?? 0)); +} + @riverpod class Aria2cModel extends _$Aria2cModel { + bool _disposed = false; + @override Aria2cModelState build() { if (appGlobalState.applicationBinaryModuleDir == null) { throw Exception("applicationBinaryModuleDir is null"); } + ref.onDispose(() { + _disposed = true; + }); ref.keepAlive(); final aria2cDir = "${appGlobalState.applicationBinaryModuleDir}\\aria2c"; // LazyLoad init @@ -53,11 +69,11 @@ class Aria2cModel extends _$Aria2cModel { } }(); - return Aria2cModelState(isDaemonRunning: false, aria2cDir: aria2cDir); + return Aria2cModelState(aria2cDir: aria2cDir); } Future launchDaemon(String applicationBinaryModuleDir) async { - if (state.isDaemonRunning) return; + if (state.aria2c != null) return; await BinaryModuleConf.extractModule( ["aria2c"], applicationBinaryModuleDir); @@ -111,16 +127,16 @@ class Aria2cModel extends _$Aria2cModel { _onLaunch(port, pwd, trackerList); } } else if (event.startsWith("error:")) { - state = state.copyWith(aria2c: null, isDaemonRunning: false); + state = state.copyWith(aria2c: null); launchError = event; } else if (event.startsWith("exit:")) { - state = state.copyWith(aria2c: null, isDaemonRunning: false); + state = state.copyWith(aria2c: null); launchError = event; } }); while (true) { - if (state.isDaemonRunning) return; + if (state.aria2c != null) return; if (launchError.isNotEmpty) throw launchError; await Future.delayed(const Duration(milliseconds: 100)); } @@ -163,9 +179,10 @@ class Aria2cModel extends _$Aria2cModel { Future _onLaunch(int port, String pwd, String trackerList) async { final aria2c = Aria2c("ws://127.0.0.1:$port/jsonrpc", "websocket", pwd); - state = state.copyWith(aria2c: aria2c, isDaemonRunning: true); + state = state.copyWith(aria2c: aria2c); aria2c.getVersion().then((value) { dPrint("Aria2cManager.connected! version == ${value.version}"); + _listenState(aria2c); }); final box = await Hive.openBox("app_conf"); aria2c.changeGlobalOption(Aria2Option() @@ -175,4 +192,21 @@ class Aria2cModel extends _$Aria2cModel { textToByte(box.get("downloader_down_limit", defaultValue: "0")) ..btTracker = trackerList); } + + Future _listenState(Aria2c aria2c) async { + dPrint("Aria2cModel._listenState start"); + while (true) { + if (_disposed || state.aria2c == null) { + dPrint("Aria2cModel._listenState end"); + return; + } + try { + final aria2globalStat = await aria2c.getGlobalStat(); + state = state.copyWith(aria2globalStat: aria2globalStat); + } catch (e) { + dPrint("aria2globalStat update error:$e"); + } + await Future.delayed(const Duration(seconds: 1)); + } + } } diff --git a/lib/provider/aria2c.freezed.dart b/lib/provider/aria2c.freezed.dart index d421447..eeb7609 100644 --- a/lib/provider/aria2c.freezed.dart +++ b/lib/provider/aria2c.freezed.dart @@ -16,9 +16,9 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$Aria2cModelState { - bool get isDaemonRunning => throw _privateConstructorUsedError; String get aria2cDir => throw _privateConstructorUsedError; Aria2c? get aria2c => throw _privateConstructorUsedError; + Aria2GlobalStat? get aria2globalStat => throw _privateConstructorUsedError; @JsonKey(ignore: true) $Aria2cModelStateCopyWith get copyWith => @@ -31,7 +31,8 @@ abstract class $Aria2cModelStateCopyWith<$Res> { Aria2cModelState value, $Res Function(Aria2cModelState) then) = _$Aria2cModelStateCopyWithImpl<$Res, Aria2cModelState>; @useResult - $Res call({bool isDaemonRunning, String aria2cDir, Aria2c? aria2c}); + $Res call( + {String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat}); } /// @nodoc @@ -47,15 +48,11 @@ class _$Aria2cModelStateCopyWithImpl<$Res, $Val extends Aria2cModelState> @pragma('vm:prefer-inline') @override $Res call({ - Object? isDaemonRunning = null, Object? aria2cDir = null, Object? aria2c = freezed, + Object? aria2globalStat = freezed, }) { return _then(_value.copyWith( - isDaemonRunning: null == isDaemonRunning - ? _value.isDaemonRunning - : isDaemonRunning // ignore: cast_nullable_to_non_nullable - as bool, aria2cDir: null == aria2cDir ? _value.aria2cDir : aria2cDir // ignore: cast_nullable_to_non_nullable @@ -64,6 +61,10 @@ class _$Aria2cModelStateCopyWithImpl<$Res, $Val extends Aria2cModelState> ? _value.aria2c : aria2c // ignore: cast_nullable_to_non_nullable as Aria2c?, + aria2globalStat: freezed == aria2globalStat + ? _value.aria2globalStat + : aria2globalStat // ignore: cast_nullable_to_non_nullable + as Aria2GlobalStat?, ) as $Val); } } @@ -76,7 +77,8 @@ abstract class _$$Aria2cModelStateImplCopyWith<$Res> __$$Aria2cModelStateImplCopyWithImpl<$Res>; @override @useResult - $Res call({bool isDaemonRunning, String aria2cDir, Aria2c? aria2c}); + $Res call( + {String aria2cDir, Aria2c? aria2c, Aria2GlobalStat? aria2globalStat}); } /// @nodoc @@ -90,15 +92,11 @@ class __$$Aria2cModelStateImplCopyWithImpl<$Res> @pragma('vm:prefer-inline') @override $Res call({ - Object? isDaemonRunning = null, Object? aria2cDir = null, Object? aria2c = freezed, + Object? aria2globalStat = freezed, }) { return _then(_$Aria2cModelStateImpl( - isDaemonRunning: null == isDaemonRunning - ? _value.isDaemonRunning - : isDaemonRunning // ignore: cast_nullable_to_non_nullable - as bool, aria2cDir: null == aria2cDir ? _value.aria2cDir : aria2cDir // ignore: cast_nullable_to_non_nullable @@ -107,6 +105,10 @@ class __$$Aria2cModelStateImplCopyWithImpl<$Res> ? _value.aria2c : aria2c // ignore: cast_nullable_to_non_nullable as Aria2c?, + aria2globalStat: freezed == aria2globalStat + ? _value.aria2globalStat + : aria2globalStat // ignore: cast_nullable_to_non_nullable + as Aria2GlobalStat?, )); } } @@ -117,18 +119,18 @@ class _$Aria2cModelStateImpl with DiagnosticableTreeMixin implements _Aria2cModelState { const _$Aria2cModelStateImpl( - {required this.isDaemonRunning, required this.aria2cDir, this.aria2c}); + {required this.aria2cDir, this.aria2c, this.aria2globalStat}); - @override - final bool isDaemonRunning; @override final String aria2cDir; @override final Aria2c? aria2c; + @override + final Aria2GlobalStat? aria2globalStat; @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { - return 'Aria2cModelState(isDaemonRunning: $isDaemonRunning, aria2cDir: $aria2cDir, aria2c: $aria2c)'; + return 'Aria2cModelState(aria2cDir: $aria2cDir, aria2c: $aria2c, aria2globalStat: $aria2globalStat)'; } @override @@ -136,9 +138,9 @@ class _$Aria2cModelStateImpl super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('type', 'Aria2cModelState')) - ..add(DiagnosticsProperty('isDaemonRunning', isDaemonRunning)) ..add(DiagnosticsProperty('aria2cDir', aria2cDir)) - ..add(DiagnosticsProperty('aria2c', aria2c)); + ..add(DiagnosticsProperty('aria2c', aria2c)) + ..add(DiagnosticsProperty('aria2globalStat', aria2globalStat)); } @override @@ -146,16 +148,16 @@ class _$Aria2cModelStateImpl return identical(this, other) || (other.runtimeType == runtimeType && other is _$Aria2cModelStateImpl && - (identical(other.isDaemonRunning, isDaemonRunning) || - other.isDaemonRunning == isDaemonRunning) && (identical(other.aria2cDir, aria2cDir) || other.aria2cDir == aria2cDir) && - (identical(other.aria2c, aria2c) || other.aria2c == aria2c)); + (identical(other.aria2c, aria2c) || other.aria2c == aria2c) && + (identical(other.aria2globalStat, aria2globalStat) || + other.aria2globalStat == aria2globalStat)); } @override int get hashCode => - Object.hash(runtimeType, isDaemonRunning, aria2cDir, aria2c); + Object.hash(runtimeType, aria2cDir, aria2c, aria2globalStat); @JsonKey(ignore: true) @override @@ -167,17 +169,17 @@ class _$Aria2cModelStateImpl abstract class _Aria2cModelState implements Aria2cModelState { const factory _Aria2cModelState( - {required final bool isDaemonRunning, - required final String aria2cDir, - final Aria2c? aria2c}) = _$Aria2cModelStateImpl; + {required final String aria2cDir, + final Aria2c? aria2c, + final Aria2GlobalStat? aria2globalStat}) = _$Aria2cModelStateImpl; - @override - bool get isDaemonRunning; @override String get aria2cDir; @override Aria2c? get aria2c; @override + Aria2GlobalStat? get aria2globalStat; + @override @JsonKey(ignore: true) _$$Aria2cModelStateImplCopyWith<_$Aria2cModelStateImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/lib/provider/aria2c.g.dart b/lib/provider/aria2c.g.dart index acfd355..f9db6d6 100644 --- a/lib/provider/aria2c.g.dart +++ b/lib/provider/aria2c.g.dart @@ -6,7 +6,7 @@ part of 'aria2c.dart'; // RiverpodGenerator // ************************************************************************** -String _$aria2cModelHash() => r'45bfdd07a11bb93594b76297a995e8ba24e0e984'; +String _$aria2cModelHash() => r'6685f6a716016113487de190a61f71196094526e'; /// See also [Aria2cModel]. @ProviderFor(Aria2cModel) diff --git a/lib/ui/index_ui.dart b/lib/ui/index_ui.dart index c37742f..522ca74 100644 --- a/lib/ui/index_ui.dart +++ b/lib/ui/index_ui.dart @@ -2,6 +2,7 @@ import 'package:fluent_ui/fluent_ui.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:starcitizen_doctor/common/conf/const_conf.dart'; +import 'package:starcitizen_doctor/provider/aria2c.dart'; import 'package:starcitizen_doctor/widgets/widgets.dart'; import 'package:window_manager/window_manager.dart'; @@ -48,25 +49,7 @@ class IndexUI extends HookConsumerWidget { color: Colors.white.withOpacity(.6), ), ), - // if (model.aria2TotalTaskNum != 0) - // Positioned( - // bottom: 0, - // right: 0, - // child: Container( - // decoration: BoxDecoration( - // color: Colors.red, - // borderRadius: BorderRadius.circular(12), - // ), - // padding: const EdgeInsets.only( - // left: 6, right: 6, bottom: 1.5, top: 1.5), - // child: Text( - // "${model.aria2TotalTaskNum}", - // style: const TextStyle( - // fontSize: 8, - // color: Colors.white, - // ), - // ), - // )), + _makeAria2TaskNumWidget() ], ), onPressed: () {}, @@ -134,4 +117,33 @@ class IndexUI extends HookConsumerWidget { pageMenus.values.toList().indexWhere((element) => element == value); curIndexState.value = pageIndex; } + + Widget _makeAria2TaskNumWidget() { + return Consumer( + builder: (BuildContext context, WidgetRef ref, Widget? child) { + final aria2cState = ref.watch(aria2cModelProvider); + if (!aria2cState.hasDownloadTask) { + return const SizedBox(); + } + return Positioned( + bottom: 0, + right: 0, + child: Container( + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(12), + ), + padding: const EdgeInsets.only( + left: 6, right: 6, bottom: 1.5, top: 1.5), + child: Text( + "${aria2cState.aria2TotalTaskNum}", + style: const TextStyle( + fontSize: 8, + color: Colors.white, + ), + ), + )); + }, + ); + } }