From 6e47594a91af583dd3d8397564fda4b770b15601 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 22 Sep 2026 11:36:29 -0400 Subject: [PATCH] fix race condition on startup --- lib/controllers/multi_provider.dart | 2 +- lib/controllers/unified_push.dart | 46 +++++++------- lib/main.dart | 94 +++++++++++++++-------------- 3 files changed, 74 insertions(+), 68 deletions(-) diff --git a/lib/controllers/multi_provider.dart b/lib/controllers/multi_provider.dart index 98c01db..ab37d07 100644 --- a/lib/controllers/multi_provider.dart +++ b/lib/controllers/multi_provider.dart @@ -7,7 +7,7 @@ class MultiProviderController(final IList providers) extends AsyncNotifier { @override Future build() => .wait( - providers.map((provider) => ref.read(provider.future)), + providers.map((provider) => ref.watch(provider.future)), eagerError: true, ); diff --git a/lib/controllers/unified_push.dart b/lib/controllers/unified_push.dart index 7dbc386..719a096 100644 --- a/lib/controllers/unified_push.dart +++ b/lib/controllers/unified_push.dart @@ -22,7 +22,6 @@ class UnifiedPushController extends AsyncNotifier { Future build() async { if (!Platform.isLinux && !Platform.isAndroid) return false; - final client = ref.watch(ClientController.provider.notifier); final registered = await UnifiedPush.initialize( linuxOptions: .new( dbusName: "nexus.federated.nexus.UnifiedPush", @@ -36,21 +35,23 @@ class UnifiedPushController extends AsyncNotifier { .watch(PushKeyController.provider(instance).notifier) .set(pushKey); - await client.registerPusher( - .new( - appDisplayName: "Nexus", - appId: "nexus.federated.nexus", - data: .webPush( - url: .parse(endpoint.url), - auth: endpoint.pubKeySet!.auth, - ), - deviceDisplayName: - "Nexus on ${toBeginningOfSentenceCase(Platform.operatingSystem)}", - kind: .webPush, - lang: "en", - pushKey: pushKey, - ), - ); + await ref + .watch(ClientController.provider.notifier) + .registerPusher( + .new( + appDisplayName: "Nexus", + appId: "nexus.federated.nexus", + data: .webPush( + url: .parse(endpoint.url), + auth: endpoint.pubKeySet!.auth, + ), + deviceDisplayName: + "Nexus on ${toBeginningOfSentenceCase(Platform.operatingSystem)}", + kind: .webPush, + lang: "en", + pushKey: pushKey, + ), + ); }, onMessage: (message, instance) async { debugPrint("UP message received for $instance"); @@ -59,9 +60,9 @@ class UnifiedPushController extends AsyncNotifier { "Failed to decrypt notification. Try toggling off and on UnifiedPush in settings.", ); } - final event = await client.handlePush( - json.decode(String.fromCharCodes(message.content)), - ); + final event = await ref + .watch(ClientController.provider.notifier) + .handlePush(json.decode(String.fromCharCodes(message.content))); if (event == null || event.unreadType?.shouldNotify() != true || @@ -120,8 +121,11 @@ class UnifiedPushController extends AsyncNotifier { } Future register([bool alreadyRegistered = false]) async { - final clientState = ref.watch(ClientStateController.provider); - if (clientState?.deviceId == null) return ref.invalidateSelf(); + final clientStateProvider = ClientStateController.provider; + while (ref.watch(clientStateProvider)?.deviceId == null) { + await Future.delayed(.new(milliseconds: 250)); + } + final clientState = ref.watch(clientStateProvider); final capabilities = await ref .watch(ClientController.provider.notifier) diff --git a/lib/main.dart b/lib/main.dart index 903456e..f2794fe 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -151,54 +151,56 @@ class const App({super.key}) extends StatelessWidget { builder: (_, ref, _) => ref .watch(ClientController.provider) .betterWhen( - data: (_) => ref - .watch( - MultiProviderController.provider( - .new([ - NotificationController.provider, - UnifiedPushController.provider, - MemberListOpenedController.provider, - KeyController.provider(KeyController.roomKey), - KeyController.provider(KeyController.spaceKey), - ]), - ), - ) - .betterWhen( - data: (_) => Consumer( - builder: (_, ref, _) { - final clientState = ref.watch( - ClientStateController.provider, - ); - - if (clientState == null || - !clientState.isInitialized) { - return Loading(); - } - - if (!clientState.isLoggedIn) { - return SelectServerPage(); - } else if (!clientState.isVerified) { - return VerifyPage(); - } else { - return ChatPage(); - } - }, - ), - ), - loading: () => Scaffold( - appBar: Appbar( - actions: .new([ - IconButton( - onPressed: () => showDialog( - context: context, - builder: (_) => SettingsPage(), - ), - icon: Icon(Icons.settings), - ), + data: (_) => switch (ref.watch( + MultiProviderController.provider( + .new([ + NotificationController.provider, + UnifiedPushController.provider, + MemberListOpenedController.provider, + KeyController.provider(KeyController.roomKey), + KeyController.provider(KeyController.spaceKey), ]), ), - body: Loading(), - ), + )) { + AsyncData(value: _) || AsyncLoading(value: _?) => Consumer( + builder: (_, ref, _) { + final clientState = ref.watch( + ClientStateController.provider, + ); + + if (clientState == null || !clientState.isInitialized) { + return Loading(); + } + + if (!clientState.isLoggedIn) { + return SelectServerPage(); + } else if (!clientState.isVerified) { + return VerifyPage(); + } else { + return ChatPage(); + } + }, + ), + + AsyncLoading _ => Scaffold( + appBar: Appbar( + actions: .new([ + IconButton( + onPressed: () => showDialog( + context: context, + builder: (_) => SettingsPage(), + ), + icon: Icon(Icons.settings), + ), + ]), + ), + body: Loading(), + ), + AsyncError(:final error, :final stackTrace) => ErrorDialog( + error, + stackTrace, + ), + }, ), ), ),