Code 1 : import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; class AppSpacing { static const double xs = 4.0; static const double sm = 8.0; static const double md = 16.0; static const double lg = 24.0; static const double xl = 32.0; static const double xxl = 48.0; static const EdgeInsets paddingXs = EdgeInsets.all(xs); static const EdgeInsets paddingSm = EdgeInsets.all(sm); static const EdgeInsets paddingMd = EdgeInsets.all(md); static const EdgeInsets paddingLg = EdgeInsets.all(lg); static const EdgeInsets paddingXl = EdgeInsets.all(xl); static const EdgeInsets horizontalXs = EdgeInsets.symmetric(horizontal: xs); static const EdgeInsets horizontalSm = EdgeInsets.symmetric(horizontal: sm); static const EdgeInsets horizontalMd = EdgeInsets.symmetric(horizontal: md); static const EdgeInsets horizontalLg = EdgeInsets.symmetric(horizontal: lg); static const EdgeInsets horizontalXl = EdgeInsets.symmetric(horizontal: xl); static const EdgeInsets verticalXs = EdgeInsets.symmetric(vertical: xs); static const EdgeInsets verticalSm = EdgeInsets.symmetric(vertical: sm); static const EdgeInsets verticalMd = EdgeInsets.symmetric(vertical: md); static const EdgeInsets verticalLg = EdgeInsets.symmetric(vertical: lg); static const EdgeInsets verticalXl = EdgeInsets.symmetric(vertical: xl); } class AppRadius { static const double sm = 8.0; static const double md = 12.0; static const double lg = 16.0; static const double xl = 24.0; } extension TextStyleContext on BuildContext { TextTheme get textStyles => Theme.of(this).textTheme; } extension TextStyleExtensions on TextStyle { TextStyle get bold => copyWith(fontWeight: FontWeight.bold); TextStyle get semiBold => copyWith(fontWeight: FontWeight.w600); TextStyle get medium => copyWith(fontWeight: FontWeight.w500); TextStyle get normal => copyWith(fontWeight: FontWeight.w400); TextStyle get light => copyWith(fontWeight: FontWeight.w300); TextStyle withColor(Color color) => copyWith(color: color); TextStyle withSize(double size) => copyWith(fontSize: size); } /// Minimal Mauritanian-inspired palette (flag: green + gold), kept intentionally calm. class LightModeColors { static const lightPrimary = Color(0xFF0F6B3A); static const lightOnPrimary = Color(0xFFFFFFFF); static const lightPrimaryContainer = Color(0xFFDDF4E8); static const lightOnPrimaryContainer = Color(0xFF062716); static const lightSecondary = Color(0xFFD6A100); static const lightOnSecondary = Color(0xFF1B1400); static const lightTertiary = Color(0xFF1B2A24); static const lightOnTertiary = Color(0xFFFFFFFF); static const lightError = Color(0xFFBA1A1A); static const lightOnError = Color(0xFFFFFFFF); static const lightErrorContainer = Color(0xFFFFDAD6); static const lightOnErrorContainer = Color(0xFF410002); static const lightSurface = Color(0xFFFFFFFF); static const lightOnSurface = Color(0xFF0E1512); static const lightBackground = Color(0xFFF7F5EF); static const lightSurfaceVariant = Color(0xFFE9E6DD); static const lightOnSurfaceVariant = Color(0xFF3C4A44); static const lightOutline = Color(0xFF7C8B84); static const lightShadow = Color(0xFF000000); static const lightInversePrimary = Color(0xFF8AD8AE); } class DarkModeColors { static const darkPrimary = Color(0xFF4CD58C); static const darkOnPrimary = Color(0xFF062816); static const darkPrimaryContainer = Color(0xFF0A3D22); static const darkOnPrimaryContainer = Color(0xFFCFF3E0); static const darkSecondary = Color(0xFFFFD16A); static const darkOnSecondary = Color(0xFF261A00); static const darkTertiary = Color(0xFFE7E2D6); static const darkOnTertiary = Color(0xFF13130F); static const darkError = Color(0xFFFFB4AB); static const darkOnError = Color(0xFF690005); static const darkErrorContainer = Color(0xFF93000A); static const darkOnErrorContainer = Color(0xFFFFDAD6); static const darkSurface = Color(0xFF0D1411); static const darkOnSurface = Color(0xFFEAF1ED); static const darkSurfaceVariant = Color(0xFF1C2622); static const darkOnSurfaceVariant = Color(0xFFB8C7C0); static const darkOutline = Color(0xFF5D7067); static const darkShadow = Color(0xFF000000); static const darkInversePrimary = Color(0xFF0F6B3A); } class FontSizes { static const double displayLarge = 57.0; static const double displayMedium = 45.0; static const double displaySmall = 36.0; static const double headlineLarge = 32.0; static const double headlineMedium = 28.0; static const double headlineSmall = 24.0; static const double titleLarge = 22.0; static const double titleMedium = 16.0; static const double titleSmall = 14.0; static const double labelLarge = 14.0; static const double labelMedium = 12.0; static const double labelSmall = 11.0; static const double bodyLarge = 16.0; static const double bodyMedium = 14.0; static const double bodySmall = 12.0; } ThemeData get lightTheme => ThemeData( useMaterial3: true, splashFactory: NoSplash.splashFactory, highlightColor: Colors.transparent, splashColor: Colors.transparent, colorScheme: const ColorScheme.light( primary: LightModeColors.lightPrimary, onPrimary: LightModeColors.lightOnPrimary, primaryContainer: LightModeColors.lightPrimaryContainer, onPrimaryContainer: LightModeColors.lightOnPrimaryContainer, secondary: LightModeColors.lightSecondary, onSecondary: LightModeColors.lightOnSecondary, tertiary: LightModeColors.lightTertiary, onTertiary: LightModeColors.lightOnTertiary, error: LightModeColors.lightError, onError: LightModeColors.lightOnError, errorContainer: LightModeColors.lightErrorContainer, onErrorContainer: LightModeColors.lightOnErrorContainer, surface: LightModeColors.lightSurface, onSurface: LightModeColors.lightOnSurface, surfaceContainerHighest: LightModeColors.lightSurfaceVariant, onSurfaceVariant: LightModeColors.lightOnSurfaceVariant, outline: LightModeColors.lightOutline, shadow: LightModeColors.lightShadow, inversePrimary: LightModeColors.lightInversePrimary, ), brightness: Brightness.light, scaffoldBackgroundColor: LightModeColors.lightBackground, appBarTheme: const AppBarTheme( backgroundColor: Colors.transparent, foregroundColor: LightModeColors.lightOnSurface, elevation: 0, scrolledUnderElevation: 0, ), cardTheme: CardThemeData( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide(color: LightModeColors.lightOutline.withValues(alpha: 0.20), width: 1), ), ), filledButtonTheme: FilledButtonThemeData( style: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)), textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)), textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)), ), ), textTheme: _buildTextTheme(Brightness.light), ); ThemeData get darkTheme => ThemeData( useMaterial3: true, splashFactory: NoSplash.splashFactory, highlightColor: Colors.transparent, splashColor: Colors.transparent, colorScheme: const ColorScheme.dark( primary: DarkModeColors.darkPrimary, onPrimary: DarkModeColors.darkOnPrimary, primaryContainer: DarkModeColors.darkPrimaryContainer, onPrimaryContainer: DarkModeColors.darkOnPrimaryContainer, secondary: DarkModeColors.darkSecondary, onSecondary: DarkModeColors.darkOnSecondary, tertiary: DarkModeColors.darkTertiary, onTertiary: DarkModeColors.darkOnTertiary, error: DarkModeColors.darkError, onError: DarkModeColors.darkOnError, errorContainer: DarkModeColors.darkErrorContainer, onErrorContainer: DarkModeColors.darkOnErrorContainer, surface: DarkModeColors.darkSurface, onSurface: DarkModeColors.darkOnSurface, surfaceContainerHighest: DarkModeColors.darkSurfaceVariant, onSurfaceVariant: DarkModeColors.darkOnSurfaceVariant, outline: DarkModeColors.darkOutline, shadow: DarkModeColors.darkShadow, inversePrimary: DarkModeColors.darkInversePrimary, ), brightness: Brightness.dark, scaffoldBackgroundColor: DarkModeColors.darkSurface, appBarTheme: const AppBarTheme( backgroundColor: Colors.transparent, foregroundColor: DarkModeColors.darkOnSurface, elevation: 0, scrolledUnderElevation: 0, ), cardTheme: CardThemeData( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide(color: DarkModeColors.darkOutline.withValues(alpha: 0.20), width: 1), ), ), filledButtonTheme: FilledButtonThemeData( style: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)), textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)), ), ), outlinedButtonTheme: OutlinedButtonThemeData( style: ButtonStyle( shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))), padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)), textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)), ), ), textTheme: _buildTextTheme(Brightness.dark), ); TextTheme _buildTextTheme(Brightness brightness) { // Keep Inter for a modern look; Arabic glyph support relies on system fallback. return TextTheme( displayLarge: GoogleFonts.inter(fontSize: FontSizes.displayLarge, fontWeight: FontWeight.w400, letterSpacing: -0.25), displayMedium: GoogleFonts.inter(fontSize: FontSizes.displayMedium, fontWeight: FontWeight.w400), displaySmall: GoogleFonts.inter(fontSize: FontSizes.displaySmall, fontWeight: FontWeight.w400), headlineLarge: GoogleFonts.inter(fontSize: FontSizes.headlineLarge, fontWeight: FontWeight.w600, letterSpacing: -0.5), headlineMedium: GoogleFonts.inter(fontSize: FontSizes.headlineMedium, fontWeight: FontWeight.w600), headlineSmall: GoogleFonts.inter(fontSize: FontSizes.headlineSmall, fontWeight: FontWeight.w600), titleLarge: GoogleFonts.inter(fontSize: FontSizes.titleLarge, fontWeight: FontWeight.w600), titleMedium: GoogleFonts.inter(fontSize: FontSizes.titleMedium, fontWeight: FontWeight.w500), titleSmall: GoogleFonts.inter(fontSize: FontSizes.titleSmall, fontWeight: FontWeight.w500), labelLarge: GoogleFonts.inter(fontSize: FontSizes.labelLarge, fontWeight: FontWeight.w500, letterSpacing: 0.1), labelMedium: GoogleFonts.inter(fontSize: FontSizes.labelMedium, fontWeight: FontWeight.w500, letterSpacing: 0.5), labelSmall: GoogleFonts.inter(fontSize: FontSizes.labelSmall, fontWeight: FontWeight.w500, letterSpacing: 0.5), bodyLarge: GoogleFonts.inter(fontSize: FontSizes.bodyLarge, fontWeight: FontWeight.w400, letterSpacing: 0.15), bodyMedium: GoogleFonts.inter(fontSize: FontSizes.bodyMedium, fontWeight: FontWeight.w400, letterSpacing: 0.25), bodySmall: GoogleFonts.inter(fontSize: FontSizes.bodySmall, fontWeight: FontWeight.w400, letterSpacing: 0.4), ); } Code 2 : import 'package:flutter/material.dart'; import 'package:banck/theme.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State createState() => _HomePageState(); } class _HomePageState extends State { bool _hideBalance = true; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Directionality( textDirection: TextDirection.rtl, child: SafeArea( child: CustomScrollView( slivers: [ SliverPadding( padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.sm, AppSpacing.md, 0), sliver: SliverToBoxAdapter( child: Row( children: [ _TopIconButton(icon: Icons.menu_rounded, label: 'القائمة', onPressed: () => _showQuickSheet(context)), const Spacer(), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text('mebanck', style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w800, color: scheme.tertiary)), const SizedBox(height: 2), Text('محفظة بسيطة', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2)), ], ), const SizedBox(width: AppSpacing.md), _TopIconButton(icon: Icons.notifications_none_rounded, label: 'إشعارات', onPressed: () => _showSnack(context, 'لا توجد إشعارات الآن')), ], ), ), ), SliverPadding( padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.lg, AppSpacing.md, 0), sliver: SliverToBoxAdapter( child: TweenAnimationBuilder( duration: const Duration(milliseconds: 520), curve: Curves.easeOutCubic, tween: Tween(begin: 0, end: 1), builder: (context, t, child) => Opacity(opacity: t, child: Transform.translate(offset: Offset(0, (1 - t) * 10), child: child)), child: BalancePanel( isHidden: _hideBalance, onToggle: () => setState(() => _hideBalance = !_hideBalance), balanceText: _hideBalance ? '•••••' : '12,450 MRU', subtitle: 'الرصيد المتاح', ), ), ), ), const SliverToBoxAdapter(child: SizedBox(height: AppSpacing.lg)), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md), sliver: SliverToBoxAdapter( child: Row( children: [ Expanded( child: OutlinedButton.icon( onPressed: () => _showSnack(context, 'إرسال (قريباً)'), icon: Icon(Icons.call_made_rounded, color: scheme.primary), label: Text('إرسال', style: TextStyle(color: scheme.primary)), ), ), const SizedBox(width: AppSpacing.md), Expanded( child: FilledButton.icon( onPressed: () => _showSnack(context, 'استلام (قريباً)'), icon: Icon(Icons.call_received_rounded, color: scheme.onPrimary), label: Text('استلام', style: TextStyle(color: scheme.onPrimary)), ), ), ], ), ), ), const SliverToBoxAdapter(child: SizedBox(height: AppSpacing.lg)), SliverPadding( padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md), sliver: SliverToBoxAdapter( child: ServicesTwoColumns( onTap: (id) { switch (id) { case 'pay': _showSnack(context, 'الدفع (قريباً)'); return; case 'transfer': _showSnack(context, 'التحويل (قريباً)'); return; case 'topup': _showSnack(context, 'شحن الهاتف (قريباً)'); return; case 'cashout': _showSnack(context, 'سحب (قريباً)'); return; case 'bills': _showSnack(context, 'الفواتير (قريباً)'); return; case 'more': _showMoreServices(context); return; } }, ), ), ), SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.lg, AppSpacing.md, AppSpacing.xxl), child: Container( decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), padding: const EdgeInsets.all(AppSpacing.md), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)), child: Icon(Icons.shield_outlined, color: scheme.onPrimaryContainer, size: 22), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('نصيحة', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 2), Text('لا تشارك رمزك السري، وفعّل القفل إن توفر.', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.4)), ], ), ), ], ), ), ), ), ], ), ), ); } void _showSnack(BuildContext context, String message) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message, textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating, showCloseIcon: true), ); } void _showQuickSheet(BuildContext context) { final scheme = Theme.of(context).colorScheme; showModalBottomSheet( context: context, showDragHandle: true, backgroundColor: scheme.surface, builder: (context) => Padding( padding: const EdgeInsets.fromLTRB(AppSpacing.lg, 0, AppSpacing.lg, AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('إجراءات سريعة', style: Theme.of(context).textTheme.titleLarge, textDirection: TextDirection.rtl), const SizedBox(height: AppSpacing.md), Wrap( spacing: AppSpacing.sm, runSpacing: AppSpacing.sm, children: [ _QuickChip(icon: Icons.qr_code_scanner_rounded, label: 'QR', onTap: () => Navigator.of(context).pop()), _QuickChip(icon: Icons.person_add_alt_1_rounded, label: 'مستفيد جديد', onTap: () => Navigator.of(context).pop()), _QuickChip(icon: Icons.support_agent_rounded, label: 'مساعدة', onTap: () => Navigator.of(context).pop()), ], ), ], ), ), ); } void _showMoreServices(BuildContext context) { final scheme = Theme.of(context).colorScheme; showModalBottomSheet( context: context, showDragHandle: true, backgroundColor: scheme.surface, builder: (context) => Padding( padding: const EdgeInsets.fromLTRB(AppSpacing.lg, 0, AppSpacing.lg, AppSpacing.lg), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('خدمات أكثر', style: Theme.of(context).textTheme.titleLarge, textDirection: TextDirection.rtl), const SizedBox(height: AppSpacing.md), _SheetRow(icon: Icons.storefront_outlined, title: 'دفع للتجار', onTap: () => Navigator.of(context).pop()), _SheetRow(icon: Icons.school_outlined, title: 'رسوم المدرسة', onTap: () => Navigator.of(context).pop()), _SheetRow(icon: Icons.directions_bus_outlined, title: 'مواصلات', onTap: () => Navigator.of(context).pop()), ], ), ), ); } } class BalancePanel extends StatelessWidget { const BalancePanel({super.key, required this.isHidden, required this.onToggle, required this.balanceText, required this.subtitle}); final bool isHidden; final VoidCallback onToggle; final String balanceText; final String subtitle; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; final gradient = LinearGradient( begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [scheme.primary, scheme.primary.withValues(alpha: 0.86)], ); return Container( decoration: BoxDecoration(gradient: gradient, borderRadius: BorderRadius.circular(AppRadius.xl)), padding: const EdgeInsets.all(AppSpacing.lg), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onPrimary.withValues(alpha: 0.90), height: 1.2)), const SizedBox(height: 8), Text(balanceText, style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: scheme.onPrimary, fontWeight: FontWeight.w900)), const SizedBox(height: 12), Row( children: [ _BalanceToggle(isHidden: isHidden, onPressed: onToggle), const SizedBox(width: 10), Text('إخفاء/إظهار', style: Theme.of(context).textTheme.labelMedium?.copyWith(color: scheme.onPrimary.withValues(alpha: 0.92))), ], ), ], ), ), const SizedBox(width: AppSpacing.md), Container( width: 64, height: 64, decoration: BoxDecoration(color: scheme.onPrimary.withValues(alpha: 0.14), borderRadius: BorderRadius.circular(18)), child: Icon(Icons.account_balance_wallet_rounded, color: scheme.onPrimary, size: 30), ), ], ), ); } } class _BalanceToggle extends StatefulWidget { const _BalanceToggle({required this.isHidden, required this.onPressed}); final bool isHidden; final VoidCallback onPressed; @override State<_BalanceToggle> createState() => _BalanceToggleState(); } class _BalanceToggleState extends State<_BalanceToggle> { bool _pressed = false; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return GestureDetector( onTapDown: (_) => setState(() => _pressed = true), onTapCancel: () => setState(() => _pressed = false), onTapUp: (_) => setState(() => _pressed = false), onTap: widget.onPressed, child: AnimatedContainer( duration: const Duration(milliseconds: 160), curve: Curves.easeOut, width: 62, height: 34, padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: scheme.onPrimary.withValues(alpha: 0.18), borderRadius: BorderRadius.circular(40), border: Border.all(color: scheme.onPrimary.withValues(alpha: _pressed ? 0.45 : 0.25)), ), child: Align( alignment: widget.isHidden ? Alignment.centerLeft : Alignment.centerRight, child: Container( width: 26, height: 26, decoration: BoxDecoration(color: scheme.onPrimary, borderRadius: BorderRadius.circular(26)), child: Icon(widget.isHidden ? Icons.visibility_off_rounded : Icons.visibility_rounded, size: 16, color: scheme.primary), ), ), ), ); } } class ServicesTwoColumns extends StatelessWidget { const ServicesTwoColumns({super.key, required this.onTap}); final void Function(String id) onTap; @override Widget build(BuildContext context) { return Row( children: [ Expanded( child: Column( children: [ ServiceFrame(id: 'pay', icon: Icons.payments_outlined, title: 'الدفع', subtitle: 'للتجار', onTap: onTap), const SizedBox(height: AppSpacing.md), ServiceFrame(id: 'topup', icon: Icons.phone_iphone_rounded, title: 'شحن', subtitle: 'الهاتف', onTap: onTap), const SizedBox(height: AppSpacing.md), ServiceFrame(id: 'bills', icon: Icons.receipt_long_outlined, title: 'فواتير', subtitle: 'كهرباء/ماء', onTap: onTap), ], ), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( children: [ ServiceFrame(id: 'transfer', icon: Icons.swap_horiz_rounded, title: 'تحويل', subtitle: 'إرسال/استلام', onTap: onTap), const SizedBox(height: AppSpacing.md), ServiceFrame(id: 'cashout', icon: Icons.local_atm_outlined, title: 'سحب', subtitle: 'نقاط خدمة', onTap: onTap), const SizedBox(height: AppSpacing.md), ServiceFrame(id: 'more', icon: Icons.grid_view_rounded, title: 'المزيد', subtitle: 'خدمات', onTap: onTap), ], ), ), ], ); } } class ServiceFrame extends StatefulWidget { const ServiceFrame({super.key, required this.id, required this.icon, required this.title, required this.subtitle, required this.onTap}); final String id; final IconData icon; final String title; final String subtitle; final void Function(String id) onTap; @override State createState() => _ServiceFrameState(); } class _ServiceFrameState extends State { bool _pressed = false; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return GestureDetector( onTap: () => widget.onTap(widget.id), onTapDown: (_) => setState(() => _pressed = true), onTapCancel: () => setState(() => _pressed = false), onTapUp: (_) => setState(() => _pressed = false), child: AnimatedScale( duration: const Duration(milliseconds: 130), curve: Curves.easeOut, scale: _pressed ? 0.985 : 1, child: AnimatedContainer( duration: const Duration(milliseconds: 170), curve: Curves.easeOut, padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: 14), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.md), border: Border.all(color: scheme.outline.withValues(alpha: _pressed ? 0.22 : 0.14)), ), child: Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(12)), child: Icon(widget.icon, color: scheme.onPrimaryContainer, size: 20), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)), const SizedBox(height: 2), Text(widget.subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2), maxLines: 1, overflow: TextOverflow.ellipsis), ], ), ), Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant), ], ), ), ), ); } } class _TopIconButton extends StatelessWidget { const _TopIconButton({required this.icon, required this.label, required this.onPressed}); final IconData icon; final String label; final VoidCallback onPressed; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Semantics( button: true, label: label, child: GestureDetector( onTap: onPressed, child: Container( width: 46, height: 46, decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(16), border: Border.all(color: scheme.outline.withValues(alpha: 0.12)), ), child: Icon(icon, color: scheme.onSurface), ), ), ); } } class _QuickChip extends StatelessWidget { const _QuickChip({required this.icon, required this.label, required this.onTap}); final IconData icon; final String label; final VoidCallback onTap; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(999), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 18, color: scheme.onSurface), const SizedBox(width: 8), Text(label, style: Theme.of(context).textTheme.labelLarge), ], ), ), ); } } class _SheetRow extends StatelessWidget { const _SheetRow({required this.icon, required this.title, required this.onTap}); final IconData icon; final String title; final VoidCallback onTap; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Padding( padding: const EdgeInsets.only(bottom: AppSpacing.sm), child: GestureDetector( onTap: onTap, child: Container( decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: scheme.outline.withValues(alpha: 0.12)), ), padding: const EdgeInsets.all(AppSpacing.md), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)), child: Icon(icon, color: scheme.onPrimaryContainer), ), const SizedBox(width: AppSpacing.md), Expanded(child: Text(title, style: Theme.of(context).textTheme.titleMedium, textDirection: TextDirection.rtl)), Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant), ], ), ), ), ); } } Code 3 : import 'package:flutter/material.dart'; import 'package:banck/theme.dart'; class HistoryPage extends StatelessWidget { const HistoryPage({super.key}); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Directionality( textDirection: TextDirection.rtl, child: SafeArea( child: Padding( padding: const EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('السجل', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)), const SizedBox(height: AppSpacing.sm), Text('آخر العمليات (نموذج تجريبي).', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)), const SizedBox(height: AppSpacing.lg), Expanded( child: ListView.separated( itemCount: 8, separatorBuilder: (_, __) => const SizedBox(height: AppSpacing.sm), itemBuilder: (context, index) { final isIn = index.isEven; return _TxnRow( icon: isIn ? Icons.call_received_rounded : Icons.call_made_rounded, title: isIn ? 'استلام' : 'إرسال', subtitle: 'اليوم • 12:${30 + index}', amount: isIn ? '+ 1,200' : '- 250', amountColor: isIn ? scheme.secondary : scheme.onSurface, ); }, ), ), ], ), ), ), ); } } class _TxnRow extends StatelessWidget { const _TxnRow({required this.icon, required this.title, required this.subtitle, required this.amount, required this.amountColor}); final IconData icon; final String title; final String subtitle; final String amount; final Color amountColor; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Container( padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)), child: Icon(icon, color: scheme.onPrimaryContainer, size: 20), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)), const SizedBox(height: 2), Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)), ], ), ), Text(amount, style: Theme.of(context).textTheme.titleMedium?.copyWith(color: amountColor, fontWeight: FontWeight.w900)), ], ), ); } } Code 4: import 'package:flutter/material.dart'; import 'package:banck/theme.dart'; class QrPage extends StatelessWidget { const QrPage({super.key}); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Directionality( textDirection: TextDirection.rtl, child: SafeArea( child: Padding( padding: const EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('QR', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)), const SizedBox(height: AppSpacing.sm), Text('اعرض رمزك ليستلم الآخرون منك، أو امسح لاحقاً عند إضافة الكاميرا.', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)), const SizedBox(height: AppSpacing.lg), Expanded( child: Container( decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Center( child: Container( width: 230, height: 230, decoration: BoxDecoration( color: scheme.primaryContainer, borderRadius: BorderRadius.circular(22), ), child: Stack( children: [ Center(child: Icon(Icons.qr_code_2_rounded, size: 130, color: scheme.onPrimaryContainer)), Positioned( right: 14, top: 14, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(999), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.verified_rounded, size: 16, color: scheme.primary), const SizedBox(width: 6), Text('mebanck', style: Theme.of(context).textTheme.labelMedium?.copyWith(fontWeight: FontWeight.w800)), ], ), ), ), ], ), ), ), ), ), const SizedBox(height: AppSpacing.md), FilledButton.icon( onPressed: () => ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('سيتم إضافة المسح الحقيقي لاحقاً', textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating), ), icon: Icon(Icons.qr_code_scanner_rounded, color: scheme.onPrimary), label: Text('مسح (قريباً)', style: TextStyle(color: scheme.onPrimary)), ), ], ), ), ), ); } } Code 5 import 'package:flutter/material.dart'; import 'package:banck/theme.dart'; class BankPage extends StatelessWidget { const BankPage({super.key}); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Directionality( textDirection: TextDirection.rtl, child: SafeArea( child: Padding( padding: const EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('الحساب', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)), const SizedBox(height: AppSpacing.sm), Text('معلومات مختصرة للحساب (واجهة قابلة للتطوير).', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)), const SizedBox(height: AppSpacing.lg), _InfoCard(icon: Icons.account_balance_wallet_rounded, title: 'محفظة mebanck', subtitle: 'MRU • حساب شخصي', trailing: '49055137'), const SizedBox(height: AppSpacing.sm), _InfoCard(icon: Icons.location_on_outlined, title: 'المدينة', subtitle: 'نواكشوط', trailing: 'MR'), ], ), ), ), ); } } class _InfoCard extends StatelessWidget { const _InfoCard({required this.icon, required this.title, required this.subtitle, required this.trailing}); final IconData icon; final String title; final String subtitle; final String trailing; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Container( padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( children: [ Container( width: 42, height: 42, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)), child: Icon(icon, color: scheme.onPrimaryContainer, size: 20), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)), const SizedBox(height: 2), Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)), ], ), ), Text(trailing, style: Theme.of(context).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)), ], ), ); } } Code 6:import 'package:flutter/material.dart'; import 'package:banck/theme.dart'; class ProfilePage extends StatelessWidget { const ProfilePage({super.key}); @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Directionality( textDirection: TextDirection.rtl, child: SafeArea( child: Padding( padding: const EdgeInsets.all(AppSpacing.md), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('حسابي', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)), const SizedBox(height: AppSpacing.lg), Container( padding: const EdgeInsets.all(AppSpacing.lg), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.xl), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( children: [ CircleAvatar(radius: 26, backgroundColor: scheme.primaryContainer, child: Icon(Icons.person_rounded, color: scheme.onPrimaryContainer)), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('مستخدم', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w900)), const SizedBox(height: 2), Text('بدون تسجيل دخول', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(999)), child: Text('MRU', style: Theme.of(context).textTheme.labelMedium?.copyWith(color: scheme.onPrimaryContainer, fontWeight: FontWeight.w900)), ), ], ), ), const SizedBox(height: AppSpacing.lg), _SettingTile(icon: Icons.security_rounded, title: 'الأمان', subtitle: 'رمز وقفل', onTap: () => _snack(context, 'الأمان (قريباً)')), _SettingTile(icon: Icons.language_rounded, title: 'اللغة', subtitle: 'العربية / الفرنسية', onTap: () => _snack(context, 'تغيير اللغة (قريباً)')), _SettingTile(icon: Icons.support_agent_rounded, title: 'مساعدة', subtitle: 'الدعم', onTap: () => _snack(context, 'الدعم (قريباً)')), ], ), ), ), ); } void _snack(BuildContext context, String message) => ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(message, textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating), ); } class _SettingTile extends StatelessWidget { const _SettingTile({required this.icon, required this.title, required this.subtitle, required this.onTap}); final IconData icon; final String title; final String subtitle; final VoidCallback onTap; @override Widget build(BuildContext context) { final scheme = Theme.of(context).colorScheme; return Padding( padding: const EdgeInsets.only(bottom: AppSpacing.sm), child: GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: scheme.surface, borderRadius: BorderRadius.circular(AppRadius.lg), border: Border.all(color: scheme.outline.withValues(alpha: 0.14)), ), child: Row( children: [ Container( width: 44, height: 44, decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)), child: Icon(icon, color: scheme.onPrimaryContainer), ), const SizedBox(width: AppSpacing.md), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w900)), const SizedBox(height: 2), Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2)), ], ), ), Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant), ], ), ), ), ); } } Code 7 : import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:banck/nav.dart'; import 'package:banck/theme.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp.router( title: 'mebanck', debugShowCheckedModeBanner: false, theme: lightTheme, darkTheme: darkTheme, themeMode: ThemeMode.system, locale: const Locale('ar'), supportedLocales: const [Locale('ar'), Locale('fr'), Locale('en')], localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], routerConfig: AppRouter.router, ); } }