From ae166127d6a1b9192cf401eed8ad3e82433e242e Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 15 Oct 2026 18:04:49 -0700 Subject: [PATCH] fix(mobile): preserve current screen during browser sign-in Co-authored-by: Brain <1a02c72794dcd0f07058a353bc3a81f4028b8c77c92c87fce6d5c8b85970a20b@buzz.block.builderlab.xyz> Signed-off-by: Wes --- mobile/lib/hosted_app_gate.dart | 8 ++++++++ .../features/onboarding/hosted_communities_test.dart | 12 ++++++++++++ mobile/test/helpers/hosted_communities_fixture.dart | 10 ++++++---- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/mobile/lib/hosted_app_gate.dart b/mobile/lib/hosted_app_gate.dart index 1c34b0c3d8..a1b551cd06 100644 --- a/mobile/lib/hosted_app_gate.dart +++ b/mobile/lib/hosted_app_gate.dart @@ -96,6 +96,13 @@ class HostedAppGate extends HookConsumerWidget { final visible = flow.stage != HostedFlowStage.idle && flow.stage != HostedFlowStage.complete; + // Native browser authentication presents its own alert over the current + // screen. Keep that screen in place while checking the session/opening it. + final openingSignIn = + flow.stage == HostedFlowStage.signIn || + (flow.accountOnly && + flow.stage == HostedFlowStage.working && + flow.account.account == null); return DeepLinkDispatcher( dispatchMessageLinks: authenticated && !visible, onboardingHandler: (routeContext, link) async { @@ -178,6 +185,7 @@ class HostedAppGate extends HookConsumerWidget { children: [ child, if (visible && + !openingSignIn && (!inlineEntry || flow.accountOnly || flow.stage == HostedFlowStage.chooseIdentity)) diff --git a/mobile/test/features/onboarding/hosted_communities_test.dart b/mobile/test/features/onboarding/hosted_communities_test.dart index d99f36efc1..4798a2a627 100644 --- a/mobile/test/features/onboarding/hosted_communities_test.dart +++ b/mobile/test/features/onboarding/hosted_communities_test.dart @@ -41,6 +41,18 @@ void main() { ), ); await tester.pumpAndSettle(); + f.expired = true; + await tester.tap(find.text('Continue with Builderlab')); + await tester.pump(); + await tester.pumpAndSettle(); + expect(f.flow.stage, HostedFlowStage.signIn); + expect(f.browser.startedIntent, {'type': 'account'}); + expect(find.byType(HostedConnectPage), findsNothing); + expect(find.text('Signing in…').hitTestable(), findsOneWidget); + expect(find.text('Enter a community link'), findsOneWidget); + await f.flow.leave(); + f.expired = false; + await tester.pumpAndSettle(); expect(find.text('Continue with Builderlab'), findsOneWidget); expect(find.byType(HostedConnectPage), findsNothing); await tester.tap(find.text('Continue with Builderlab')); diff --git a/mobile/test/helpers/hosted_communities_fixture.dart b/mobile/test/helpers/hosted_communities_fixture.dart index 9c2d9c21f4..915d7f0a97 100644 --- a/mobile/test/helpers/hosted_communities_fixture.dart +++ b/mobile/test/helpers/hosted_communities_fixture.dart @@ -41,10 +41,12 @@ class WidgetDiscoveryAccount extends BuilderlabAccountClient { WidgetDiscoveryAccount(this.fixture); final HostedCommunitiesFixture fixture; @override - BuilderlabAccount get account => BuilderlabAccount( - subject: fixture.subject, - expiresAt: DateTime.now().add(const Duration(hours: 1)), - ); + BuilderlabAccount? get account => fixture.expired + ? null + : BuilderlabAccount( + subject: fixture.subject, + expiresAt: DateTime.now().add(const Duration(hours: 1)), + ); @override Future restore() async => account; @override