Not a member of GistPad yet?
Sign Up,
it unlocks many cool features!
- 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<HomePage> createState() => _HomePageState();
- }
- class _HomePageState extends State<HomePage> {
- 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<double>(
- 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<void>(
- 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<void>(
- 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<ServiceFrame> createState() => _ServiceFrameState();
- }
- class _ServiceFrameState extends State<ServiceFrame> {
- 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,
- );
- }
- }
RAW Paste Data
Copied
