From 8c392d903db7a44c43a9f615ab35856e6d80cee5 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:16 +0100 Subject: [PATCH 1/7] Centralize design tokens for typography, spacing, and button proportions. --- .../presentation/core/themes/dimensions.dart | 61 +++++++++++-- .../presentation/core/ui/screen_header.dart | 85 +++++++++++++++++++ 2 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 mobile_client/lib/presentation/core/ui/screen_header.dart diff --git a/mobile_client/lib/presentation/core/themes/dimensions.dart b/mobile_client/lib/presentation/core/themes/dimensions.dart index a5619cd..41680b7 100644 --- a/mobile_client/lib/presentation/core/themes/dimensions.dart +++ b/mobile_client/lib/presentation/core/themes/dimensions.dart @@ -10,8 +10,11 @@ import 'package:flutter/material.dart'; /// Avoid using the below subtypes directly final class Dimens { static PaddingDim padding = PaddingDim(); - static IconDim icon = IconDim(); + static TextDim text = TextDim(); + static ButtonDim button = ButtonDim(); + static RadiusDim radius = RadiusDim(); + static SpacingDim spacing = SpacingDim(); } /// ------------------------------ @@ -19,11 +22,8 @@ final class Dimens { /// ------------------------------ class PaddingDim { final horizontal = 20.0; - final vertical = 24.0; - final screenHorizontal = 20.0; - final screenVertical = 24.0; /// Horizontal symmetric padding for screen edges @@ -39,7 +39,56 @@ class PaddingDim { /// Icon Dimensions /// ------------------------------ class IconDim { - final large = 45.0; - final medium = 35.0; + final large = 40.0; + final medium = 28.0; final small = 20.0; + final tiny = 16.0; +} + +/// ------------------------------ +/// Typography Dimensions +/// ------------------------------ +class TextDim { + final header = 22.0; + final title = 18.0; + final body = 16.0; + final small = 14.0; + final tiny = 12.0; + final label = 13.0; +} + +/// ------------------------------ +/// Button Dimensions +/// ------------------------------ +class ButtonDim { + final ctaFontSize = 18.0; + final ctaVerticalPadding = 14.0; + final ctaHorizontalPadding = 32.0; + final ctaIconSize = 24.0; + + final styledButtonBorderWidth = 4.0; + final styledButtonMargin = 8.0; +} + +/// ------------------------------ +/// Radius Dimensions +/// ------------------------------ +class RadiusDim { + final large = 40.0; + final medium = 24.0; + final small = 16.0; + final tiny = 8.0; + final pill = 999.0; +} + +/// ------------------------------ +/// Spacing Dimensions +/// ------------------------------ +class SpacingDim { + final xl = 32.0; + final lg = 24.0; + final md = 16.0; + final sm = 12.0; + final xs = 8.0; + final xss = 4.0; } diff --git a/mobile_client/lib/presentation/core/ui/screen_header.dart b/mobile_client/lib/presentation/core/ui/screen_header.dart new file mode 100644 index 0000000..7cc2b1e --- /dev/null +++ b/mobile_client/lib/presentation/core/ui/screen_header.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:laze/presentation/core/themes/generated_theme.dart'; + +class ScreenHeader extends StatelessWidget { + final Widget title; + final List? actions; + + const ScreenHeader({ + super.key, + required this.title, + this.actions, + }); + + @override + Widget build(BuildContext context) { + final appColors = Theme.of(context).extension()!; + final scale = Theme.of(context).extension()!; + + return LayoutBuilder( + builder: (context, constraints) { + final isCompact = constraints.maxWidth < 460; + + final titleBanner = Container( + height: 68, + padding: const EdgeInsets.symmetric(horizontal: 22), + decoration: BoxDecoration( + color: appColors.border, + border: Border.all(color: appColors.divider, width: 1), + borderRadius: BorderRadius.circular(scale.radiusPill), + ), + alignment: Alignment.centerLeft, + child: DefaultTextStyle( + style: TextStyle( + color: appColors.textMuted, + fontSize: isCompact ? 18 : 22, + fontWeight: FontWeight.w600, + letterSpacing: 1.2, + ), + child: title, + ), + ); + + final actionRow = actions != null && actions!.isNotEmpty + ? Row( + mainAxisSize: MainAxisSize.min, + children: actions! + .asMap() + .entries + .map((entry) => Padding( + padding: EdgeInsets.only( + left: entry.key == 0 ? 0 : 10, + ), + child: entry.value, + )) + .toList(), + ) + : null; + + if (actionRow == null) return titleBanner; + + return isCompact + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + titleBanner, + const SizedBox(height: 12), + Align( + alignment: Alignment.centerRight, + child: actionRow, + ), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded(child: titleBanner), + const SizedBox(width: 12), + actionRow, + ], + ); + }, + ); + } +} From dd413dbf018a86f6a2f880b69d08d7172a9ccf13 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:22 +0100 Subject: [PATCH 2/7] Standardize headers across Home and Settings screens using new ScreenHeader component. --- .../presentation/core/ui/screen_header.dart | 104 +++++------- .../home/widgets/connection_header.dart | 151 ++++++----------- .../settings/settings_screen.dart | 154 +++++++----------- 3 files changed, 153 insertions(+), 256 deletions(-) diff --git a/mobile_client/lib/presentation/core/ui/screen_header.dart b/mobile_client/lib/presentation/core/ui/screen_header.dart index 7cc2b1e..ee75996 100644 --- a/mobile_client/lib/presentation/core/ui/screen_header.dart +++ b/mobile_client/lib/presentation/core/ui/screen_header.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; class ScreenHeader extends StatelessWidget { @@ -16,70 +17,51 @@ class ScreenHeader extends StatelessWidget { final appColors = Theme.of(context).extension()!; final scale = Theme.of(context).extension()!; - return LayoutBuilder( - builder: (context, constraints) { - final isCompact = constraints.maxWidth < 460; + final actionRow = actions != null && actions!.isNotEmpty + ? Row( + mainAxisSize: MainAxisSize.min, + children: actions! + .asMap() + .entries + .map((entry) => Padding( + padding: EdgeInsets.only( + left: entry.key == 0 ? 0 : 10, + ), + child: entry.value, + )) + .toList(), + ) + : null; - final titleBanner = Container( - height: 68, - padding: const EdgeInsets.symmetric(horizontal: 22), - decoration: BoxDecoration( - color: appColors.border, - border: Border.all(color: appColors.divider, width: 1), - borderRadius: BorderRadius.circular(scale.radiusPill), - ), - alignment: Alignment.centerLeft, - child: DefaultTextStyle( - style: TextStyle( - color: appColors.textMuted, - fontSize: isCompact ? 18 : 22, - fontWeight: FontWeight.w600, - letterSpacing: 1.2, + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Container( + height: 60, + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: appColors.border, + border: Border.all(color: appColors.divider, width: 1), + borderRadius: BorderRadius.circular(scale.radiusPill), + ), + alignment: Alignment.centerLeft, + child: DefaultTextStyle( + style: TextStyle( + color: appColors.textMuted, + fontSize: Dimens.text.header, + fontWeight: FontWeight.w600, + letterSpacing: 1.1, + ), + child: title, ), - child: title, ), - ); - - final actionRow = actions != null && actions!.isNotEmpty - ? Row( - mainAxisSize: MainAxisSize.min, - children: actions! - .asMap() - .entries - .map((entry) => Padding( - padding: EdgeInsets.only( - left: entry.key == 0 ? 0 : 10, - ), - child: entry.value, - )) - .toList(), - ) - : null; - - if (actionRow == null) return titleBanner; - - return isCompact - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - titleBanner, - const SizedBox(height: 12), - Align( - alignment: Alignment.centerRight, - child: actionRow, - ), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded(child: titleBanner), - const SizedBox(width: 12), - actionRow, - ], - ); - }, + ), + if (actionRow != null) ...[ + const SizedBox(width: 12), + actionRow, + ], + ], ); } } diff --git a/mobile_client/lib/presentation/home/widgets/connection_header.dart b/mobile_client/lib/presentation/home/widgets/connection_header.dart index 9b7ad47..d08da73 100644 --- a/mobile_client/lib/presentation/home/widgets/connection_header.dart +++ b/mobile_client/lib/presentation/home/widgets/connection_header.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:laze/presentation/core/themes/app_shadows.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/styled_button.dart'; +import 'package:laze/presentation/core/ui/screen_header.dart'; import 'package:laze/services/app_connection_status.dart'; typedef Callback = void Function(); @@ -28,111 +29,65 @@ class ConnectionHeader extends StatelessWidget { Widget build(BuildContext context) { final appColors = Theme.of(context).extension()!; - return LayoutBuilder( - builder: (context, constraints) { - final isCompact = constraints.maxWidth < 460; - final statusFontSize = isCompact ? 24.0 : 30.0; - - final statusBanner = Container( - height: 68, - padding: const EdgeInsets.symmetric(horizontal: 22), - decoration: BoxDecoration( - color: appColors.border, - border: Border.all(color: appColors.divider, width: 1), - borderRadius: BorderRadius.circular(999), - ), - child: Row( - children: [ - Expanded( - child: Text( - connectionStatus.label, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: appColors.textMuted, - fontSize: statusFontSize, - fontWeight: FontWeight.w500, - ), - ), + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: ScreenHeader( + title: Row( + children: [ + Expanded( + child: Text( + connectionStatus.label, + overflow: TextOverflow.ellipsis, ), - if (connectionStatus == AppConnectionStatus.connected) ...[ - const SizedBox(width: 8), - Container( - width: 17, - height: 17, - decoration: BoxDecoration( - color: appColors.success, - shape: BoxShape.circle, - border: Border.all(color: appColors.onSuccess, width: 3), - ), + ), + if (connectionStatus == AppConnectionStatus.connected) ...[ + const SizedBox(width: 8), + Container( + width: 17, + height: 17, + decoration: BoxDecoration( + color: appColors.success, + shape: BoxShape.circle, + border: Border.all(color: appColors.onSuccess, width: 3), ), - ], + ), ], + ], + ), + actions: [ + StyledButton( + onPressed: () { + if (onOpenSettings != null) { + onOpenSettings!(); + } else { + Navigator.pushNamed(context, '/settings'); + } + }, + icon: Icons.settings, ), - ); - - final actionButtons = Row( - mainAxisSize: MainAxisSize.min, - children: [ - StyledButton( - onPressed: () { - if (onOpenSettings != null) { - onOpenSettings!(); - } else { - Navigator.pushNamed(context, '/settings'); - } - }, - icon: Icons.settings, + Container( + width: 72, + height: 60, + decoration: BoxDecoration( + color: appColors.error, + border: Border.all(color: appColors.onError, width: 6), + borderRadius: BorderRadius.circular(999), + boxShadow: AppShadows.raisedControl(appColors), ), - const SizedBox(width: 10), - Container( - width: 84, - height: 60, - decoration: BoxDecoration( - color: appColors.error, - border: Border.all(color: appColors.onError, width: 6), - borderRadius: BorderRadius.circular(999), - boxShadow: AppShadows.raisedControl(appColors), - ), - child: IconButton( - onPressed: () => _handlePrimaryAction(context), - icon: Icon( - connectionStatus == AppConnectionStatus.searching - ? Icons.cancel - : Icons.power_settings_new, - color: appColors.textInverse, - ), - iconSize: 35, - padding: EdgeInsets.zero, + child: IconButton( + onPressed: () => _handlePrimaryAction(context), + icon: Icon( + connectionStatus == AppConnectionStatus.searching + ? Icons.cancel + : Icons.power_settings_new, + color: appColors.textInverse, ), + iconSize: 30, + padding: EdgeInsets.zero, ), - ], - ); - - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: isCompact - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - statusBanner, - const SizedBox(height: 12), - Align( - alignment: Alignment.centerRight, - child: actionButtons, - ), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded(child: statusBanner), - const SizedBox(width: 12), - actionButtons, - ], - ), - ); - }, + ), + ], + ), ); } diff --git a/mobile_client/lib/presentation/settings/settings_screen.dart b/mobile_client/lib/presentation/settings/settings_screen.dart index b7ce6c9..bd3a4db 100644 --- a/mobile_client/lib/presentation/settings/settings_screen.dart +++ b/mobile_client/lib/presentation/settings/settings_screen.dart @@ -5,6 +5,7 @@ import 'package:laze/data/repositories/device/device_settings_repository.dart'; import 'package:laze/presentation/core/ui/controller_page.dart'; import 'package:laze/presentation/core/ui/styled_button.dart'; import 'package:laze/presentation/core/ui/styled_input.dart'; +import 'package:laze/presentation/core/ui/screen_header.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/services/theme_notifier.dart'; @@ -100,57 +101,16 @@ class _SettingsScreenState extends State { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - LayoutBuilder( - builder: (context, constraints) { - final isCompact = constraints.maxWidth < 460; - final titleBanner = Container( - height: 68, - padding: const EdgeInsets.symmetric(horizontal: 22), - decoration: BoxDecoration( - color: appColors.border, - border: Border.all(color: appColors.divider, width: 1), - borderRadius: BorderRadius.circular(scale.radiusPill), - ), - alignment: Alignment.centerLeft, - child: Text( - 'SETTINGS', - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: appColors.textMuted, - fontSize: isCompact ? 24 : 30, - fontWeight: FontWeight.w500, - ), - ), - ); - final closeButton = StyledButton( + ScreenHeader( + title: const Text('SETTINGS'), + actions: [ + StyledButton( onPressed: () => Navigator.of(context).pop(), icon: Icons.close, - ); - - return isCompact - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - titleBanner, - const SizedBox(height: 12), - Align( - alignment: Alignment.centerRight, - child: closeButton, - ), - ], - ) - : Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded(child: titleBanner), - const SizedBox(width: 12), - closeButton, - ], - ); - }, + ), + ], ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), if (_isLoading) const Expanded(child: Center(child: CircularProgressIndicator())) else ...[ @@ -164,7 +124,7 @@ class _SettingsScreenState extends State { scale: scale, controller: _deviceNameController, ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), _ControlsCard( appColors: appColors, scale: scale, @@ -177,9 +137,9 @@ class _SettingsScreenState extends State { ).setSensitivity(v); }, ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), _ThemeCard(appColors: appColors, scale: scale), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), _HelpCard(appColors: appColors, scale: scale), ], ), @@ -207,10 +167,10 @@ class _DeviceNameCard extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - padding: EdgeInsets.all(scale.spaceXl), + padding: EdgeInsets.all(scale.spaceLg), decoration: BoxDecoration( color: appColors.surface_1, - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(16), border: Border.all(color: appColors.divider, width: 1), ), child: Column( @@ -220,17 +180,17 @@ class _DeviceNameCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 56, - height: 56, + width: 44, + height: 44, decoration: BoxDecoration( color: appColors.surface_2, - borderRadius: BorderRadius.circular(scale.radiusLg), + borderRadius: BorderRadius.circular(scale.radiusMd), border: Border.all(color: appColors.divider, width: 1), ), alignment: Alignment.center, - child: Icon(Icons.smartphone, color: appColors.primary, size: 28), + child: Icon(Icons.smartphone, color: appColors.primary, size: 22), ), - SizedBox(width: scale.spaceLg), + SizedBox(width: scale.spaceMd), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -239,17 +199,17 @@ class _DeviceNameCard extends StatelessWidget { 'Device Name', style: TextStyle( color: appColors.text, - fontSize: 24, + fontSize: 18, fontWeight: FontWeight.w700, ), ), - SizedBox(height: scale.spaceSm), + SizedBox(height: scale.space2xs), Text( - 'This name identifies your device on the server when multiple devices are connected.', + 'This name identifies your device on the server.', style: TextStyle( color: appColors.textMuted, - fontSize: 15, - height: 1.35, + fontSize: 14, + height: 1.2, ), ), ], @@ -257,7 +217,7 @@ class _DeviceNameCard extends StatelessWidget { ), ], ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), Text( 'Visible device label', style: TextStyle( @@ -298,10 +258,10 @@ class _ThemeCard extends StatelessWidget { return Container( width: double.infinity, - padding: EdgeInsets.all(scale.spaceXl), + padding: EdgeInsets.all(scale.spaceLg), decoration: BoxDecoration( color: appColors.surface_1, - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(16), border: Border.all(color: appColors.divider, width: 1), ), child: Column( @@ -311,18 +271,18 @@ class _ThemeCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 56, - height: 56, + width: 44, + height: 44, decoration: BoxDecoration( color: appColors.surface_2, - borderRadius: BorderRadius.circular(scale.radiusLg), + borderRadius: BorderRadius.circular(scale.radiusMd), border: Border.all(color: appColors.divider, width: 1), ), alignment: Alignment.center, child: Icon(Icons.palette_outlined, - color: appColors.primary, size: 28), + color: appColors.primary, size: 22), ), - SizedBox(width: scale.spaceLg), + SizedBox(width: scale.spaceMd), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -331,17 +291,17 @@ class _ThemeCard extends StatelessWidget { 'Appearance', style: TextStyle( color: appColors.text, - fontSize: 24, + fontSize: 18, fontWeight: FontWeight.w700, ), ), - SizedBox(height: scale.spaceSm), + SizedBox(height: scale.space2xs), Text( 'Choose a colour scheme for the app.', style: TextStyle( color: appColors.textMuted, - fontSize: 15, - height: 1.35, + fontSize: 14, + height: 1.2, ), ), ], @@ -349,7 +309,7 @@ class _ThemeCard extends StatelessWidget { ), ], ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), Row( children: AppThemeOption.values.map((option) { final selected = themeNotifier.option == option; @@ -419,10 +379,10 @@ class _ControlsCard extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - padding: EdgeInsets.all(scale.spaceXl), + padding: EdgeInsets.all(scale.spaceLg), decoration: BoxDecoration( color: appColors.surface_1, - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(16), border: Border.all(color: appColors.divider, width: 1), ), child: Column( @@ -431,28 +391,28 @@ class _ControlsCard extends StatelessWidget { Row( children: [ Container( - width: 56, - height: 56, + width: 44, + height: 44, decoration: BoxDecoration( color: appColors.surface_2, - borderRadius: BorderRadius.circular(scale.radiusLg), + borderRadius: BorderRadius.circular(scale.radiusMd), border: Border.all(color: appColors.divider, width: 1), ), alignment: Alignment.center, - child: Icon(Icons.tune, color: appColors.primary, size: 28), + child: Icon(Icons.tune, color: appColors.primary, size: 22), ), - SizedBox(width: scale.spaceLg), + SizedBox(width: scale.spaceMd), Text( 'Controls', style: TextStyle( color: appColors.text, - fontSize: 24, + fontSize: 18, fontWeight: FontWeight.w700, ), ), ], ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), // ── Sensitivity ────────────────────────────────────────────── _SettingLabel( @@ -501,10 +461,10 @@ class _HelpCard extends StatelessWidget { Widget build(BuildContext context) { return Container( width: double.infinity, - padding: EdgeInsets.all(scale.spaceXl), + padding: EdgeInsets.all(scale.spaceLg), decoration: BoxDecoration( color: appColors.surface_1, - borderRadius: BorderRadius.circular(24), + borderRadius: BorderRadius.circular(16), border: Border.all(color: appColors.divider, width: 1), ), child: Column( @@ -514,18 +474,18 @@ class _HelpCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - width: 56, - height: 56, + width: 44, + height: 44, decoration: BoxDecoration( color: appColors.surface_2, - borderRadius: BorderRadius.circular(scale.radiusLg), + borderRadius: BorderRadius.circular(scale.radiusMd), border: Border.all(color: appColors.divider, width: 1), ), alignment: Alignment.center, child: Icon(Icons.help_outline, - color: appColors.primary, size: 28), + color: appColors.primary, size: 22), ), - SizedBox(width: scale.spaceLg), + SizedBox(width: scale.spaceMd), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -534,17 +494,17 @@ class _HelpCard extends StatelessWidget { 'Help & Tutorial', style: TextStyle( color: appColors.text, - fontSize: 24, + fontSize: 18, fontWeight: FontWeight.w700, ), ), - SizedBox(height: scale.spaceSm), + SizedBox(height: scale.space2xs), Text( 'Replay the introduction to learn how Laze works.', style: TextStyle( color: appColors.textMuted, - fontSize: 15, - height: 1.35, + fontSize: 14, + height: 1.2, ), ), ], @@ -552,7 +512,7 @@ class _HelpCard extends StatelessWidget { ), ], ), - SizedBox(height: scale.spaceXl), + SizedBox(height: scale.spaceLg), GestureDetector( onTap: () => Navigator.of(context).pushNamed('/onboarding'), child: Container( From 0b18be66c20b143ae7423154f43187618bc044f9 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:31 +0100 Subject: [PATCH 3/7] Standardize button proportions and border widths across all shared UI components. --- .../lib/presentation/core/ui/cta_button.dart | 16 ++++++++++------ .../presentation/core/ui/split_panel_button.dart | 11 ++++++----- .../lib/presentation/core/ui/styled_button.dart | 4 ++-- .../presentation/core/ui/styled_long_button.dart | 7 ++++--- .../presentation/core/ui/wide_styled_button.dart | 5 +++-- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/mobile_client/lib/presentation/core/ui/cta_button.dart b/mobile_client/lib/presentation/core/ui/cta_button.dart index 94bfa69..b58fdd5 100644 --- a/mobile_client/lib/presentation/core/ui/cta_button.dart +++ b/mobile_client/lib/presentation/core/ui/cta_button.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:laze/presentation/core/themes/app_shadows.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/press_animation_mixin.dart'; @@ -11,7 +12,7 @@ class CtaButton extends StatefulWidget { final Color? foregroundColor; final Color? borderColor; final double widthFactor; - final double fontSize; + final double? fontSize; final double borderWidth; final bool showShadow; @@ -24,7 +25,7 @@ class CtaButton extends StatefulWidget { this.foregroundColor, this.borderColor, this.widthFactor = 0.75, - this.fontSize = 38, + this.fontSize, this.borderWidth = 1, this.showShadow = true, }) : assert( @@ -59,17 +60,20 @@ class _CtaButtonState extends State content = TextButton( onPressed: widget.onPressed, style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(vertical: 26), + padding: EdgeInsets.symmetric(vertical: Dimens.button.ctaVerticalPadding), shape: const StadiumBorder(), overlayColor: Colors.transparent, ), - child: Icon(widget.icon, color: resolvedForeground, size: 32), + child: Icon(widget.icon, color: resolvedForeground, size: Dimens.button.ctaIconSize), ); } else { content = TextButton( onPressed: widget.onPressed, style: TextButton.styleFrom( - padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 18), + padding: EdgeInsets.symmetric( + horizontal: Dimens.button.ctaHorizontalPadding, + vertical: Dimens.button.ctaVerticalPadding, + ), shape: const StadiumBorder(), overlayColor: Colors.transparent, ), @@ -77,7 +81,7 @@ class _CtaButtonState extends State widget.text!, style: TextStyle( color: resolvedForeground, - fontSize: widget.fontSize, + fontSize: widget.fontSize ?? Dimens.button.ctaFontSize, fontWeight: FontWeight.w900, fontFamily: 'NunitoSans', ), diff --git a/mobile_client/lib/presentation/core/ui/split_panel_button.dart b/mobile_client/lib/presentation/core/ui/split_panel_button.dart index 9d5a091..36ba3a4 100644 --- a/mobile_client/lib/presentation/core/ui/split_panel_button.dart +++ b/mobile_client/lib/presentation/core/ui/split_panel_button.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; class SplitPanelButton extends StatelessWidget { - static const Radius _radius = Radius.circular(32); - static const double _topTextSize = 24; - static const double _bottomTextSize = 22; + static final Radius _radius = Radius.circular(Dimens.radius.medium); + static final double _topTextSize = Dimens.text.title; + static final double _bottomTextSize = Dimens.text.body; static const double _separatorHorizontalPadding = 18; final String topText; @@ -31,10 +32,10 @@ class SplitPanelButton extends StatelessWidget { height: height, decoration: BoxDecoration( color: appColors.border, - borderRadius: const BorderRadius.all(_radius), + borderRadius: BorderRadius.all(_radius), ), child: ClipRRect( - borderRadius: const BorderRadius.all(_radius), + borderRadius: BorderRadius.all(_radius), child: Column( children: [ Expanded( diff --git a/mobile_client/lib/presentation/core/ui/styled_button.dart b/mobile_client/lib/presentation/core/ui/styled_button.dart index d2b02ad..56a183c 100644 --- a/mobile_client/lib/presentation/core/ui/styled_button.dart +++ b/mobile_client/lib/presentation/core/ui/styled_button.dart @@ -22,7 +22,7 @@ class StyledButton extends StatefulWidget { this.width, this.height, this.iconSize, - this.margin = const EdgeInsets.all(10), + this.margin = const EdgeInsets.all(8), this.showShadow = true, }); @@ -51,7 +51,7 @@ class _StyledButtonState extends State borderRadius: BorderRadius.circular(999), border: Border.all( color: appColors.border, - width: 6, + width: Dimens.button.styledButtonBorderWidth, ), boxShadow: flat ? null : AppShadows.raisedControl(appColors), ), diff --git a/mobile_client/lib/presentation/core/ui/styled_long_button.dart b/mobile_client/lib/presentation/core/ui/styled_long_button.dart index 0fb1aed..a1b6318 100644 --- a/mobile_client/lib/presentation/core/ui/styled_long_button.dart +++ b/mobile_client/lib/presentation/core/ui/styled_long_button.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:laze/presentation/core/themes/app_shadows.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; typedef Callback = void Function(); @@ -28,8 +29,8 @@ class StyledLongButton extends StatefulWidget { this.vertical, this.width, this.height, - this.iconSize = 45, - this.descriptionFontSize = 20, + this.iconSize = 40.0, // Match Dimens.icon.large + this.descriptionFontSize = 18.0, // Match Dimens.text.title }); @override @@ -250,7 +251,7 @@ class _StyledLongButtonState extends State { decoration: BoxDecoration( shape: BoxShape.rectangle, color: appColors.bg, - borderRadius: BorderRadius.circular(50), + borderRadius: BorderRadius.circular(Dimens.radius.large), boxShadow: AppShadows.raisedControl(appColors), ), child: _buildLayout(context, appColors), diff --git a/mobile_client/lib/presentation/core/ui/wide_styled_button.dart b/mobile_client/lib/presentation/core/ui/wide_styled_button.dart index a1d4095..76f470d 100644 --- a/mobile_client/lib/presentation/core/ui/wide_styled_button.dart +++ b/mobile_client/lib/presentation/core/ui/wide_styled_button.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:laze/presentation/core/themes/app_shadows.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; typedef Callback = void Function(); @@ -35,7 +36,7 @@ class WideStyledButton extends StatelessWidget { width: double.infinity, margin: const EdgeInsets.all(1), decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(30.0)), + borderRadius: BorderRadius.all(Radius.circular(Dimens.radius.medium)), color: backgroundColor, boxShadow: AppShadows.raisedPanel(appColors), ), @@ -43,7 +44,7 @@ class WideStyledButton extends StatelessWidget { ? IconButton( onPressed: onPressed, icon: Icon(icon), - iconSize: 60, + iconSize: Dimens.icon.large, color: iconColor, ) : TextButton( From 207f699f2b0b8529c39ed04792ab06fb78b36b66 Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:35 +0100 Subject: [PATCH 4/7] Refine MousePad labels and Home screen layout for better mobile density. --- .../home/widgets/command_btns.dart | 7 ++++-- .../home/widgets/home_screen.dart | 9 ++++--- .../presentation/home/widgets/mousepad.dart | 25 +++++++++++++------ .../home/widgets/not_connected_screen.dart | 13 +++++++--- 4 files changed, 36 insertions(+), 18 deletions(-) diff --git a/mobile_client/lib/presentation/home/widgets/command_btns.dart b/mobile_client/lib/presentation/home/widgets/command_btns.dart index 28e73d7..2631924 100644 --- a/mobile_client/lib/presentation/home/widgets/command_btns.dart +++ b/mobile_client/lib/presentation/home/widgets/command_btns.dart @@ -32,16 +32,19 @@ class CommandBtns extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { final width = constraints.maxWidth; + // Subtract the 8px consumed by Padding(horizontal: 4) so that child + // widths add up to the Row's actual available space. + final effectiveWidth = width - 8; final isCompact = width < 390; final sideWidth = math.max( 56.0, - math.min(_CommandControlSizes.sideButtonWidth, width * 0.18), + math.min(_CommandControlSizes.sideButtonWidth, effectiveWidth * 0.18), ); final centerWidth = math.max( 148.0, math.min( _CommandControlSizes.centerPanelWidth, - width - (sideWidth * 2) - 40, + effectiveWidth - (sideWidth * 2) - 40, ), ); final panelHeight = diff --git a/mobile_client/lib/presentation/home/widgets/home_screen.dart b/mobile_client/lib/presentation/home/widgets/home_screen.dart index b412d06..f6176e9 100644 --- a/mobile_client/lib/presentation/home/widgets/home_screen.dart +++ b/mobile_client/lib/presentation/home/widgets/home_screen.dart @@ -125,9 +125,11 @@ class _HomeScreenState extends State { padding: EdgeInsets.only(bottom: bottomInset.toDouble()), child: Column( children: [ - MousePad( - fullscreen: false, - sensitivity: sensitivity, + Expanded( + child: MousePad( + fullscreen: false, + sensitivity: sensitivity, + ), ), const SizedBox(height: 28), CommandBtns( @@ -135,7 +137,6 @@ class _HomeScreenState extends State { onSensitivityChanged: _updateSensitivity, feedbackNotifier: _feedbackNotifier, ), - const Spacer(), ], ), ), diff --git a/mobile_client/lib/presentation/home/widgets/mousepad.dart b/mobile_client/lib/presentation/home/widgets/mousepad.dart index 9854d46..124aa1d 100644 --- a/mobile_client/lib/presentation/home/widgets/mousepad.dart +++ b/mobile_client/lib/presentation/home/widgets/mousepad.dart @@ -4,6 +4,7 @@ import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:laze/data/services/input.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/dashed_border.dart'; @@ -360,7 +361,7 @@ class _MousePadState extends State { 'Gesture guide', style: TextStyle( color: appColors.text, - fontSize: 22, + fontSize: Dimens.text.title, fontWeight: FontWeight.w800, ), ), @@ -407,8 +408,14 @@ class _MousePadState extends State { final availableHeight = constraints.hasBoundedHeight ? constraints.maxHeight : screenSize.height; - final padHeight = - widget.fullscreen ? availableHeight : 0.40 * screenSize.height; + // Use the bounded constraint height when the parent provides one (e.g. + // when wrapped in Expanded). Fall back to 40% of screen height only + // when the height is truly unbounded. + final padHeight = widget.fullscreen + ? availableHeight + : (constraints.hasBoundedHeight && constraints.maxHeight > 0 + ? constraints.maxHeight + : 0.40 * screenSize.height); final scrollHeight = widget.fullscreen ? availableHeight : padHeight; return SizedBox( @@ -457,8 +464,9 @@ class _MousePadState extends State { 'MOUSEPAD', style: TextStyle( fontWeight: FontWeight.w400, - fontSize: 40, + fontSize: 24, color: appColors.textMuted, + letterSpacing: 2.0, ), ), ), @@ -501,8 +509,9 @@ class _MousePadState extends State { 'SCROLL', style: TextStyle( fontWeight: FontWeight.w600, - fontSize: 36, + fontSize: 20, color: appColors.textMuted, + letterSpacing: 1.5, ), ), ), @@ -517,7 +526,7 @@ class _MousePadState extends State { child: IconButton( icon: const Icon(Icons.fullscreen), color: appColors.textMuted, - iconSize: 64, + iconSize: Dimens.icon.large, onPressed: () { widget.fullscreen ? Navigator.of(context).pop() @@ -537,7 +546,7 @@ class _MousePadState extends State { child: IconButton( icon: const Icon(Icons.help_outline), color: appColors.textMuted, - iconSize: 28, + iconSize: Dimens.icon.medium, tooltip: 'Gesture guide', onPressed: () => _showGestureGuide(context, appColors), ), @@ -585,7 +594,7 @@ class _GestureHint extends StatelessWidget { text, style: TextStyle( color: appColors.text, - fontSize: 15, + fontSize: Dimens.text.small, fontWeight: FontWeight.w500, height: 1.3, ), diff --git a/mobile_client/lib/presentation/home/widgets/not_connected_screen.dart b/mobile_client/lib/presentation/home/widgets/not_connected_screen.dart index 098d992..b65f0e4 100644 --- a/mobile_client/lib/presentation/home/widgets/not_connected_screen.dart +++ b/mobile_client/lib/presentation/home/widgets/not_connected_screen.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/controller_page.dart'; import 'package:laze/presentation/core/ui/cta_button.dart'; @@ -38,8 +39,9 @@ class NotConnectedScreen extends StatelessWidget { textAlign: TextAlign.center, style: TextStyle( color: appColors.textMuted, - fontSize: 40, - fontWeight: FontWeight.w100, + fontSize: 28, + fontWeight: FontWeight.w200, + letterSpacing: 2.0, ), ), const SizedBox(height: 12), @@ -50,7 +52,7 @@ class NotConnectedScreen extends StatelessWidget { textAlign: TextAlign.center, style: TextStyle( color: appColors.textMuted, - fontSize: 16, + fontSize: Dimens.text.body, ), ), @@ -60,7 +62,10 @@ class NotConnectedScreen extends StatelessWidget { Expanded( child: Align( alignment: Alignment.topCenter, - child: Image.asset('assets/images/NoConnection.png'), + child: Image.asset( + 'assets/images/NoConnection.png', + fit: BoxFit.contain, + ), ), ), From 5359fc8cf87bc06ff55b1d653e76d26cc8592abd Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:40 +0100 Subject: [PATCH 5/7] Refine Shortcuts bottom sheet and icon labels with standardized tokens. --- .../home/widgets/shortcut_icon.dart | 6 ++- .../home/widgets/shortcuts_sheet.dart | 53 +++++-------------- 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/mobile_client/lib/presentation/home/widgets/shortcut_icon.dart b/mobile_client/lib/presentation/home/widgets/shortcut_icon.dart index 2e05efd..3f1699f 100644 --- a/mobile_client/lib/presentation/home/widgets/shortcut_icon.dart +++ b/mobile_client/lib/presentation/home/widgets/shortcut_icon.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:laze/domain/models/shortcut/shortcut.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/styled_button.dart'; import 'package:laze/data/services/input.dart'; @@ -36,7 +37,10 @@ class ShortcutIcon extends StatelessWidget { maxLines: 1, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, - style: TextStyle(color: appColors.textMuted), + style: TextStyle( + color: appColors.textMuted, + fontSize: Dimens.text.tiny, + ), ), ], ); diff --git a/mobile_client/lib/presentation/home/widgets/shortcuts_sheet.dart b/mobile_client/lib/presentation/home/widgets/shortcuts_sheet.dart index 408d8db..493a2d6 100644 --- a/mobile_client/lib/presentation/home/widgets/shortcuts_sheet.dart +++ b/mobile_client/lib/presentation/home/widgets/shortcuts_sheet.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:laze/data/services/input.dart'; import 'package:laze/domain/models/shortcut/shortcut.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/cta_button.dart'; import 'package:laze/presentation/core/ui/styled_button.dart'; @@ -88,52 +89,24 @@ class _ShortcutsSheetState extends State { return Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(82), - topRight: Radius.circular(82), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(Dimens.radius.large), + topRight: Radius.circular(Dimens.radius.large), ), border: Border( - top: BorderSide(color: borderColor, width: 3), + top: BorderSide(color: borderColor, width: 2), ), - // boxShadow: [ - // BoxShadow( - // color: appColors.border.withValues(alpha: 0.01), - // offset: const Offset(0, -19), - // blurRadius: 5, - // ), - // BoxShadow( - // color: appColors.border.withValues(alpha: 0.07), - // offset: const Offset(0, -12), - // blurRadius: 5, - // ), - // BoxShadow( - // color: appColors.border.withValues(alpha: 0.23), - // offset: const Offset(0, -7), - // blurRadius: 4, - // ), - // BoxShadow( - // color: appColors.border.withValues(alpha: 0.38), - // offset: const Offset(0, -3), - // blurRadius: 3, - // ), - // BoxShadow( - // color: appColors.border.withValues(alpha: 0.44), - // offset: const Offset(0, -1), - // blurRadius: 2, - // ), - // ], ), child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(82), - topRight: Radius.circular(82), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(Dimens.radius.large), + topRight: Radius.circular(Dimens.radius.large), ), child: Container( - // child: Container( decoration: BoxDecoration( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(82), - topRight: Radius.circular(82), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(Dimens.radius.large), + topRight: Radius.circular(Dimens.radius.large), ), color: appColors.bg, ), @@ -147,8 +120,8 @@ class _ShortcutsSheetState extends State { child: Column( children: [ Container( - width: 110, - height: 6, + width: 60, + height: 4, decoration: BoxDecoration( color: appColors.divider, borderRadius: BorderRadius.circular(999), From 005b395a23a54a8259aae42dafd50bec4623182f Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:48 +0100 Subject: [PATCH 6/7] Standardize inputs and action buttons in the Shortcut Editor flow. --- .../widgets/add_custom_shortcut.dart | 21 ++++++++++--------- .../widgets/shortcut_input_row.dart | 13 ++++++------ .../widgets/terminal_command.dart | 3 ++- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/mobile_client/lib/presentation/new_shortcut/widgets/add_custom_shortcut.dart b/mobile_client/lib/presentation/new_shortcut/widgets/add_custom_shortcut.dart index 87cf66e..2e6501f 100644 --- a/mobile_client/lib/presentation/new_shortcut/widgets/add_custom_shortcut.dart +++ b/mobile_client/lib/presentation/new_shortcut/widgets/add_custom_shortcut.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:laze/core/os_config.dart'; import 'package:laze/data/services/input.dart'; import 'package:laze/presentation/core/themes/app_shadows.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/controller_page.dart'; import 'package:laze/presentation/core/ui/cta_button.dart'; @@ -20,7 +21,7 @@ class AddCustomShortcut extends StatelessWidget { final appColors = Theme.of(context).extension()!; final scale = Theme.of(context).extension()!; final isSaving = shortcutVM.saveShortcut.running; - const actionBarHeight = 92.0; + const actionBarHeight = 72.0; final actionBarSpacing = scale.spaceLg; final scrollBottomInset = actionBarHeight + actionBarSpacing + scale.spaceXl; @@ -48,7 +49,7 @@ class AddCustomShortcut extends StatelessWidget { ), decoration: BoxDecoration( color: appColors.bg, - borderRadius: BorderRadius.circular(36), + borderRadius: BorderRadius.circular(Dimens.radius.medium), border: Border.all( color: appColors.surface_1, width: 2, @@ -64,7 +65,7 @@ class AddCustomShortcut extends StatelessWidget { onNameChanged: shortcutVM.setName, onIconSelected: shortcutVM.setIcon, ), - SizedBox(height: scale.spaceXl), + SizedBox(height: Dimens.spacing.lg), Padding( padding: EdgeInsets.symmetric( horizontal: scale.spaceLg, @@ -74,16 +75,16 @@ class AddCustomShortcut extends StatelessWidget { color: appColors.divider, ), ), - SizedBox(height: scale.spaceXl), + SizedBox(height: Dimens.spacing.lg), Text( "Type the commands to run in the host machine:", style: TextStyle( color: appColors.textMuted, - fontSize: 15, + fontSize: Dimens.text.small, fontWeight: FontWeight.w500, ), ), - SizedBox(height: scale.spaceXl), + SizedBox(height: Dimens.spacing.lg), for (final os in SUPPORTED_OSES) TerminalCommandInput( operativeSystemName: os.name, @@ -122,8 +123,8 @@ class AddCustomShortcut extends StatelessWidget { child: CtaButton( text: 'CANCEL', widthFactor: 0.92, - borderWidth: 4, - fontSize: 26, + borderWidth: 2, + fontSize: Dimens.text.title, backgroundColor: appColors.bg, foregroundColor: appColors.textMuted, borderColor: appColors.surface_1, @@ -141,7 +142,7 @@ class AddCustomShortcut extends StatelessWidget { ? 'SAVING' : (shortcutVM.isNew ? 'CREATE' : 'SAVE'), widthFactor: 0.92, - fontSize: 26, + fontSize: Dimens.text.title, onPressed: () async { if (isSaving) { return; @@ -216,7 +217,7 @@ class _FlatTestButton extends StatelessWidget { 'TEST', style: TextStyle( color: appColors.textMuted, - fontSize: 22, + fontSize: Dimens.text.body, fontWeight: FontWeight.w900, fontFamily: 'NunitoSans', ), diff --git a/mobile_client/lib/presentation/new_shortcut/widgets/shortcut_input_row.dart b/mobile_client/lib/presentation/new_shortcut/widgets/shortcut_input_row.dart index ba68762..c977849 100644 --- a/mobile_client/lib/presentation/new_shortcut/widgets/shortcut_input_row.dart +++ b/mobile_client/lib/presentation/new_shortcut/widgets/shortcut_input_row.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:laze/domain/models/shortcut/shortcut.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/styled_button.dart'; import 'package:laze/presentation/new_shortcut/widgets/icon_picker.dart'; @@ -63,7 +64,7 @@ class _ShortcutInputRowState extends State { @override Widget build(BuildContext context) { final appColors = Theme.of(context).extension()!; - const buttonHeight = 64.0; + const buttonHeight = 56.0; final counterColor = _nameLength >= Shortcut.maxNameLength ? appColors.primary : appColors.textMuted; @@ -71,9 +72,7 @@ class _ShortcutInputRowState extends State { return LayoutBuilder( builder: (context, constraints) { final isCompact = constraints.maxWidth < 430; - final buttonWidth = isCompact ? 88.0 : 116.0; - final inputFontSize = isCompact ? 24.0 : 30.0; - final hintFontSize = isCompact ? 21.0 : 26.0; + final buttonWidth = isCompact ? 72.0 : 88.0; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -94,7 +93,7 @@ class _ShortcutInputRowState extends State { maxLength: Shortcut.maxNameLength, style: TextStyle( color: appColors.textMuted, - fontSize: inputFontSize, + fontSize: Dimens.text.title, fontWeight: FontWeight.w600, ), decoration: InputDecoration( @@ -102,7 +101,7 @@ class _ShortcutInputRowState extends State { hintStyle: TextStyle( color: appColors.textMuted, fontWeight: FontWeight.w300, - fontSize: hintFontSize, + fontSize: Dimens.text.body, ), border: InputBorder.none, counterText: '', @@ -118,7 +117,7 @@ class _ShortcutInputRowState extends State { width: buttonWidth, height: buttonHeight, margin: EdgeInsets.zero, - iconSize: isCompact ? 26 : 30, + iconSize: isCompact ? 22 : 24, icon: widget.initIcon, onPressed: () => _openIconPicker(context), ), diff --git a/mobile_client/lib/presentation/new_shortcut/widgets/terminal_command.dart b/mobile_client/lib/presentation/new_shortcut/widgets/terminal_command.dart index 56e5bfd..7ef1261 100644 --- a/mobile_client/lib/presentation/new_shortcut/widgets/terminal_command.dart +++ b/mobile_client/lib/presentation/new_shortcut/widgets/terminal_command.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/styled_input.dart'; @@ -53,7 +54,7 @@ class _TerminalCommandInputState extends State { _capitalize(widget.operativeSystemName), style: TextStyle( color: appColors.text, - fontSize: 19, + fontSize: Dimens.text.title, fontWeight: FontWeight.w700, ), ), From 08aa788e4dca3bc0af687f6613610e89a3c15fda Mon Sep 17 00:00:00 2001 From: Sidnei Teixeira Date: Wed, 6 May 2026 02:34:56 +0100 Subject: [PATCH 7/7] Refine Onboarding tutorial illustrations and typography for better mobile scaling. --- .../onboarding/onboarding_screen.dart | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mobile_client/lib/presentation/onboarding/onboarding_screen.dart b/mobile_client/lib/presentation/onboarding/onboarding_screen.dart index 91c9878..670be85 100644 --- a/mobile_client/lib/presentation/onboarding/onboarding_screen.dart +++ b/mobile_client/lib/presentation/onboarding/onboarding_screen.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:laze/data/repositories/device/device_settings_repository.dart'; +import 'package:laze/presentation/core/themes/dimensions.dart'; import 'package:laze/presentation/core/themes/generated_theme.dart'; import 'package:laze/presentation/core/ui/controller_page.dart'; import 'package:laze/presentation/core/ui/cta_button.dart'; @@ -149,15 +150,14 @@ class _OnboardingScreenState extends State { current: _currentPage, appColors: appColors, ), - SizedBox(height: scale.spaceXl), + SizedBox(height: Dimens.spacing.xl), CtaButton( text: _isLastPage ? (_pages[_currentPage].ctaLabel ?? 'GET STARTED') : 'NEXT', - fontSize: 28, onPressed: _nextPage, ), - SizedBox(height: scale.spaceLg), + SizedBox(height: Dimens.spacing.lg), ], ), ); @@ -253,43 +253,43 @@ class _OnboardingPage extends StatelessWidget { children: [ SizedBox(height: scale.space2xl), Container( - width: 140, - height: 140, + width: 120, + height: 120, decoration: BoxDecoration( color: appColors.surface_2, - borderRadius: BorderRadius.circular(scale.radiusXl), + borderRadius: BorderRadius.circular(Dimens.radius.medium), border: Border.all(color: appColors.divider, width: 1), ), alignment: Alignment.center, child: Icon( data.icon, color: appColors.primary, - size: 72, + size: 56, ), ), SizedBox(height: scale.space2xl), Padding( - padding: EdgeInsets.symmetric(horizontal: scale.spaceLg), + padding: EdgeInsets.symmetric(horizontal: Dimens.spacing.lg), child: Text( data.title, textAlign: TextAlign.center, style: TextStyle( color: appColors.text, - fontSize: 28, + fontSize: Dimens.text.header, fontWeight: FontWeight.w800, height: 1.2, ), ), ), - SizedBox(height: scale.spaceLg), + SizedBox(height: Dimens.spacing.lg), Padding( - padding: EdgeInsets.symmetric(horizontal: scale.spaceXl), + padding: EdgeInsets.symmetric(horizontal: Dimens.spacing.xl), child: Text( data.description, textAlign: TextAlign.center, style: TextStyle( color: appColors.textMuted, - fontSize: 16, + fontSize: Dimens.text.body, height: 1.45, ), ),