feat(tutorial): wire tutorial carousel into the first-launch flow
Insert PantallaTutorialAyuda.mostrarSiProcede between the welcome screen and the recurring what's-new dialog in _mostrarFlujoPrimerLanzamiento, so the carousel shows once on every install -- fresh AND existing installs upgrading to this version -- via its own independent one-time flag, without racing either surface.
This commit is contained in:
@@ -12,23 +12,12 @@ import 'package:pluriwave/widgets/pluri_root_header.dart';
|
||||
/// sleep-timer action that used to live on `app.dart`'s single global
|
||||
/// `AppBar` stays reachable from every tab.
|
||||
void main() {
|
||||
// [topInset] simulates `MediaQuery.paddingOf(context).top` (status bar /
|
||||
// camera cutout) — the same technique already used by
|
||||
// `pantalla_alarma_sonando_scaffold_test.dart`'s `MediaQuery` override via
|
||||
// `MaterialApp.builder`.
|
||||
Widget host(Widget child, {double topInset = 0}) {
|
||||
Widget host(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: PluriWaveTheme.dark(),
|
||||
locale: const Locale('en'),
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
builder:
|
||||
(context, app) => MediaQuery(
|
||||
data: MediaQuery.of(
|
||||
context,
|
||||
).copyWith(padding: EdgeInsets.only(top: topInset)),
|
||||
child: app!,
|
||||
),
|
||||
home: Scaffold(body: child),
|
||||
);
|
||||
}
|
||||
@@ -53,13 +42,7 @@ void main() {
|
||||
host(PluriRootHeader(title: 'Settings', onSleepTimer: () {})),
|
||||
);
|
||||
|
||||
// Keyed lookup (not `find.byType(Padding).first`): the top-inset fix
|
||||
// wraps this content padding in an outer `Padding(top: topInset)`, so
|
||||
// `.first` would no longer reliably resolve to the content row's own
|
||||
// padding.
|
||||
final padding = tester.widget<Padding>(
|
||||
find.byKey(const ValueKey('pluri-root-header-content')),
|
||||
);
|
||||
final padding = tester.widget<Padding>(find.byType(Padding).first);
|
||||
final insets = padding.padding as EdgeInsets;
|
||||
expect(insets.left, PluriLayout.titleHorizontal);
|
||||
expect(insets.right, PluriLayout.rowHorizontal);
|
||||
@@ -114,92 +97,4 @@ void main() {
|
||||
reason: 'actions render before (to the left of) the bedtime button',
|
||||
);
|
||||
});
|
||||
|
||||
group('fix top-inset: total height and content position track '
|
||||
'MediaQuery.paddingOf(context).top, instead of always sitting flush '
|
||||
'at y=0 under the status bar', () {
|
||||
// Vertical text centering inside the 56px content row means the
|
||||
// title's own top-left never sits exactly AT the header's top-left
|
||||
// (even at topInset=0) — so these tests compare each inset's title
|
||||
// position against the topInset=0 BASELINE, isolating exactly the
|
||||
// inset's own contribution instead of asserting a brittle absolute
|
||||
// offset.
|
||||
Future<double> tituloTopPara(WidgetTester tester, double topInset) async {
|
||||
await tester.pumpWidget(
|
||||
host(
|
||||
PluriRootHeader(title: 'Settings', onSleepTimer: () {}),
|
||||
topInset: topInset,
|
||||
),
|
||||
);
|
||||
return tester.getTopLeft(find.text('Settings')).dy;
|
||||
}
|
||||
|
||||
testWidgets(
|
||||
'topInset=0 (e.g. desktop/no cutout): total height stays the plain '
|
||||
'56px content height',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
host(PluriRootHeader(title: 'Settings', onSleepTimer: () {})),
|
||||
);
|
||||
|
||||
expect(tester.getSize(find.byType(PluriRootHeader)).height, 56);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'topInset=24 (typical status bar): total height becomes 56+24=80, '
|
||||
'and the title shifts down by exactly the inset relative to the '
|
||||
'topInset=0 baseline',
|
||||
(tester) async {
|
||||
final base = await tituloTopPara(tester, 0);
|
||||
final conInset = await tituloTopPara(tester, 24);
|
||||
|
||||
expect(tester.getSize(find.byType(PluriRootHeader)).height, 80);
|
||||
expect(conInset - base, 24);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'topInset=44 (taller status bar): total height becomes 56+44=100, '
|
||||
'and the title still shifts down by exactly the inset — never '
|
||||
'clipped',
|
||||
(tester) async {
|
||||
final base = await tituloTopPara(tester, 0);
|
||||
final conInset = await tituloTopPara(tester, 44);
|
||||
|
||||
expect(tester.getSize(find.byType(PluriRootHeader)).height, 100);
|
||||
expect(conInset - base, 44);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'topInset=60 (notch/camera-cutout simulation): total height becomes '
|
||||
'56+60=116, and the title still fully clears the inset — never '
|
||||
'overlapping it',
|
||||
(tester) async {
|
||||
final base = await tituloTopPara(tester, 0);
|
||||
final conInset = await tituloTopPara(tester, 60);
|
||||
|
||||
expect(tester.getSize(find.byType(PluriRootHeader)).height, 116);
|
||||
expect(conInset - base, 60);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'PluriRootHeader.height stays the CONTENT height (56) regardless of '
|
||||
'inset — callers doing total-height math must separately add '
|
||||
'MediaQuery.paddingOf(context).top',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(
|
||||
host(
|
||||
PluriRootHeader(title: 'Settings', onSleepTimer: () {}),
|
||||
topInset: 44,
|
||||
),
|
||||
);
|
||||
|
||||
expect(PluriRootHeader.height, 56);
|
||||
expect(tester.getSize(find.byType(PluriRootHeader)).height, 100);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user