diff --git a/apps/mobile_app/lib/app/app_theme.dart b/apps/mobile_app/lib/app/app_theme.dart index 346603a..b92774f 100644 --- a/apps/mobile_app/lib/app/app_theme.dart +++ b/apps/mobile_app/lib/app/app_theme.dart @@ -3,18 +3,21 @@ import 'package:flutter/material.dart'; class AppTheme { static const EdgeInsets pagePadding = EdgeInsets.fromLTRB(20, 16, 20, 24); static const EdgeInsets panelPadding = EdgeInsets.all(16); - static const BorderRadius panelRadius = BorderRadius.all(Radius.circular(24)); + static const BorderRadius panelRadius = BorderRadius.all(Radius.circular(22)); static ThemeData build() { - const background = Color(0xFF09111C); - const surface = Color(0xFF111C2C); - const surfaceHigh = Color(0xFF182538); - const surfaceHighest = Color(0xFF1E2E45); - const outline = Color(0xFF2C405F); - const outlineVariant = Color(0xFF22324A); - const accent = Color(0xFF67CFFF); - const secondary = Color(0xFF7AA6FF); - const tertiary = Color(0xFF77E3CF); + const background = Color(0xFF05070A); + const surface = Color(0xFF101419); + const surfaceHigh = Color(0xFF151B21); + const surfaceHighest = Color(0xFF1A222B); + const outline = Color(0xFF3A4652); + const outlineVariant = Color(0xFF252E37); + const accent = Color(0xFFC2A574); + const secondary = Color(0xFF8EA3B8); + const tertiary = Color(0xFF8EB8A7); + const onSurface = Color(0xFFF3EFE7); + const subText = Color(0xFFBBB3A7); + const mutedText = Color(0xFF91897E); final scheme = const ColorScheme.dark().copyWith( primary: accent, @@ -26,6 +29,9 @@ class AppTheme { surfaceContainerHighest: surfaceHighest, outline: outline, outlineVariant: outlineVariant, + onPrimary: onSurface, + onSecondary: onSurface, + onSurface: onSurface, error: const Color(0xFFFF7575), ); @@ -36,6 +42,8 @@ class AppTheme { scaffoldBackgroundColor: background, canvasColor: background, splashFactory: InkSparkle.splashFactory, + highlightColor: Colors.transparent, + hoverColor: Colors.transparent, ); return base.copyWith( @@ -44,28 +52,51 @@ class AppTheme { elevation: 0, backgroundColor: background, surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, titleTextStyle: base.textTheme.titleLarge?.copyWith( - color: Colors.white, - fontWeight: FontWeight.w700, + color: onSurface, + fontWeight: FontWeight.w800, + letterSpacing: -0.45, ), + iconTheme: const IconThemeData(color: Color(0xFFD7D0C5)), ), textTheme: base.textTheme.copyWith( headlineSmall: base.textTheme.headlineSmall?.copyWith( - fontWeight: FontWeight.w700, - letterSpacing: -0.4, + color: onSurface, + fontWeight: FontWeight.w800, + height: 1.02, + letterSpacing: -1.05, ), titleMedium: base.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, + color: onSurface, + fontWeight: FontWeight.w700, + letterSpacing: -0.3, ), titleSmall: base.textTheme.titleSmall?.copyWith( - fontWeight: FontWeight.w600, + color: onSurface, + fontWeight: FontWeight.w700, + letterSpacing: -0.2, ), labelLarge: base.textTheme.labelLarge?.copyWith( - fontWeight: FontWeight.w700, + color: const Color(0xFFD1C2A7), + fontWeight: FontWeight.w800, + fontSize: 11, + letterSpacing: 1.7, + ), + labelMedium: base.textTheme.labelMedium?.copyWith( + color: mutedText, + fontWeight: FontWeight.w600, letterSpacing: 0.4, ), + bodyMedium: base.textTheme.bodyMedium?.copyWith( + color: subText, + fontWeight: FontWeight.w500, + height: 1.38, + ), bodySmall: base.textTheme.bodySmall?.copyWith( - color: const Color(0xFFA4B4CB), + color: mutedText, + fontWeight: FontWeight.w500, + height: 1.4, ), ), cardTheme: const CardThemeData( @@ -80,57 +111,93 @@ class AppTheme { inputDecorationTheme: InputDecorationTheme( isDense: true, filled: true, - fillColor: surface, - hintStyle: const TextStyle(color: Color(0xFF8195B2)), - labelStyle: const TextStyle(color: Color(0xFFAFC1DB)), + fillColor: const Color(0xFF0C1014), + hintStyle: const TextStyle(color: mutedText), + labelStyle: const TextStyle( + color: subText, + fontWeight: FontWeight.w500, + ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 14, ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(18), - borderSide: const BorderSide(color: outlineVariant), + borderSide: const BorderSide(color: outlineVariant, width: 1), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(18), - borderSide: const BorderSide(color: outlineVariant), + borderSide: const BorderSide(color: outlineVariant, width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(18), - borderSide: const BorderSide(color: accent), + borderSide: const BorderSide(color: accent, width: 1.15), + ), + disabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(18), + borderSide: const BorderSide(color: outlineVariant, width: 1), ), ), filledButtonTheme: FilledButtonThemeData( style: FilledButton.styleFrom( minimumSize: const Size(0, 48), - backgroundColor: accent, - foregroundColor: const Color(0xFF05111D), + backgroundColor: const Color(0xFFD6CBC0), + foregroundColor: const Color(0xFF14100C), + textStyle: const TextStyle( + fontWeight: FontWeight.w700, + letterSpacing: 0.15, + ), + elevation: 0, + overlayColor: const Color(0x140F0C09), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.circular(16), ), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: OutlinedButton.styleFrom( minimumSize: const Size(0, 48), - side: const BorderSide(color: outline), - foregroundColor: const Color(0xFFE8F1FF), + side: const BorderSide(color: outline, width: 1), + foregroundColor: const Color(0xFFEAE2D7), + textStyle: const TextStyle( + fontWeight: FontWeight.w700, + letterSpacing: 0.15, + ), + backgroundColor: const Color(0xFF14191F), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18), + borderRadius: BorderRadius.circular(16), + ), + ), + ), + textButtonTheme: TextButtonThemeData( + style: TextButton.styleFrom( + foregroundColor: const Color(0xFFD2BF9A), + textStyle: const TextStyle( + fontWeight: FontWeight.w700, + letterSpacing: 0.1, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14), ), ), ), iconButtonTheme: IconButtonThemeData( - style: IconButton.styleFrom(foregroundColor: const Color(0xFFD7E4F8)), + style: IconButton.styleFrom( + foregroundColor: const Color(0xFFE0D9CF), + backgroundColor: Colors.transparent, + ), ), floatingActionButtonTheme: const FloatingActionButtonThemeData( - backgroundColor: accent, - foregroundColor: Color(0xFF05111D), + backgroundColor: Color(0xFFB89460), + foregroundColor: Color(0xFF120F0B), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(18)), + ), ), snackBarTheme: SnackBarThemeData( behavior: SnackBarBehavior.floating, backgroundColor: surfaceHighest, - contentTextStyle: const TextStyle(color: Color(0xFFF2F7FF)), + contentTextStyle: const TextStyle(color: onSurface), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(18)), ), dividerTheme: const DividerThemeData(color: outlineVariant, thickness: 1), diff --git a/apps/mobile_app/lib/app/ui_shell.dart b/apps/mobile_app/lib/app/ui_shell.dart index 775161f..83e987e 100644 --- a/apps/mobile_app/lib/app/ui_shell.dart +++ b/apps/mobile_app/lib/app/ui_shell.dart @@ -2,28 +2,77 @@ import 'package:flutter/material.dart'; import 'app_theme.dart'; +enum AppPanelTone { primary, subdued, emphasis } + class AppPanel extends StatelessWidget { const AppPanel({ super.key, required this.child, this.padding = AppTheme.panelPadding, this.borderRadius = AppTheme.panelRadius, + this.tone = AppPanelTone.primary, }); final Widget child; final EdgeInsetsGeometry padding; final BorderRadiusGeometry borderRadius; + final AppPanelTone tone; @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; + final palette = switch (tone) { + AppPanelTone.primary => ( + base: colorScheme.surfaceContainerHighest, + edge: colorScheme.outlineVariant, + glow: const Color(0x22000000), + ), + AppPanelTone.subdued => ( + base: colorScheme.surfaceContainerHigh, + edge: colorScheme.outlineVariant.withValues(alpha: 0.8), + glow: const Color(0x18000000), + ), + AppPanelTone.emphasis => ( + base: const Color(0xFF161B21), + edge: const Color(0xFF4B4338), + glow: const Color(0x14000000), + ), + }; + return DecoratedBox( decoration: BoxDecoration( - color: colorScheme.surfaceContainerHighest, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Color.alphaBlend( + Colors.white.withValues(alpha: 0.035), + palette.base, + ), + palette.base, + ], + ), borderRadius: borderRadius, - border: Border.all(color: colorScheme.outlineVariant), + border: Border.all(color: palette.edge), + boxShadow: [ + BoxShadow( + color: palette.glow, + blurRadius: 22, + offset: const Offset(0, 10), + ), + ], + ), + child: DecoratedBox( + decoration: BoxDecoration( + borderRadius: borderRadius, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Colors.white.withValues(alpha: 0.02), Colors.transparent], + ), + ), + child: Padding(padding: padding, child: child), ), - child: Padding(padding: padding, child: child), ); } } @@ -45,10 +94,22 @@ class AppSectionHeader extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(eyebrow, style: Theme.of(context).textTheme.labelLarge), - const SizedBox(height: 8), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container(width: 28, height: 1, color: const Color(0xFF766855)), + const SizedBox(width: 8), + Text( + eyebrow.toUpperCase(), + style: Theme.of( + context, + ).textTheme.labelLarge?.copyWith(color: const Color(0xFFD0C0A3)), + ), + ], + ), + const SizedBox(height: 10), Text(title, style: Theme.of(context).textTheme.headlineSmall), - const SizedBox(height: 4), + const SizedBox(height: 6), Text(subtitle, style: Theme.of(context).textTheme.bodySmall), ], ); @@ -70,9 +131,29 @@ class AppEmptyState extends StatelessWidget { @override Widget build(BuildContext context) { return AppPanel( + tone: AppPanelTone.subdued, child: Column( children: [ - Icon(icon, size: 56, color: Theme.of(context).colorScheme.primary), + Container( + width: 64, + height: 64, + decoration: BoxDecoration( + color: Theme.of( + context, + ).colorScheme.primary.withValues(alpha: 0.09), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Theme.of( + context, + ).colorScheme.primary.withValues(alpha: 0.18), + ), + ), + child: Icon( + icon, + size: 28, + color: Theme.of(context).colorScheme.primary, + ), + ), const SizedBox(height: 16), Text( title, @@ -105,18 +186,23 @@ class StatusPill extends StatelessWidget { @override Widget build(BuildContext context) { + final backgroundColor = Color.alphaBlend( + color.withValues(alpha: 0.18), + Theme.of(context).colorScheme.surfaceContainerHigh, + ); + return DecoratedBox( decoration: BoxDecoration( - color: color.withValues(alpha: 0.14), + color: backgroundColor, borderRadius: BorderRadius.circular(999), - border: Border.all(color: color.withValues(alpha: 0.24)), + border: Border.all(color: color.withValues(alpha: 0.28)), ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 7), child: Row( mainAxisSize: MainAxisSize.min, children: [ - Icon(icon, size: 16, color: color), + Icon(icon, size: 14, color: color), const SizedBox(width: 6), Text( label, diff --git a/apps/mobile_app/lib/features/projects/project_list_page.dart b/apps/mobile_app/lib/features/projects/project_list_page.dart index a43815e..8814d97 100644 --- a/apps/mobile_app/lib/features/projects/project_list_page.dart +++ b/apps/mobile_app/lib/features/projects/project_list_page.dart @@ -356,7 +356,7 @@ class _ProjectListPageState extends ConsumerState { Text( 'Recent sessions', style: Theme.of(context).textTheme.labelLarge?.copyWith( - color: Theme.of(context).colorScheme.secondary, + color: const Color(0xFFD0C0A3), ), ), const SizedBox(height: 8), @@ -392,6 +392,7 @@ class _ProjectListPageState extends ConsumerState { final isCompact = MediaQuery.sizeOf(context).width < 420; return AppPanel( + tone: AppPanelTone.emphasis, key: const Key('agent_connection_panel'), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -400,6 +401,11 @@ class _ProjectListPageState extends ConsumerState { 'Agent base URL', style: Theme.of(context).textTheme.titleMedium, ), + const SizedBox(height: 6), + Text( + 'Remote endpoint', + style: Theme.of(context).textTheme.labelMedium, + ), const SizedBox(height: 12), if (isCompact) ...[ TextField( @@ -443,9 +449,21 @@ class _ProjectListPageState extends ConsumerState { ], ), const SizedBox(height: 8), - Text( - 'Project requests use this base origin: ${baseUri.toString()}.', - style: Theme.of(context).textTheme.bodySmall, + Container( + key: const Key('agent_connection_readout'), + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + color: Theme.of( + context, + ).colorScheme.surface.withValues(alpha: 0.72), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF3A342C)), + ), + child: Text( + 'Project requests use this base origin: ${baseUri.toString()}.', + style: Theme.of(context).textTheme.bodySmall, + ), ), ], ), @@ -481,7 +499,20 @@ class _ProjectListPageState extends ConsumerState { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Icon(Icons.folder_copy_outlined), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: const Color(0x22C2A574), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF443A2E)), + ), + child: Icon( + Icons.folder_copy_outlined, + size: 20, + color: const Color(0xFFC2A574), + ), + ), const SizedBox(width: 12), Expanded( child: Column( @@ -671,8 +702,13 @@ class _ProjectSessionRow extends StatelessWidget { Widget build(BuildContext context) { return DecoratedBox( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(12), + color: Theme.of(context).colorScheme.surface.withValues(alpha: 0.8), + borderRadius: BorderRadius.circular(14), + border: Border.all( + color: Theme.of( + context, + ).colorScheme.outlineVariant.withValues(alpha: 0.9), + ), ), child: Padding( padding: const EdgeInsets.fromLTRB(12, 8, 6, 8), diff --git a/apps/mobile_app/lib/features/sessions/session_list_page.dart b/apps/mobile_app/lib/features/sessions/session_list_page.dart index c8105d7..f996ec5 100644 --- a/apps/mobile_app/lib/features/sessions/session_list_page.dart +++ b/apps/mobile_app/lib/features/sessions/session_list_page.dart @@ -184,6 +184,7 @@ class _SessionListPageState extends ConsumerState { final isCompact = MediaQuery.sizeOf(context).width < 420; return AppPanel( + tone: AppPanelTone.emphasis, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -191,6 +192,11 @@ class _SessionListPageState extends ConsumerState { 'Agent base URL', style: Theme.of(context).textTheme.titleMedium, ), + const SizedBox(height: 6), + Text( + 'Runtime endpoint', + style: Theme.of(context).textTheme.labelMedium, + ), const SizedBox(height: 12), if (isCompact) ...[ TextField( @@ -234,9 +240,21 @@ class _SessionListPageState extends ConsumerState { ], ), const SizedBox(height: 8), - Text( - 'Session requests use this base origin: ${baseUri.toString()}.', - style: Theme.of(context).textTheme.bodySmall, + Container( + key: const Key('agent_connection_readout'), + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + color: Theme.of( + context, + ).colorScheme.surface.withValues(alpha: 0.72), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF3A342C)), + ), + child: Text( + 'Session requests use this base origin: ${baseUri.toString()}.', + style: Theme.of(context).textTheme.bodySmall, + ), ), ], ), @@ -272,7 +290,20 @@ class _SessionListPageState extends ConsumerState { Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Icon(Icons.memory_outlined), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: const Color(0x229E8A6B), + borderRadius: BorderRadius.circular(14), + border: Border.all(color: const Color(0xFF443A2E)), + ), + child: Icon( + Icons.memory_outlined, + size: 20, + color: const Color(0xFFB8A180), + ), + ), const SizedBox(width: 12), Expanded( child: Column( diff --git a/apps/mobile_app/lib/features/terminal/terminal_page.dart b/apps/mobile_app/lib/features/terminal/terminal_page.dart index 7d22bd0..333d84f 100644 --- a/apps/mobile_app/lib/features/terminal/terminal_page.dart +++ b/apps/mobile_app/lib/features/terminal/terminal_page.dart @@ -207,6 +207,7 @@ class _TerminalPageState extends ConsumerState { Future _showDiagnostics() { return showModalBottomSheet( context: context, + backgroundColor: const Color(0xFF13191F), isScrollControlled: true, builder: (context) { return SafeArea( @@ -230,10 +231,9 @@ class _TerminalPageState extends ConsumerState { width: double.infinity, padding: const EdgeInsets.all(10), decoration: BoxDecoration( - color: Theme.of( - context, - ).colorScheme.surfaceContainerHigh, + color: const Color(0xFF0E1217), borderRadius: BorderRadius.circular(12), + border: Border.all(color: const Color(0xFF2D241B)), ), child: _diagnosticLog.entries.isEmpty ? Text( @@ -270,6 +270,7 @@ class _TerminalPageState extends ConsumerState { Future _showToolsSheet() { return showModalBottomSheet( context: context, + backgroundColor: const Color(0xFF13191F), builder: (context) { return SafeArea( child: AnimatedBuilder( @@ -367,23 +368,27 @@ class _TerminalPageState extends ConsumerState { appBar: AppBar( toolbarHeight: 44, titleSpacing: 0, - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - widget.session.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.titleSmall, - ), - Text( - workingDirectory, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodySmall, - ), - ], + title: Container( + key: const Key('terminal_header_panel'), + padding: const EdgeInsets.symmetric(vertical: 2), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + widget.session.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.titleSmall, + ), + Text( + workingDirectory, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall, + ), + ], + ), ), actions: [ AnimatedBuilder( @@ -395,6 +400,7 @@ class _TerminalPageState extends ConsumerState { final modeLabel = '$mode | ${controller.liveLines.length} lines'; return Row( + key: const Key('terminal_status_summary'), mainAxisSize: MainAxisSize.min, children: [ TextButton( @@ -402,6 +408,7 @@ class _TerminalPageState extends ConsumerState { ? controller.enterScrollback : controller.jumpToLive, style: TextButton.styleFrom( + foregroundColor: const Color(0xFFD8C4A0), minimumSize: const Size(0, 32), padding: const EdgeInsets.symmetric(horizontal: 8), tapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -435,11 +442,16 @@ class _TerminalPageState extends ConsumerState { child: Container( key: const Key('terminal_surface_panel'), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHighest, - borderRadius: BorderRadius.zero, - border: Border.all( - color: Theme.of(context).colorScheme.outlineVariant, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Theme.of(context).colorScheme.surfaceContainerHighest, + const Color(0xFF090B0E), + ], ), + borderRadius: BorderRadius.zero, + border: Border.all(color: const Color(0xFF332B22)), ), child: TerminalView( terminal, @@ -472,6 +484,7 @@ class _TerminalPageState extends ConsumerState { child: Column( children: [ AppPanel( + tone: AppPanelTone.subdued, padding: const EdgeInsets.all(8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -510,8 +523,9 @@ class _TerminalPageState extends ConsumerState { constraints: const BoxConstraints(maxHeight: 64), child: DecoratedBox( decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, + color: const Color(0xFF0D1115), borderRadius: BorderRadius.zero, + border: Border.all(color: const Color(0xFF2A231B)), ), child: ListView.separated( key: const Key('terminal_scrollback_list'), @@ -547,8 +561,9 @@ class _TerminalPageState extends ConsumerState { vertical: 8, ), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, + color: const Color(0xFF0D1115), borderRadius: BorderRadius.zero, + border: Border.all(color: const Color(0xFF2A231B)), ), child: isCompact ? _buildCompactHistoryActions(context) @@ -559,6 +574,7 @@ class _TerminalPageState extends ConsumerState { ), const SizedBox(height: 6), AppPanel( + tone: AppPanelTone.emphasis, padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 8, @@ -570,7 +586,7 @@ class _TerminalPageState extends ConsumerState { Icon( Icons.pause_circle_outline, size: 18, - color: Theme.of(context).colorScheme.secondary, + color: const Color(0xFFC2A574), ), const SizedBox(width: 8), Expanded( @@ -675,6 +691,7 @@ class _TerminalPageState extends ConsumerState { Widget _buildCommandDeck(BuildContext context, bool isCompact) { return AppPanel( key: const Key('terminal_command_deck'), + tone: AppPanelTone.emphasis, padding: const EdgeInsets.fromLTRB(8, 6, 8, 6), borderRadius: BorderRadius.zero, child: AnimatedBuilder( @@ -685,6 +702,13 @@ class _TerminalPageState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ + Text( + 'Command deck', + style: Theme.of(context).textTheme.labelLarge?.copyWith( + color: const Color(0xFFD1C2A7), + ), + ), + const SizedBox(height: 8), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( @@ -698,6 +722,9 @@ class _TerminalPageState extends ConsumerState { ? () => _sendQuickKey(quickKey) : null, style: OutlinedButton.styleFrom( + foregroundColor: const Color(0xFFE8DED1), + backgroundColor: const Color(0xFF151A20), + side: const BorderSide(color: Color(0xFF3F3428)), minimumSize: const Size(0, 34), padding: const EdgeInsets.symmetric( horizontal: 10, @@ -746,6 +773,10 @@ class _TerminalPageState extends ConsumerState { key: const Key('terminal_direct_input_toggle'), onPressed: _canSendInput ? _toggleDirectInput : null, visualDensity: VisualDensity.compact, + style: IconButton.styleFrom( + backgroundColor: const Color(0xFF241F1A), + foregroundColor: const Color(0xFFD7C4A0), + ), icon: Icon( _isDirectInputEnabled ? Icons.keyboard_hide @@ -760,6 +791,10 @@ class _TerminalPageState extends ConsumerState { key: const Key('terminal_toggle_actions_button'), onPressed: _showToolsSheet, visualDensity: VisualDensity.compact, + style: IconButton.styleFrom( + backgroundColor: const Color(0xFF241F1A), + foregroundColor: const Color(0xFFD7C4A0), + ), icon: const Icon(Icons.tune), tooltip: 'Show tools', ), @@ -797,6 +832,10 @@ class _TerminalPageState extends ConsumerState { key: const Key('terminal_direct_input_toggle'), onPressed: _canSendInput ? _toggleDirectInput : null, visualDensity: VisualDensity.compact, + style: IconButton.styleFrom( + backgroundColor: const Color(0xFF241F1A), + foregroundColor: const Color(0xFFD7C4A0), + ), icon: Icon( _isDirectInputEnabled ? Icons.keyboard_hide @@ -811,6 +850,10 @@ class _TerminalPageState extends ConsumerState { key: const Key('terminal_toggle_actions_button'), onPressed: _showToolsSheet, visualDensity: VisualDensity.compact, + style: IconButton.styleFrom( + backgroundColor: const Color(0xFF241F1A), + foregroundColor: const Color(0xFFD7C4A0), + ), icon: const Icon(Icons.tune), tooltip: 'Show tools', ), diff --git a/apps/mobile_app/test/project_home_test.dart b/apps/mobile_app/test/project_home_test.dart index 885994d..14c5fdb 100644 --- a/apps/mobile_app/test/project_home_test.dart +++ b/apps/mobile_app/test/project_home_test.dart @@ -39,6 +39,7 @@ void main() { expect(find.text('Projects'), findsOneWidget); expect(find.byKey(const Key('project_page_header')), findsOneWidget); + expect(find.byKey(const Key('agent_connection_readout')), findsOneWidget); expect(find.text('TermRemoteCtl'), findsOneWidget); expect(find.text(r'C:\repo\termremotectl'), findsOneWidget); expect( diff --git a/apps/mobile_app/test/widget_test.dart b/apps/mobile_app/test/widget_test.dart index 0d1a131..4a765e7 100644 --- a/apps/mobile_app/test/widget_test.dart +++ b/apps/mobile_app/test/widget_test.dart @@ -32,10 +32,13 @@ void main() { expect(find.text('Projects'), findsOneWidget); expect(materialApp.theme?.brightness, Brightness.dark); expect(materialApp.theme?.scaffoldBackgroundColor, isNot(Colors.white)); + expect(materialApp.theme?.scaffoldBackgroundColor, const Color(0xFF05070A)); + expect(materialApp.theme?.colorScheme.primary, const Color(0xFFC2A574)); expect(find.byKey(const Key('project_page_header')), findsOneWidget); expect(find.text('Agent base URL'), findsOneWidget); expect(agentUrlField.controller?.text, 'http://10.0.2.2:5067'); expect(agentUrlField.decoration?.hintText, 'http://10.0.2.2:5067'); + expect(find.byKey(const Key('agent_connection_readout')), findsOneWidget); expect( find.text('Project requests use this base origin: http://10.0.2.2:5067.'), findsOneWidget, @@ -67,8 +70,10 @@ void main() { expect(sessionRepository.lastCreatedProjectId, 'project-1'); expect(find.text('codex-main'), findsOneWidget); expect(find.text(r'C:\repo\codex-main'), findsOneWidget); + expect(find.byKey(const Key('terminal_header_panel')), findsOneWidget); expect(find.byKey(const Key('terminal_surface_panel')), findsOneWidget); expect(find.byKey(const Key('terminal_command_deck')), findsOneWidget); + expect(find.byKey(const Key('terminal_status_summary')), findsOneWidget); expect( find.byKey(const Key('terminal_toggle_actions_button')), findsOneWidget,