mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-15 12:53:41 +00:00
fix(ui): preserve desktop platform listeners (#1483)
This commit is contained in:
2 files changed
+130
-15
No files matched your search
@@ -54,6 +54,9 @@ class AppPlatformState {
|
|||||||
enum AppUpdateStatus { idle, checking, upToDate, available, failed }
|
enum AppUpdateStatus { idle, checking, upToDate, available, failed }
|
||||||
|
|
||||||
class AppPlatformController extends AsyncNotifier<AppPlatformState> with WindowListener, TrayListener {
|
class AppPlatformController extends AsyncNotifier<AppPlatformState> with WindowListener, TrayListener {
|
||||||
|
@protected
|
||||||
|
bool get isDesktop => Util.isDesktop();
|
||||||
|
|
||||||
bool _started = false;
|
bool _started = false;
|
||||||
String? _trayLocaleConfig;
|
String? _trayLocaleConfig;
|
||||||
bool _updateInitialized = false;
|
bool _updateInitialized = false;
|
||||||
@@ -74,30 +77,54 @@ class AppPlatformController extends AsyncNotifier<AppPlatformState> with WindowL
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AppPlatformState> build() async {
|
Future<AppPlatformState> build() async {
|
||||||
final runtime = ref.watch(appRuntimeControllerProvider).value;
|
ref.listen(appRuntimeControllerProvider, (_, next) {
|
||||||
if (runtime == null || kIsWeb) {
|
unawaited(
|
||||||
return _snapshot();
|
_handleRuntimeChange(next.value).catchError((Object error, StackTrace stackTrace) {
|
||||||
}
|
if (ref.mounted) state = AsyncValue.error(error, stackTrace);
|
||||||
if (!Util.isDesktop()) {
|
}),
|
||||||
_scheduleInitialUpdateCheck();
|
);
|
||||||
return _snapshot();
|
});
|
||||||
}
|
|
||||||
if (_started) {
|
|
||||||
final localeConfig = runtime.downloaderConfig.extra.locale;
|
|
||||||
if (_trayLocaleConfig != localeConfig) await _initTray();
|
|
||||||
return _snapshot();
|
|
||||||
}
|
|
||||||
await _start();
|
|
||||||
_scheduleInitialUpdateCheck();
|
|
||||||
ref.onDispose(() {
|
ref.onDispose(() {
|
||||||
|
if (!_started) return;
|
||||||
|
_started = false;
|
||||||
windowManager.removeListener(this);
|
windowManager.removeListener(this);
|
||||||
trayManager.removeListener(this);
|
trayManager.removeListener(this);
|
||||||
unawaited(HostRpcService.instance.stop());
|
unawaited(HostRpcService.instance.stop());
|
||||||
unawaited(AppWindowCapabilityHost.instance.stop());
|
unawaited(AppWindowCapabilityHost.instance.stop());
|
||||||
});
|
});
|
||||||
|
final runtime = ref.read(appRuntimeControllerProvider).value;
|
||||||
|
if (runtime == null || kIsWeb) {
|
||||||
|
return _snapshot();
|
||||||
|
}
|
||||||
|
if (!isDesktop) {
|
||||||
|
_scheduleInitialUpdateCheck();
|
||||||
|
return _snapshot();
|
||||||
|
}
|
||||||
|
if (_started) {
|
||||||
|
return _snapshot();
|
||||||
|
}
|
||||||
|
await _start();
|
||||||
|
_scheduleInitialUpdateCheck();
|
||||||
return _snapshot();
|
return _snapshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _handleRuntimeChange(AppRuntimeState? runtime) async {
|
||||||
|
if (runtime == null || kIsWeb) return;
|
||||||
|
if (!isDesktop) {
|
||||||
|
_scheduleInitialUpdateCheck();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_started) {
|
||||||
|
await _start();
|
||||||
|
_scheduleInitialUpdateCheck();
|
||||||
|
_emit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_trayLocaleConfig != runtime.downloaderConfig.extra.locale) {
|
||||||
|
await _initTray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _scheduleInitialUpdateCheck() {
|
void _scheduleInitialUpdateCheck() {
|
||||||
if (_updateInitialized) return;
|
if (_updateInitialized) return;
|
||||||
_updateInitialized = true;
|
_updateInitialized = true;
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:gopeed/api/model/downloader_config.dart';
|
||||||
|
import 'package:gopeed/app/application/app_platform_controller.dart';
|
||||||
|
import 'package:gopeed/app/application/app_runtime_controller.dart';
|
||||||
|
import 'package:gopeed/core/common/api_server_state.dart';
|
||||||
|
import 'package:gopeed/core/common/start_config.dart';
|
||||||
|
import 'package:gopeed/util/updater.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
test('runtime updates do not rebuild the platform controller', () async {
|
||||||
|
final container = ProviderContainer(
|
||||||
|
overrides: [
|
||||||
|
appRuntimeControllerProvider.overrideWith(_TestRuntimeController.new),
|
||||||
|
appPlatformControllerProvider.overrideWith(_TestPlatformController.new),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
addTearDown(container.dispose);
|
||||||
|
final subscription = container.listen(appPlatformControllerProvider, (_, _) {}, fireImmediately: true);
|
||||||
|
addTearDown(subscription.close);
|
||||||
|
|
||||||
|
await container.read(appPlatformControllerProvider.future);
|
||||||
|
final platformController = container.read(appPlatformControllerProvider.notifier) as _TestPlatformController;
|
||||||
|
final runtimeController = container.read(appRuntimeControllerProvider.notifier) as _TestRuntimeController;
|
||||||
|
|
||||||
|
expect(platformController.buildCount, 1);
|
||||||
|
|
||||||
|
runtimeController.completeRuntime();
|
||||||
|
await container.read(appRuntimeControllerProvider.future);
|
||||||
|
await Future<void>.delayed(Duration.zero);
|
||||||
|
expect(platformController.updateCheckCount, 1);
|
||||||
|
|
||||||
|
final config = DownloaderConfig.fromJson(runtimeController.state.requireValue.downloaderConfig.toJson());
|
||||||
|
config.extra.locale = 'zh';
|
||||||
|
runtimeController.replaceDownloaderConfig(config);
|
||||||
|
await container.pump();
|
||||||
|
|
||||||
|
expect(platformController.buildCount, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestPlatformController extends AppPlatformController {
|
||||||
|
int buildCount = 0;
|
||||||
|
int updateCheckCount = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isDesktop => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AppPlatformState> build() {
|
||||||
|
buildCount++;
|
||||||
|
return super.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<VersionInfo?> checkForUpdate() async {
|
||||||
|
updateCheckCount++;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestRuntimeController extends AppRuntimeController {
|
||||||
|
final _pendingRuntime = Completer<AppRuntimeState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AppRuntimeState> build() => _pendingRuntime.future;
|
||||||
|
|
||||||
|
void completeRuntime() {
|
||||||
|
_pendingRuntime.complete(
|
||||||
|
AppRuntimeState(
|
||||||
|
startConfig: StartConfig(),
|
||||||
|
apiServerState: const ApiServerState(
|
||||||
|
enabled: false,
|
||||||
|
mcpEnabled: false,
|
||||||
|
running: false,
|
||||||
|
network: '',
|
||||||
|
address: '',
|
||||||
|
runningPort: 0,
|
||||||
|
pendingApply: false,
|
||||||
|
lastError: '',
|
||||||
|
),
|
||||||
|
downloaderConfig: DownloaderConfig(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user