general cleanups and mounted guards

This commit is contained in:
Henry Hiles 2026-10-24 12:02:23 -04:00
commit 0a09a4ee0a
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
5 changed files with 33 additions and 22 deletions

View file

@ -200,14 +200,8 @@ class ClientController extends AsyncNotifier<int> {
Future<String?> setState(SetStateRequest request) async => Future<String?> setState(SetStateRequest request) async =>
await _sendCommand("set_state", request.toJson()); await _sendCommand("set_state", request.toJson());
Future<String?> verify(String recoveryKey) async { Future<void> verify(String recoveryKey) =>
try { _sendCommand("verify", {"recovery_key": recoveryKey});
await _sendCommand("verify", {"recovery_key": recoveryKey});
return null;
} catch (error) {
return error.toString();
}
}
Future<RecoveryKey> generateRecoveryKey(String passphrase) async => .fromJson( Future<RecoveryKey> generateRecoveryKey(String passphrase) async => .fromJson(
await _sendCommand("generate_recovery_key", {"passphrase": passphrase}), await _sendCommand("generate_recovery_key", {"passphrase": passphrase}),

View file

@ -169,7 +169,7 @@ class NotificationController
if (Platform.isLinux) { if (Platform.isLinux) {
final portal = await ref.read(PortalController.provider.future); final portal = await ref.read(PortalController.provider.future);
const escape = HtmlEscape(HtmlEscapeMode.element); const escape = HtmlEscape(.element);
await portal.notification.addNotification( await portal.notification.addNotification(
id.toString(), id.toString(),

View file

@ -160,8 +160,8 @@ class const App({super.key}) extends StatelessWidget {
MultiProviderController.provider( MultiProviderController.provider(
.new([ .new([
GomuksListenerController.provider, GomuksListenerController.provider,
NotificationController.provider,
UnifiedPushController.provider, UnifiedPushController.provider,
NotificationController.provider,
MemberListOpenedController.provider, MemberListOpenedController.provider,
KeyController.provider(KeyController.roomKey), KeyController.provider(KeyController.roomKey),
KeyController.provider(KeyController.spaceKey), KeyController.provider(KeyController.spaceKey),

View file

@ -60,6 +60,8 @@ class const SelectServerPage({super.key}) extends HookConsumerWidget {
return; return;
} }
if (!context.mounted) return;
await ref.read(LaunchHelper.provider).launchUrl(codeResponse.url); await ref.read(LaunchHelper.provider).launchUrl(codeResponse.url);
AppLinks().uriLinkStream.listen((encodedUri) async { AppLinks().uriLinkStream.listen((encodedUri) async {
@ -70,7 +72,7 @@ class const SelectServerPage({super.key}) extends HookConsumerWidget {
try { try {
final code = encodedUri.queryParameters["code"]; final code = encodedUri.queryParameters["code"];
if (code != null) { if (code != null && context.mounted) {
await ref await ref
.read(ClientController.provider.notifier) .read(ClientController.provider.notifier)
.exchangeToken( .exchangeToken(

View file

@ -18,6 +18,7 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
final isLoading = useState(false); final isLoading = useState(false);
final inputError = useState<String?>(null); final inputError = useState<String?>(null);
final formKey = useRef(GlobalKey<FormState>()); final formKey = useRef(GlobalKey<FormState>());
final verificationState = ref.watch( final verificationState = ref.watch(
ClientStateController.provider.select( ClientStateController.provider.select(
(state) => state?.verificationState, (state) => state?.verificationState,
@ -25,18 +26,24 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
); );
Future<void> verify() async { Future<void> verify() async {
if (isLoading.value) return;
if (formKey.value.currentState?.validate() != true) {
return;
}
isLoading.value = true; isLoading.value = true;
try { try {
if (formKey.value.currentState?.validate() != true) { await ref
return;
}
inputError.value = await ref
.read(ClientController.provider.notifier) .read(ClientController.provider.notifier)
.verify(passphraseController.text); .verify(passphraseController.text);
} catch (error) {
inputError.value = error.toString();
} finally { } finally {
isLoading.value = false; if (context.mounted) {
isLoading.value = false;
}
} }
} }
@ -52,7 +59,8 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
), ),
body: switch (verificationState) { body: switch (verificationState) {
null || VerificationState(stateChecked: false) => const Loading(), null || VerificationState(stateChecked: false) => const Loading(),
// Nothing to verify with yet, so go straight to setting it up.
// Nothing to verify yet, so go straight to setup.
VerificationState(hasSecretStorage: false) => Dialog( VerificationState(hasSecretStorage: false) => Dialog(
insetPadding: const .symmetric(vertical: 12, horizontal: 32), insetPadding: const .symmetric(vertical: 12, horizontal: 32),
child: ConstrainedBox( child: ConstrainedBox(
@ -60,6 +68,7 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
child: const ResetEncryptionSheet(isPage: true), child: const ResetEncryptionSheet(isPage: true),
), ),
), ),
_ => AlertDialog( _ => AlertDialog(
insetPadding: .symmetric(vertical: 12, horizontal: 32), insetPadding: .symmetric(vertical: 12, horizontal: 32),
scrollable: true, scrollable: true,
@ -71,7 +80,9 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
crossAxisAlignment: .start, crossAxisAlignment: .start,
children: [ children: [
Text( Text(
"Enter your recovery key or passphrase below to unlock encrypted events.\nYour passphrase is usually not the same as your password.", "Enter your recovery key or passphrase below to "
"unlock encrypted events.\nYour passphrase is usually "
"not the same as your password.",
), ),
SizedBox(height: 12), SizedBox(height: 12),
TextFormField( TextFormField(
@ -94,9 +105,13 @@ class const VerifyPage({super.key}) extends HookConsumerWidget {
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.showAdaptiveSheet( onPressed: isLoading.value
(_) => const ResetEncryptionSheet(), ? null
), : () {
context.showAdaptiveSheet(
(_) => const ResetEncryptionSheet(),
);
},
style: TextButton.styleFrom( style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error, foregroundColor: Theme.of(context).colorScheme.error,
), ),