diff --git a/lib/features/sessions/presentation/screens/session_dashboard_screen.dart b/lib/features/sessions/presentation/screens/session_dashboard_screen.dart index 31f198c..6b02abd 100644 --- a/lib/features/sessions/presentation/screens/session_dashboard_screen.dart +++ b/lib/features/sessions/presentation/screens/session_dashboard_screen.dart @@ -544,9 +544,14 @@ class _SessionDashboardScreenState required NpcInstancesState npcInstancesState, required SessionsState sessionsState, }) { + // Note: these columns intentionally do NOT get their own + // SingleChildScrollView - the whole page already scrolls via the + // SingleChildScrollView below, and nesting an unbounded-height + // scrollable inside another (previously also wrapped in + // IntrinsicHeight) collapsed every column to zero height on web. Widget column(String title, Widget body, {Widget? headingTrailing}) { return Expanded( - child: SingleChildScrollView( + child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -600,23 +605,21 @@ class _SessionDashboardScreenState children: [ _sessionInfoCard(), const SizedBox(height: 24), - IntrinsicHeight( - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - leftColumn, - column( - 'NPCs em Combate', - _npcsBody( - npcInstancesState, - isGm, - showNpcHp, - crossAxisCount: 2, - ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + leftColumn, + column( + 'NPCs em Combate', + _npcsBody( + npcInstancesState, + isGm, + showNpcHp, + crossAxisCount: 2, ), - column('Log de Combate', _logBody(isGm)), - ], - ), + ), + column('Log de Combate', _logBody(isGm)), + ], ), ], ), diff --git a/test/features/sessions/presentation/screens/session_dashboard_screen_test.dart b/test/features/sessions/presentation/screens/session_dashboard_screen_test.dart index a01f8b1..48214e7 100644 --- a/test/features/sessions/presentation/screens/session_dashboard_screen_test.dart +++ b/test/features/sessions/presentation/screens/session_dashboard_screen_test.dart @@ -344,10 +344,28 @@ void main() { await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); + // Regression guard: catches layout errors (e.g. IntrinsicHeight + + // nested SingleChildScrollView) that Flutter swallows into a + // per-subtree error widget instead of failing the pump outright - + // find.text() alone wouldn't detect those, since the Text widgets + // are still built even when their RenderObject fails to lay out. + expect(tester.takeException(), isNull); + expect(find.text('SESSÕES'), findsOneWidget); expect(find.text('Voltar à campanha'), findsOneWidget); // FAB is mobile-only. expect(find.byKey(const Key('session_add_npc_fab')), findsNothing); + + // Regression guard: the 3-column layout previously collapsed to zero + // height on web (IntrinsicHeight + nested SingleChildScrollView), + // hiding every column's content behind the sidebar/session card. + expect(find.text('Jogadores'), findsOneWidget); + expect(find.text('NPCs em Combate'), findsOneWidget); + expect(find.text('Log de Combate'), findsOneWidget); + expect( + find.text('Nenhum jogador com ficha ativa nesta campanha.'), + findsOneWidget, + ); }); }); }