fix(#1030): act on the Gemini review of the app-only settings

Route into the app on return from settings only when the scanner is the current route again, the same condition the connection listener uses. A popping route is outside the navigator's present set, so the settings route does not block it.

The share tests now wait frame by frame on their own condition instead of a fixed 2-second window, and the persistence checks were re-proven to fail with persist: false.

Correct a stale comment: the Experimental unlock is on the Device Info Build row, not About.

Agent: BrightDog (session 38fb0e08)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix/1033-scan-location-message
diffwireauto 2 weeks ago committed by Strycher
parent 92a9cd75a2
commit d469fd502e

@ -103,8 +103,12 @@ class _ScannerScreenState extends State<ScannerScreen> {
).push(MaterialPageRoute(builder: (_) => const AppOnlySettingsScreen()));
// A connection that completed while settings were open routed nowhere,
// because this screen was not the current route. Route in now, as the
// connection listener would have.
// connection listener would have, and under the same condition: only if
// this screen is current again, not covered by some other route. The
// settings route is already out of the "present" set by the time its
// future completes, so it does not count against that check.
if (mounted &&
(ModalRoute.of(context)?.isCurrent ?? true) &&
_connector.state == MeshCoreConnectionState.connected &&
!_routingIntoApp) {
_routeIntoApp();

@ -154,8 +154,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
);
// Owner-only Experimental section (#509), revealed by the 7-tap gesture on
// the About version row. Selects narrowly so the category list only rebuilds
// when the flag flips, not on every connector update (same reason as above).
// the Device Info Build row. Selects narrowly so the category list only
// rebuilds when the flag flips, not on every connector update (same reason
// as above).
final experimentalUnlocked = context.select<AppSettingsService, bool>(
(s) => s.settings.experimentalUnlocked,
);

@ -79,19 +79,26 @@ Future<AppLocalizations> _openFromScanner(WidgetTester tester) async {
return l10n;
}
/// Run the real-IO export in the real zone and wait for it to settle, either
/// at the share sheet or at a message on screen.
Future<void> _tapShareAndSettle(WidgetTester tester, String label) async {
final before = _shared.length;
await tester.runAsync(() async {
await tester.tap(find.text(label));
for (var i = 0; i < 100 && _shared.length == before; i++) {
await Future<void>.delayed(const Duration(milliseconds: 20));
}
});
await tester.pump();
/// Tap Share in the real zone, where the export's file IO can run, then let
/// it progress frame by frame until [done] holds. The ceiling is generous so
/// a slow runner waits rather than flakes; a run that never gets there fails
/// on the caller's next expectation.
Future<void> _tapShareUntil(
WidgetTester tester,
String label,
bool Function() done,
) async {
await tester.runAsync(() => tester.tap(find.text(label)));
for (var i = 0; i < 300 && !done(); i++) {
await tester.runAsync(
() => Future<void>.delayed(const Duration(milliseconds: 50)),
);
await tester.pump();
}
}
bool _shown(String text) => find.text(text).evaluate().isNotEmpty;
/// Drain ScannerScreen's dispose-time disconnect before teardown.
Future<void> _unmount(WidgetTester tester) async {
await tester.pumpWidget(const SizedBox.shrink());
@ -214,7 +221,11 @@ void main() {
await tester.pumpAndSettle();
final sharesBefore = _shared.length;
await _tapShareAndSettle(tester, l10n.debugLog_shareLog);
await _tapShareUntil(
tester,
l10n.debugLog_shareLog,
() => _shared.length > sharesBefore,
);
expect(_shared.length, sharesBefore + 1);
final logDir = FileLogService.instance.logDir!.path;
@ -239,7 +250,12 @@ void main() {
await tester.tap(find.text(l10n.settings_debug));
await tester.pumpAndSettle();
await _tapShareAndSettle(tester, l10n.debugLog_shareLog);
await _tapShareUntil(
tester,
l10n.debugLog_shareLog,
() => _shown(l10n.debugLog_exportFailed),
);
// Finish the entrance animation, which is what starts the timeout.
await tester.pump(const Duration(seconds: 1));
expect(find.text(l10n.debugLog_exportFailed), findsOneWidget);
@ -266,7 +282,11 @@ void main() {
await tester.pumpAndSettle();
final sharesBefore = _shared.length;
await _tapShareAndSettle(tester, l10n.debugLog_shareLog);
await _tapShareUntil(
tester,
l10n.debugLog_shareLog,
() => _shown(l10n.debugLog_logUnavailable),
);
await tester.pump(const Duration(seconds: 1));
expect(_shared.length, sharesBefore, reason: 'nothing to hand over');
expect(find.text(l10n.debugLog_logUnavailable), findsOneWidget);

Loading…
Cancel
Save

Powered by TurnKey Linux.