Guest

Untitled 922

Mar 29th, 2026
15
0
Never
Not a member of GistPad yet? Sign Up, it unlocks many cool features!
None 99.52 KB | None | 0 0
  1. Code 1 :
  2. import 'package:flutter/material.dart';
  3. import 'package:google_fonts/google_fonts.dart';
  4.  
  5. class AppSpacing {
  6. static const double xs = 4.0;
  7. static const double sm = 8.0;
  8. static const double md = 16.0;
  9. static const double lg = 24.0;
  10. static const double xl = 32.0;
  11. static const double xxl = 48.0;
  12.  
  13. static const EdgeInsets paddingXs = EdgeInsets.all(xs);
  14. static const EdgeInsets paddingSm = EdgeInsets.all(sm);
  15. static const EdgeInsets paddingMd = EdgeInsets.all(md);
  16. static const EdgeInsets paddingLg = EdgeInsets.all(lg);
  17. static const EdgeInsets paddingXl = EdgeInsets.all(xl);
  18.  
  19. static const EdgeInsets horizontalXs = EdgeInsets.symmetric(horizontal: xs);
  20. static const EdgeInsets horizontalSm = EdgeInsets.symmetric(horizontal: sm);
  21. static const EdgeInsets horizontalMd = EdgeInsets.symmetric(horizontal: md);
  22. static const EdgeInsets horizontalLg = EdgeInsets.symmetric(horizontal: lg);
  23. static const EdgeInsets horizontalXl = EdgeInsets.symmetric(horizontal: xl);
  24.  
  25. static const EdgeInsets verticalXs = EdgeInsets.symmetric(vertical: xs);
  26. static const EdgeInsets verticalSm = EdgeInsets.symmetric(vertical: sm);
  27. static const EdgeInsets verticalMd = EdgeInsets.symmetric(vertical: md);
  28. static const EdgeInsets verticalLg = EdgeInsets.symmetric(vertical: lg);
  29. static const EdgeInsets verticalXl = EdgeInsets.symmetric(vertical: xl);
  30. }
  31.  
  32. class AppRadius {
  33. static const double sm = 8.0;
  34. static const double md = 12.0;
  35. static const double lg = 16.0;
  36. static const double xl = 24.0;
  37. }
  38.  
  39. extension TextStyleContext on BuildContext {
  40. TextTheme get textStyles => Theme.of(this).textTheme;
  41. }
  42.  
  43. extension TextStyleExtensions on TextStyle {
  44. TextStyle get bold => copyWith(fontWeight: FontWeight.bold);
  45. TextStyle get semiBold => copyWith(fontWeight: FontWeight.w600);
  46. TextStyle get medium => copyWith(fontWeight: FontWeight.w500);
  47. TextStyle get normal => copyWith(fontWeight: FontWeight.w400);
  48. TextStyle get light => copyWith(fontWeight: FontWeight.w300);
  49. TextStyle withColor(Color color) => copyWith(color: color);
  50. TextStyle withSize(double size) => copyWith(fontSize: size);
  51. }
  52.  
  53. /// Minimal Mauritanian-inspired palette (flag: green + gold), kept intentionally calm.
  54. class LightModeColors {
  55. static const lightPrimary = Color(0xFF0F6B3A);
  56. static const lightOnPrimary = Color(0xFFFFFFFF);
  57. static const lightPrimaryContainer = Color(0xFFDDF4E8);
  58. static const lightOnPrimaryContainer = Color(0xFF062716);
  59.  
  60. static const lightSecondary = Color(0xFFD6A100);
  61. static const lightOnSecondary = Color(0xFF1B1400);
  62.  
  63. static const lightTertiary = Color(0xFF1B2A24);
  64. static const lightOnTertiary = Color(0xFFFFFFFF);
  65.  
  66. static const lightError = Color(0xFFBA1A1A);
  67. static const lightOnError = Color(0xFFFFFFFF);
  68. static const lightErrorContainer = Color(0xFFFFDAD6);
  69. static const lightOnErrorContainer = Color(0xFF410002);
  70.  
  71. static const lightSurface = Color(0xFFFFFFFF);
  72. static const lightOnSurface = Color(0xFF0E1512);
  73. static const lightBackground = Color(0xFFF7F5EF);
  74. static const lightSurfaceVariant = Color(0xFFE9E6DD);
  75. static const lightOnSurfaceVariant = Color(0xFF3C4A44);
  76.  
  77. static const lightOutline = Color(0xFF7C8B84);
  78. static const lightShadow = Color(0xFF000000);
  79. static const lightInversePrimary = Color(0xFF8AD8AE);
  80. }
  81.  
  82. class DarkModeColors {
  83. static const darkPrimary = Color(0xFF4CD58C);
  84. static const darkOnPrimary = Color(0xFF062816);
  85. static const darkPrimaryContainer = Color(0xFF0A3D22);
  86. static const darkOnPrimaryContainer = Color(0xFFCFF3E0);
  87.  
  88. static const darkSecondary = Color(0xFFFFD16A);
  89. static const darkOnSecondary = Color(0xFF261A00);
  90.  
  91. static const darkTertiary = Color(0xFFE7E2D6);
  92. static const darkOnTertiary = Color(0xFF13130F);
  93.  
  94. static const darkError = Color(0xFFFFB4AB);
  95. static const darkOnError = Color(0xFF690005);
  96. static const darkErrorContainer = Color(0xFF93000A);
  97. static const darkOnErrorContainer = Color(0xFFFFDAD6);
  98.  
  99. static const darkSurface = Color(0xFF0D1411);
  100. static const darkOnSurface = Color(0xFFEAF1ED);
  101. static const darkSurfaceVariant = Color(0xFF1C2622);
  102. static const darkOnSurfaceVariant = Color(0xFFB8C7C0);
  103.  
  104. static const darkOutline = Color(0xFF5D7067);
  105. static const darkShadow = Color(0xFF000000);
  106. static const darkInversePrimary = Color(0xFF0F6B3A);
  107. }
  108.  
  109. class FontSizes {
  110. static const double displayLarge = 57.0;
  111. static const double displayMedium = 45.0;
  112. static const double displaySmall = 36.0;
  113. static const double headlineLarge = 32.0;
  114. static const double headlineMedium = 28.0;
  115. static const double headlineSmall = 24.0;
  116. static const double titleLarge = 22.0;
  117. static const double titleMedium = 16.0;
  118. static const double titleSmall = 14.0;
  119. static const double labelLarge = 14.0;
  120. static const double labelMedium = 12.0;
  121. static const double labelSmall = 11.0;
  122. static const double bodyLarge = 16.0;
  123. static const double bodyMedium = 14.0;
  124. static const double bodySmall = 12.0;
  125. }
  126.  
  127. ThemeData get lightTheme => ThemeData(
  128. useMaterial3: true,
  129. splashFactory: NoSplash.splashFactory,
  130. highlightColor: Colors.transparent,
  131. splashColor: Colors.transparent,
  132. colorScheme: const ColorScheme.light(
  133. primary: LightModeColors.lightPrimary,
  134. onPrimary: LightModeColors.lightOnPrimary,
  135. primaryContainer: LightModeColors.lightPrimaryContainer,
  136. onPrimaryContainer: LightModeColors.lightOnPrimaryContainer,
  137. secondary: LightModeColors.lightSecondary,
  138. onSecondary: LightModeColors.lightOnSecondary,
  139. tertiary: LightModeColors.lightTertiary,
  140. onTertiary: LightModeColors.lightOnTertiary,
  141. error: LightModeColors.lightError,
  142. onError: LightModeColors.lightOnError,
  143. errorContainer: LightModeColors.lightErrorContainer,
  144. onErrorContainer: LightModeColors.lightOnErrorContainer,
  145. surface: LightModeColors.lightSurface,
  146. onSurface: LightModeColors.lightOnSurface,
  147. surfaceContainerHighest: LightModeColors.lightSurfaceVariant,
  148. onSurfaceVariant: LightModeColors.lightOnSurfaceVariant,
  149. outline: LightModeColors.lightOutline,
  150. shadow: LightModeColors.lightShadow,
  151. inversePrimary: LightModeColors.lightInversePrimary,
  152. ),
  153. brightness: Brightness.light,
  154. scaffoldBackgroundColor: LightModeColors.lightBackground,
  155. appBarTheme: const AppBarTheme(
  156. backgroundColor: Colors.transparent,
  157. foregroundColor: LightModeColors.lightOnSurface,
  158. elevation: 0,
  159. scrolledUnderElevation: 0,
  160. ),
  161. cardTheme: CardThemeData(
  162. elevation: 0,
  163. shape: RoundedRectangleBorder(
  164. borderRadius: BorderRadius.circular(12),
  165. side: BorderSide(color: LightModeColors.lightOutline.withValues(alpha: 0.20), width: 1),
  166. ),
  167. ),
  168. filledButtonTheme: FilledButtonThemeData(
  169. style: ButtonStyle(
  170. shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))),
  171. padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)),
  172. textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)),
  173. ),
  174. ),
  175. outlinedButtonTheme: OutlinedButtonThemeData(
  176. style: ButtonStyle(
  177. shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))),
  178. padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)),
  179. textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)),
  180. ),
  181. ),
  182. textTheme: _buildTextTheme(Brightness.light),
  183. );
  184.  
  185. ThemeData get darkTheme => ThemeData(
  186. useMaterial3: true,
  187. splashFactory: NoSplash.splashFactory,
  188. highlightColor: Colors.transparent,
  189. splashColor: Colors.transparent,
  190. colorScheme: const ColorScheme.dark(
  191. primary: DarkModeColors.darkPrimary,
  192. onPrimary: DarkModeColors.darkOnPrimary,
  193. primaryContainer: DarkModeColors.darkPrimaryContainer,
  194. onPrimaryContainer: DarkModeColors.darkOnPrimaryContainer,
  195. secondary: DarkModeColors.darkSecondary,
  196. onSecondary: DarkModeColors.darkOnSecondary,
  197. tertiary: DarkModeColors.darkTertiary,
  198. onTertiary: DarkModeColors.darkOnTertiary,
  199. error: DarkModeColors.darkError,
  200. onError: DarkModeColors.darkOnError,
  201. errorContainer: DarkModeColors.darkErrorContainer,
  202. onErrorContainer: DarkModeColors.darkOnErrorContainer,
  203. surface: DarkModeColors.darkSurface,
  204. onSurface: DarkModeColors.darkOnSurface,
  205. surfaceContainerHighest: DarkModeColors.darkSurfaceVariant,
  206. onSurfaceVariant: DarkModeColors.darkOnSurfaceVariant,
  207. outline: DarkModeColors.darkOutline,
  208. shadow: DarkModeColors.darkShadow,
  209. inversePrimary: DarkModeColors.darkInversePrimary,
  210. ),
  211. brightness: Brightness.dark,
  212. scaffoldBackgroundColor: DarkModeColors.darkSurface,
  213. appBarTheme: const AppBarTheme(
  214. backgroundColor: Colors.transparent,
  215. foregroundColor: DarkModeColors.darkOnSurface,
  216. elevation: 0,
  217. scrolledUnderElevation: 0,
  218. ),
  219. cardTheme: CardThemeData(
  220. elevation: 0,
  221. shape: RoundedRectangleBorder(
  222. borderRadius: BorderRadius.circular(12),
  223. side: BorderSide(color: DarkModeColors.darkOutline.withValues(alpha: 0.20), width: 1),
  224. ),
  225. ),
  226. filledButtonTheme: FilledButtonThemeData(
  227. style: ButtonStyle(
  228. shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))),
  229. padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)),
  230. textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)),
  231. ),
  232. ),
  233. outlinedButtonTheme: OutlinedButtonThemeData(
  234. style: ButtonStyle(
  235. shape: WidgetStatePropertyAll(RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))),
  236. padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)),
  237. textStyle: WidgetStatePropertyAll(GoogleFonts.inter(fontWeight: FontWeight.w700)),
  238. ),
  239. ),
  240. textTheme: _buildTextTheme(Brightness.dark),
  241. );
  242.  
  243. TextTheme _buildTextTheme(Brightness brightness) {
  244. // Keep Inter for a modern look; Arabic glyph support relies on system fallback.
  245. return TextTheme(
  246. displayLarge: GoogleFonts.inter(fontSize: FontSizes.displayLarge, fontWeight: FontWeight.w400, letterSpacing: -0.25),
  247. displayMedium: GoogleFonts.inter(fontSize: FontSizes.displayMedium, fontWeight: FontWeight.w400),
  248. displaySmall: GoogleFonts.inter(fontSize: FontSizes.displaySmall, fontWeight: FontWeight.w400),
  249. headlineLarge: GoogleFonts.inter(fontSize: FontSizes.headlineLarge, fontWeight: FontWeight.w600, letterSpacing: -0.5),
  250. headlineMedium: GoogleFonts.inter(fontSize: FontSizes.headlineMedium, fontWeight: FontWeight.w600),
  251. headlineSmall: GoogleFonts.inter(fontSize: FontSizes.headlineSmall, fontWeight: FontWeight.w600),
  252. titleLarge: GoogleFonts.inter(fontSize: FontSizes.titleLarge, fontWeight: FontWeight.w600),
  253. titleMedium: GoogleFonts.inter(fontSize: FontSizes.titleMedium, fontWeight: FontWeight.w500),
  254. titleSmall: GoogleFonts.inter(fontSize: FontSizes.titleSmall, fontWeight: FontWeight.w500),
  255. labelLarge: GoogleFonts.inter(fontSize: FontSizes.labelLarge, fontWeight: FontWeight.w500, letterSpacing: 0.1),
  256. labelMedium: GoogleFonts.inter(fontSize: FontSizes.labelMedium, fontWeight: FontWeight.w500, letterSpacing: 0.5),
  257. labelSmall: GoogleFonts.inter(fontSize: FontSizes.labelSmall, fontWeight: FontWeight.w500, letterSpacing: 0.5),
  258. bodyLarge: GoogleFonts.inter(fontSize: FontSizes.bodyLarge, fontWeight: FontWeight.w400, letterSpacing: 0.15),
  259. bodyMedium: GoogleFonts.inter(fontSize: FontSizes.bodyMedium, fontWeight: FontWeight.w400, letterSpacing: 0.25),
  260. bodySmall: GoogleFonts.inter(fontSize: FontSizes.bodySmall, fontWeight: FontWeight.w400, letterSpacing: 0.4),
  261. );
  262. }
  263. Code 2 :
  264. import 'package:flutter/material.dart';
  265. import 'package:banck/theme.dart';
  266.  
  267. class HomePage extends StatefulWidget {
  268. const HomePage({super.key});
  269.  
  270. @override
  271. State<HomePage> createState() => _HomePageState();
  272. }
  273.  
  274. class _HomePageState extends State<HomePage> {
  275. bool _hideBalance = true;
  276.  
  277. @override
  278. Widget build(BuildContext context) {
  279. final scheme = Theme.of(context).colorScheme;
  280. return Directionality(
  281. textDirection: TextDirection.rtl,
  282. child: SafeArea(
  283. child: CustomScrollView(
  284. slivers: [
  285. SliverPadding(
  286. padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.sm, AppSpacing.md, 0),
  287. sliver: SliverToBoxAdapter(
  288. child: Row(
  289. children: [
  290. _TopIconButton(icon: Icons.menu_rounded, label: 'القائمة', onPressed: () => _showQuickSheet(context)),
  291. const Spacer(),
  292. Column(
  293. crossAxisAlignment: CrossAxisAlignment.end,
  294. children: [
  295. Text('mebanck', style: Theme.of(context).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w800, color: scheme.tertiary)),
  296. const SizedBox(height: 2),
  297. Text('محفظة بسيطة', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2)),
  298. ],
  299. ),
  300. const SizedBox(width: AppSpacing.md),
  301. _TopIconButton(icon: Icons.notifications_none_rounded, label: 'إشعارات', onPressed: () => _showSnack(context, 'لا توجد إشعارات الآن')),
  302. ],
  303. ),
  304. ),
  305. ),
  306. SliverPadding(
  307. padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.lg, AppSpacing.md, 0),
  308. sliver: SliverToBoxAdapter(
  309. child: TweenAnimationBuilder<double>(
  310. duration: const Duration(milliseconds: 520),
  311. curve: Curves.easeOutCubic,
  312. tween: Tween(begin: 0, end: 1),
  313. builder: (context, t, child) => Opacity(opacity: t, child: Transform.translate(offset: Offset(0, (1 - t) * 10), child: child)),
  314. child: BalancePanel(
  315. isHidden: _hideBalance,
  316. onToggle: () => setState(() => _hideBalance = !_hideBalance),
  317. balanceText: _hideBalance ? '•••••' : '12,450 MRU',
  318. subtitle: 'الرصيد المتاح',
  319. ),
  320. ),
  321. ),
  322. ),
  323. const SliverToBoxAdapter(child: SizedBox(height: AppSpacing.lg)),
  324. SliverPadding(
  325. padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
  326. sliver: SliverToBoxAdapter(
  327. child: Row(
  328. children: [
  329. Expanded(
  330. child: OutlinedButton.icon(
  331. onPressed: () => _showSnack(context, 'إرسال (قريباً)'),
  332. icon: Icon(Icons.call_made_rounded, color: scheme.primary),
  333. label: Text('إرسال', style: TextStyle(color: scheme.primary)),
  334. ),
  335. ),
  336. const SizedBox(width: AppSpacing.md),
  337. Expanded(
  338. child: FilledButton.icon(
  339. onPressed: () => _showSnack(context, 'استلام (قريباً)'),
  340. icon: Icon(Icons.call_received_rounded, color: scheme.onPrimary),
  341. label: Text('استلام', style: TextStyle(color: scheme.onPrimary)),
  342. ),
  343. ),
  344. ],
  345. ),
  346. ),
  347. ),
  348. const SliverToBoxAdapter(child: SizedBox(height: AppSpacing.lg)),
  349. SliverPadding(
  350. padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
  351. sliver: SliverToBoxAdapter(
  352. child: ServicesTwoColumns(
  353. onTap: (id) {
  354. switch (id) {
  355. case 'pay':
  356. _showSnack(context, 'الدفع (قريباً)');
  357. return;
  358. case 'transfer':
  359. _showSnack(context, 'التحويل (قريباً)');
  360. return;
  361. case 'topup':
  362. _showSnack(context, 'شحن الهاتف (قريباً)');
  363. return;
  364. case 'cashout':
  365. _showSnack(context, 'سحب (قريباً)');
  366. return;
  367. case 'bills':
  368. _showSnack(context, 'الفواتير (قريباً)');
  369. return;
  370. case 'more':
  371. _showMoreServices(context);
  372. return;
  373. }
  374. },
  375. ),
  376. ),
  377. ),
  378. SliverToBoxAdapter(
  379. child: Padding(
  380. padding: const EdgeInsets.fromLTRB(AppSpacing.md, AppSpacing.lg, AppSpacing.md, AppSpacing.xxl),
  381. child: Container(
  382. decoration: BoxDecoration(
  383. color: scheme.surface,
  384. borderRadius: BorderRadius.circular(AppRadius.lg),
  385. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  386. ),
  387. padding: const EdgeInsets.all(AppSpacing.md),
  388. child: Row(
  389. children: [
  390. Container(
  391. width: 42,
  392. height: 42,
  393. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)),
  394. child: Icon(Icons.shield_outlined, color: scheme.onPrimaryContainer, size: 22),
  395. ),
  396. const SizedBox(width: AppSpacing.md),
  397. Expanded(
  398. child: Column(
  399. crossAxisAlignment: CrossAxisAlignment.start,
  400. children: [
  401. Text('نصيحة', style: Theme.of(context).textTheme.titleMedium),
  402. const SizedBox(height: 2),
  403. Text('لا تشارك رمزك السري، وفعّل القفل إن توفر.', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.4)),
  404. ],
  405. ),
  406. ),
  407. ],
  408. ),
  409. ),
  410. ),
  411. ),
  412. ],
  413. ),
  414. ),
  415. );
  416. }
  417.  
  418. void _showSnack(BuildContext context, String message) {
  419. ScaffoldMessenger.of(context).showSnackBar(
  420. SnackBar(content: Text(message, textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating, showCloseIcon: true),
  421. );
  422. }
  423.  
  424. void _showQuickSheet(BuildContext context) {
  425. final scheme = Theme.of(context).colorScheme;
  426. showModalBottomSheet<void>(
  427. context: context,
  428. showDragHandle: true,
  429. backgroundColor: scheme.surface,
  430. builder: (context) => Padding(
  431. padding: const EdgeInsets.fromLTRB(AppSpacing.lg, 0, AppSpacing.lg, AppSpacing.lg),
  432. child: Column(
  433. mainAxisSize: MainAxisSize.min,
  434. crossAxisAlignment: CrossAxisAlignment.stretch,
  435. children: [
  436. Text('إجراءات سريعة', style: Theme.of(context).textTheme.titleLarge, textDirection: TextDirection.rtl),
  437. const SizedBox(height: AppSpacing.md),
  438. Wrap(
  439. spacing: AppSpacing.sm,
  440. runSpacing: AppSpacing.sm,
  441. children: [
  442. _QuickChip(icon: Icons.qr_code_scanner_rounded, label: 'QR', onTap: () => Navigator.of(context).pop()),
  443. _QuickChip(icon: Icons.person_add_alt_1_rounded, label: 'مستفيد جديد', onTap: () => Navigator.of(context).pop()),
  444. _QuickChip(icon: Icons.support_agent_rounded, label: 'مساعدة', onTap: () => Navigator.of(context).pop()),
  445. ],
  446. ),
  447. ],
  448. ),
  449. ),
  450. );
  451. }
  452.  
  453. void _showMoreServices(BuildContext context) {
  454. final scheme = Theme.of(context).colorScheme;
  455. showModalBottomSheet<void>(
  456. context: context,
  457. showDragHandle: true,
  458. backgroundColor: scheme.surface,
  459. builder: (context) => Padding(
  460. padding: const EdgeInsets.fromLTRB(AppSpacing.lg, 0, AppSpacing.lg, AppSpacing.lg),
  461. child: Column(
  462. mainAxisSize: MainAxisSize.min,
  463. crossAxisAlignment: CrossAxisAlignment.stretch,
  464. children: [
  465. Text('خدمات أكثر', style: Theme.of(context).textTheme.titleLarge, textDirection: TextDirection.rtl),
  466. const SizedBox(height: AppSpacing.md),
  467. _SheetRow(icon: Icons.storefront_outlined, title: 'دفع للتجار', onTap: () => Navigator.of(context).pop()),
  468. _SheetRow(icon: Icons.school_outlined, title: 'رسوم المدرسة', onTap: () => Navigator.of(context).pop()),
  469. _SheetRow(icon: Icons.directions_bus_outlined, title: 'مواصلات', onTap: () => Navigator.of(context).pop()),
  470. ],
  471. ),
  472. ),
  473. );
  474. }
  475. }
  476.  
  477. class BalancePanel extends StatelessWidget {
  478. const BalancePanel({super.key, required this.isHidden, required this.onToggle, required this.balanceText, required this.subtitle});
  479.  
  480. final bool isHidden;
  481. final VoidCallback onToggle;
  482. final String balanceText;
  483. final String subtitle;
  484.  
  485. @override
  486. Widget build(BuildContext context) {
  487. final scheme = Theme.of(context).colorScheme;
  488. final gradient = LinearGradient(
  489. begin: Alignment.topRight,
  490. end: Alignment.bottomLeft,
  491. colors: [scheme.primary, scheme.primary.withValues(alpha: 0.86)],
  492. );
  493.  
  494. return Container(
  495. decoration: BoxDecoration(gradient: gradient, borderRadius: BorderRadius.circular(AppRadius.xl)),
  496. padding: const EdgeInsets.all(AppSpacing.lg),
  497. child: Row(
  498. children: [
  499. Expanded(
  500. child: Column(
  501. crossAxisAlignment: CrossAxisAlignment.start,
  502. children: [
  503. Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onPrimary.withValues(alpha: 0.90), height: 1.2)),
  504. const SizedBox(height: 8),
  505. Text(balanceText, style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: scheme.onPrimary, fontWeight: FontWeight.w900)),
  506. const SizedBox(height: 12),
  507. Row(
  508. children: [
  509. _BalanceToggle(isHidden: isHidden, onPressed: onToggle),
  510. const SizedBox(width: 10),
  511. Text('إخفاء/إظهار', style: Theme.of(context).textTheme.labelMedium?.copyWith(color: scheme.onPrimary.withValues(alpha: 0.92))),
  512. ],
  513. ),
  514. ],
  515. ),
  516. ),
  517. const SizedBox(width: AppSpacing.md),
  518. Container(
  519. width: 64,
  520. height: 64,
  521. decoration: BoxDecoration(color: scheme.onPrimary.withValues(alpha: 0.14), borderRadius: BorderRadius.circular(18)),
  522. child: Icon(Icons.account_balance_wallet_rounded, color: scheme.onPrimary, size: 30),
  523. ),
  524. ],
  525. ),
  526. );
  527. }
  528. }
  529.  
  530. class _BalanceToggle extends StatefulWidget {
  531. const _BalanceToggle({required this.isHidden, required this.onPressed});
  532.  
  533. final bool isHidden;
  534. final VoidCallback onPressed;
  535.  
  536. @override
  537. State<_BalanceToggle> createState() => _BalanceToggleState();
  538. }
  539.  
  540. class _BalanceToggleState extends State<_BalanceToggle> {
  541. bool _pressed = false;
  542.  
  543. @override
  544. Widget build(BuildContext context) {
  545. final scheme = Theme.of(context).colorScheme;
  546. return GestureDetector(
  547. onTapDown: (_) => setState(() => _pressed = true),
  548. onTapCancel: () => setState(() => _pressed = false),
  549. onTapUp: (_) => setState(() => _pressed = false),
  550. onTap: widget.onPressed,
  551. child: AnimatedContainer(
  552. duration: const Duration(milliseconds: 160),
  553. curve: Curves.easeOut,
  554. width: 62,
  555. height: 34,
  556. padding: const EdgeInsets.all(4),
  557. decoration: BoxDecoration(
  558. color: scheme.onPrimary.withValues(alpha: 0.18),
  559. borderRadius: BorderRadius.circular(40),
  560. border: Border.all(color: scheme.onPrimary.withValues(alpha: _pressed ? 0.45 : 0.25)),
  561. ),
  562. child: Align(
  563. alignment: widget.isHidden ? Alignment.centerLeft : Alignment.centerRight,
  564. child: Container(
  565. width: 26,
  566. height: 26,
  567. decoration: BoxDecoration(color: scheme.onPrimary, borderRadius: BorderRadius.circular(26)),
  568. child: Icon(widget.isHidden ? Icons.visibility_off_rounded : Icons.visibility_rounded, size: 16, color: scheme.primary),
  569. ),
  570. ),
  571. ),
  572. );
  573. }
  574. }
  575.  
  576. class ServicesTwoColumns extends StatelessWidget {
  577. const ServicesTwoColumns({super.key, required this.onTap});
  578.  
  579. final void Function(String id) onTap;
  580.  
  581. @override
  582. Widget build(BuildContext context) {
  583. return Row(
  584. children: [
  585. Expanded(
  586. child: Column(
  587. children: [
  588. ServiceFrame(id: 'pay', icon: Icons.payments_outlined, title: 'الدفع', subtitle: 'للتجار', onTap: onTap),
  589. const SizedBox(height: AppSpacing.md),
  590. ServiceFrame(id: 'topup', icon: Icons.phone_iphone_rounded, title: 'شحن', subtitle: 'الهاتف', onTap: onTap),
  591. const SizedBox(height: AppSpacing.md),
  592. ServiceFrame(id: 'bills', icon: Icons.receipt_long_outlined, title: 'فواتير', subtitle: 'كهرباء/ماء', onTap: onTap),
  593. ],
  594. ),
  595. ),
  596. const SizedBox(width: AppSpacing.md),
  597. Expanded(
  598. child: Column(
  599. children: [
  600. ServiceFrame(id: 'transfer', icon: Icons.swap_horiz_rounded, title: 'تحويل', subtitle: 'إرسال/استلام', onTap: onTap),
  601. const SizedBox(height: AppSpacing.md),
  602. ServiceFrame(id: 'cashout', icon: Icons.local_atm_outlined, title: 'سحب', subtitle: 'نقاط خدمة', onTap: onTap),
  603. const SizedBox(height: AppSpacing.md),
  604. ServiceFrame(id: 'more', icon: Icons.grid_view_rounded, title: 'المزيد', subtitle: 'خدمات', onTap: onTap),
  605. ],
  606. ),
  607. ),
  608. ],
  609. );
  610. }
  611. }
  612.  
  613. class ServiceFrame extends StatefulWidget {
  614. const ServiceFrame({super.key, required this.id, required this.icon, required this.title, required this.subtitle, required this.onTap});
  615.  
  616. final String id;
  617. final IconData icon;
  618. final String title;
  619. final String subtitle;
  620. final void Function(String id) onTap;
  621.  
  622. @override
  623. State<ServiceFrame> createState() => _ServiceFrameState();
  624. }
  625.  
  626. class _ServiceFrameState extends State<ServiceFrame> {
  627. bool _pressed = false;
  628.  
  629. @override
  630. Widget build(BuildContext context) {
  631. final scheme = Theme.of(context).colorScheme;
  632. return GestureDetector(
  633. onTap: () => widget.onTap(widget.id),
  634. onTapDown: (_) => setState(() => _pressed = true),
  635. onTapCancel: () => setState(() => _pressed = false),
  636. onTapUp: (_) => setState(() => _pressed = false),
  637. child: AnimatedScale(
  638. duration: const Duration(milliseconds: 130),
  639. curve: Curves.easeOut,
  640. scale: _pressed ? 0.985 : 1,
  641. child: AnimatedContainer(
  642. duration: const Duration(milliseconds: 170),
  643. curve: Curves.easeOut,
  644. padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md, vertical: 14),
  645. decoration: BoxDecoration(
  646. color: scheme.surface,
  647. borderRadius: BorderRadius.circular(AppRadius.md),
  648. border: Border.all(color: scheme.outline.withValues(alpha: _pressed ? 0.22 : 0.14)),
  649. ),
  650. child: Row(
  651. children: [
  652. Container(
  653. width: 40,
  654. height: 40,
  655. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(12)),
  656. child: Icon(widget.icon, color: scheme.onPrimaryContainer, size: 20),
  657. ),
  658. const SizedBox(width: AppSpacing.md),
  659. Expanded(
  660. child: Column(
  661. crossAxisAlignment: CrossAxisAlignment.start,
  662. children: [
  663. Text(widget.title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)),
  664. const SizedBox(height: 2),
  665. Text(widget.subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2), maxLines: 1, overflow: TextOverflow.ellipsis),
  666. ],
  667. ),
  668. ),
  669. Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant),
  670. ],
  671. ),
  672. ),
  673. ),
  674. );
  675. }
  676. }
  677.  
  678. class _TopIconButton extends StatelessWidget {
  679. const _TopIconButton({required this.icon, required this.label, required this.onPressed});
  680.  
  681. final IconData icon;
  682. final String label;
  683. final VoidCallback onPressed;
  684.  
  685. @override
  686. Widget build(BuildContext context) {
  687. final scheme = Theme.of(context).colorScheme;
  688. return Semantics(
  689. button: true,
  690. label: label,
  691. child: GestureDetector(
  692. onTap: onPressed,
  693. child: Container(
  694. width: 46,
  695. height: 46,
  696. decoration: BoxDecoration(
  697. color: scheme.surface,
  698. borderRadius: BorderRadius.circular(16),
  699. border: Border.all(color: scheme.outline.withValues(alpha: 0.12)),
  700. ),
  701. child: Icon(icon, color: scheme.onSurface),
  702. ),
  703. ),
  704. );
  705. }
  706. }
  707.  
  708. class _QuickChip extends StatelessWidget {
  709. const _QuickChip({required this.icon, required this.label, required this.onTap});
  710.  
  711. final IconData icon;
  712. final String label;
  713. final VoidCallback onTap;
  714.  
  715. @override
  716. Widget build(BuildContext context) {
  717. final scheme = Theme.of(context).colorScheme;
  718. return GestureDetector(
  719. onTap: onTap,
  720. child: Container(
  721. padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
  722. decoration: BoxDecoration(
  723. color: scheme.surface,
  724. borderRadius: BorderRadius.circular(999),
  725. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  726. ),
  727. child: Row(
  728. mainAxisSize: MainAxisSize.min,
  729. children: [
  730. Icon(icon, size: 18, color: scheme.onSurface),
  731. const SizedBox(width: 8),
  732. Text(label, style: Theme.of(context).textTheme.labelLarge),
  733. ],
  734. ),
  735. ),
  736. );
  737. }
  738. }
  739.  
  740. class _SheetRow extends StatelessWidget {
  741. const _SheetRow({required this.icon, required this.title, required this.onTap});
  742.  
  743. final IconData icon;
  744. final String title;
  745. final VoidCallback onTap;
  746.  
  747. @override
  748. Widget build(BuildContext context) {
  749. final scheme = Theme.of(context).colorScheme;
  750. return Padding(
  751. padding: const EdgeInsets.only(bottom: AppSpacing.sm),
  752. child: GestureDetector(
  753. onTap: onTap,
  754. child: Container(
  755. decoration: BoxDecoration(
  756. color: scheme.surface,
  757. borderRadius: BorderRadius.circular(AppRadius.xl),
  758. border: Border.all(color: scheme.outline.withValues(alpha: 0.12)),
  759. ),
  760. padding: const EdgeInsets.all(AppSpacing.md),
  761. child: Row(
  762. children: [
  763. Container(
  764. width: 42,
  765. height: 42,
  766. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)),
  767. child: Icon(icon, color: scheme.onPrimaryContainer),
  768. ),
  769. const SizedBox(width: AppSpacing.md),
  770. Expanded(child: Text(title, style: Theme.of(context).textTheme.titleMedium, textDirection: TextDirection.rtl)),
  771. Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant),
  772. ],
  773. ),
  774. ),
  775. ),
  776. );
  777. }
  778. }
  779. Code 3 :
  780. import 'package:flutter/material.dart';
  781. import 'package:banck/theme.dart';
  782.  
  783. class HistoryPage extends StatelessWidget {
  784. const HistoryPage({super.key});
  785.  
  786. @override
  787. Widget build(BuildContext context) {
  788. final scheme = Theme.of(context).colorScheme;
  789. return Directionality(
  790. textDirection: TextDirection.rtl,
  791. child: SafeArea(
  792. child: Padding(
  793. padding: const EdgeInsets.all(AppSpacing.md),
  794. child: Column(
  795. crossAxisAlignment: CrossAxisAlignment.start,
  796. children: [
  797. Text('السجل', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)),
  798. const SizedBox(height: AppSpacing.sm),
  799. Text('آخر العمليات (نموذج تجريبي).', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)),
  800. const SizedBox(height: AppSpacing.lg),
  801. Expanded(
  802. child: ListView.separated(
  803. itemCount: 8,
  804. separatorBuilder: (_, __) => const SizedBox(height: AppSpacing.sm),
  805. itemBuilder: (context, index) {
  806. final isIn = index.isEven;
  807. return _TxnRow(
  808. icon: isIn ? Icons.call_received_rounded : Icons.call_made_rounded,
  809. title: isIn ? 'استلام' : 'إرسال',
  810. subtitle: 'اليوم • 12:${30 + index}',
  811. amount: isIn ? '+ 1,200' : '- 250',
  812. amountColor: isIn ? scheme.secondary : scheme.onSurface,
  813. );
  814. },
  815. ),
  816. ),
  817. ],
  818. ),
  819. ),
  820. ),
  821. );
  822. }
  823. }
  824.  
  825. class _TxnRow extends StatelessWidget {
  826. const _TxnRow({required this.icon, required this.title, required this.subtitle, required this.amount, required this.amountColor});
  827.  
  828. final IconData icon;
  829. final String title;
  830. final String subtitle;
  831. final String amount;
  832. final Color amountColor;
  833.  
  834. @override
  835. Widget build(BuildContext context) {
  836. final scheme = Theme.of(context).colorScheme;
  837. return Container(
  838. padding: const EdgeInsets.all(AppSpacing.md),
  839. decoration: BoxDecoration(
  840. color: scheme.surface,
  841. borderRadius: BorderRadius.circular(AppRadius.lg),
  842. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  843. ),
  844. child: Row(
  845. children: [
  846. Container(
  847. width: 42,
  848. height: 42,
  849. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)),
  850. child: Icon(icon, color: scheme.onPrimaryContainer, size: 20),
  851. ),
  852. const SizedBox(width: AppSpacing.md),
  853. Expanded(
  854. child: Column(
  855. crossAxisAlignment: CrossAxisAlignment.start,
  856. children: [
  857. Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)),
  858. const SizedBox(height: 2),
  859. Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)),
  860. ],
  861. ),
  862. ),
  863. Text(amount, style: Theme.of(context).textTheme.titleMedium?.copyWith(color: amountColor, fontWeight: FontWeight.w900)),
  864. ],
  865. ),
  866. );
  867. }
  868. }
  869. Code 4:
  870. import 'package:flutter/material.dart';
  871. import 'package:banck/theme.dart';
  872.  
  873. class QrPage extends StatelessWidget {
  874. const QrPage({super.key});
  875.  
  876. @override
  877. Widget build(BuildContext context) {
  878. final scheme = Theme.of(context).colorScheme;
  879. return Directionality(
  880. textDirection: TextDirection.rtl,
  881. child: SafeArea(
  882. child: Padding(
  883. padding: const EdgeInsets.all(AppSpacing.md),
  884. child: Column(
  885. crossAxisAlignment: CrossAxisAlignment.stretch,
  886. children: [
  887. Text('QR', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)),
  888. const SizedBox(height: AppSpacing.sm),
  889. Text('اعرض رمزك ليستلم الآخرون منك، أو امسح لاحقاً عند إضافة الكاميرا.', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)),
  890. const SizedBox(height: AppSpacing.lg),
  891. Expanded(
  892. child: Container(
  893. decoration: BoxDecoration(
  894. color: scheme.surface,
  895. borderRadius: BorderRadius.circular(AppRadius.xl),
  896. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  897. ),
  898. child: Center(
  899. child: Container(
  900. width: 230,
  901. height: 230,
  902. decoration: BoxDecoration(
  903. color: scheme.primaryContainer,
  904. borderRadius: BorderRadius.circular(22),
  905. ),
  906. child: Stack(
  907. children: [
  908. Center(child: Icon(Icons.qr_code_2_rounded, size: 130, color: scheme.onPrimaryContainer)),
  909. Positioned(
  910. right: 14,
  911. top: 14,
  912. child: Container(
  913. padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
  914. decoration: BoxDecoration(
  915. color: scheme.surface,
  916. borderRadius: BorderRadius.circular(999),
  917. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  918. ),
  919. child: Row(
  920. mainAxisSize: MainAxisSize.min,
  921. children: [
  922. Icon(Icons.verified_rounded, size: 16, color: scheme.primary),
  923. const SizedBox(width: 6),
  924. Text('mebanck', style: Theme.of(context).textTheme.labelMedium?.copyWith(fontWeight: FontWeight.w800)),
  925. ],
  926. ),
  927. ),
  928. ),
  929. ],
  930. ),
  931. ),
  932. ),
  933. ),
  934. ),
  935. const SizedBox(height: AppSpacing.md),
  936. FilledButton.icon(
  937. onPressed: () => ScaffoldMessenger.of(context).showSnackBar(
  938. const SnackBar(content: Text('سيتم إضافة المسح الحقيقي لاحقاً', textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating),
  939. ),
  940. icon: Icon(Icons.qr_code_scanner_rounded, color: scheme.onPrimary),
  941. label: Text('مسح (قريباً)', style: TextStyle(color: scheme.onPrimary)),
  942. ),
  943. ],
  944. ),
  945. ),
  946. ),
  947. );
  948. }
  949. }
  950. Code 5 import 'package:flutter/material.dart';
  951. import 'package:banck/theme.dart';
  952.  
  953. class BankPage extends StatelessWidget {
  954. const BankPage({super.key});
  955.  
  956. @override
  957. Widget build(BuildContext context) {
  958. final scheme = Theme.of(context).colorScheme;
  959. return Directionality(
  960. textDirection: TextDirection.rtl,
  961. child: SafeArea(
  962. child: Padding(
  963. padding: const EdgeInsets.all(AppSpacing.md),
  964. child: Column(
  965. crossAxisAlignment: CrossAxisAlignment.start,
  966. children: [
  967. Text('الحساب', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)),
  968. const SizedBox(height: AppSpacing.sm),
  969. Text('معلومات مختصرة للحساب (واجهة قابلة للتطوير).', style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: scheme.onSurfaceVariant, height: 1.5)),
  970. const SizedBox(height: AppSpacing.lg),
  971. _InfoCard(icon: Icons.account_balance_wallet_rounded, title: 'محفظة mebanck', subtitle: 'MRU • حساب شخصي', trailing: '49055137'),
  972. const SizedBox(height: AppSpacing.sm),
  973. _InfoCard(icon: Icons.location_on_outlined, title: 'المدينة', subtitle: 'نواكشوط', trailing: 'MR'),
  974. ],
  975. ),
  976. ),
  977. ),
  978. );
  979. }
  980. }
  981.  
  982. class _InfoCard extends StatelessWidget {
  983. const _InfoCard({required this.icon, required this.title, required this.subtitle, required this.trailing});
  984.  
  985. final IconData icon;
  986. final String title;
  987. final String subtitle;
  988. final String trailing;
  989.  
  990. @override
  991. Widget build(BuildContext context) {
  992. final scheme = Theme.of(context).colorScheme;
  993. return Container(
  994. padding: const EdgeInsets.all(AppSpacing.md),
  995. decoration: BoxDecoration(
  996. color: scheme.surface,
  997. borderRadius: BorderRadius.circular(AppRadius.lg),
  998. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  999. ),
  1000. child: Row(
  1001. children: [
  1002. Container(
  1003. width: 42,
  1004. height: 42,
  1005. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)),
  1006. child: Icon(icon, color: scheme.onPrimaryContainer, size: 20),
  1007. ),
  1008. const SizedBox(width: AppSpacing.md),
  1009. Expanded(
  1010. child: Column(
  1011. crossAxisAlignment: CrossAxisAlignment.start,
  1012. children: [
  1013. Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w800)),
  1014. const SizedBox(height: 2),
  1015. Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)),
  1016. ],
  1017. ),
  1018. ),
  1019. Text(trailing, style: Theme.of(context).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)),
  1020. ],
  1021. ),
  1022. );
  1023. }
  1024. }
  1025.  
  1026. Code 6:import 'package:flutter/material.dart';
  1027. import 'package:banck/theme.dart';
  1028.  
  1029. class ProfilePage extends StatelessWidget {
  1030. const ProfilePage({super.key});
  1031.  
  1032. @override
  1033. Widget build(BuildContext context) {
  1034. final scheme = Theme.of(context).colorScheme;
  1035. return Directionality(
  1036. textDirection: TextDirection.rtl,
  1037. child: SafeArea(
  1038. child: Padding(
  1039. padding: const EdgeInsets.all(AppSpacing.md),
  1040. child: Column(
  1041. crossAxisAlignment: CrossAxisAlignment.start,
  1042. children: [
  1043. Text('حسابي', style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w900, color: scheme.tertiary)),
  1044. const SizedBox(height: AppSpacing.lg),
  1045. Container(
  1046. padding: const EdgeInsets.all(AppSpacing.lg),
  1047. decoration: BoxDecoration(
  1048. color: scheme.surface,
  1049. borderRadius: BorderRadius.circular(AppRadius.xl),
  1050. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  1051. ),
  1052. child: Row(
  1053. children: [
  1054. CircleAvatar(radius: 26, backgroundColor: scheme.primaryContainer, child: Icon(Icons.person_rounded, color: scheme.onPrimaryContainer)),
  1055. const SizedBox(width: AppSpacing.md),
  1056. Expanded(
  1057. child: Column(
  1058. crossAxisAlignment: CrossAxisAlignment.start,
  1059. children: [
  1060. Text('مستخدم', style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w900)),
  1061. const SizedBox(height: 2),
  1062. Text('بدون تسجيل دخول', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant)),
  1063. ],
  1064. ),
  1065. ),
  1066. Container(
  1067. padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
  1068. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(999)),
  1069. child: Text('MRU', style: Theme.of(context).textTheme.labelMedium?.copyWith(color: scheme.onPrimaryContainer, fontWeight: FontWeight.w900)),
  1070. ),
  1071. ],
  1072. ),
  1073. ),
  1074. const SizedBox(height: AppSpacing.lg),
  1075. _SettingTile(icon: Icons.security_rounded, title: 'الأمان', subtitle: 'رمز وقفل', onTap: () => _snack(context, 'الأمان (قريباً)')),
  1076. _SettingTile(icon: Icons.language_rounded, title: 'اللغة', subtitle: 'العربية / الفرنسية', onTap: () => _snack(context, 'تغيير اللغة (قريباً)')),
  1077. _SettingTile(icon: Icons.support_agent_rounded, title: 'مساعدة', subtitle: 'الدعم', onTap: () => _snack(context, 'الدعم (قريباً)')),
  1078. ],
  1079. ),
  1080. ),
  1081. ),
  1082. );
  1083. }
  1084.  
  1085. void _snack(BuildContext context, String message) => ScaffoldMessenger.of(context).showSnackBar(
  1086. SnackBar(content: Text(message, textDirection: TextDirection.rtl), behavior: SnackBarBehavior.floating),
  1087. );
  1088. }
  1089.  
  1090. class _SettingTile extends StatelessWidget {
  1091. const _SettingTile({required this.icon, required this.title, required this.subtitle, required this.onTap});
  1092.  
  1093. final IconData icon;
  1094. final String title;
  1095. final String subtitle;
  1096. final VoidCallback onTap;
  1097.  
  1098. @override
  1099. Widget build(BuildContext context) {
  1100. final scheme = Theme.of(context).colorScheme;
  1101. return Padding(
  1102. padding: const EdgeInsets.only(bottom: AppSpacing.sm),
  1103. child: GestureDetector(
  1104. onTap: onTap,
  1105. child: Container(
  1106. padding: const EdgeInsets.all(AppSpacing.md),
  1107. decoration: BoxDecoration(
  1108. color: scheme.surface,
  1109. borderRadius: BorderRadius.circular(AppRadius.lg),
  1110. border: Border.all(color: scheme.outline.withValues(alpha: 0.14)),
  1111. ),
  1112. child: Row(
  1113. children: [
  1114. Container(
  1115. width: 44,
  1116. height: 44,
  1117. decoration: BoxDecoration(color: scheme.primaryContainer, borderRadius: BorderRadius.circular(14)),
  1118. child: Icon(icon, color: scheme.onPrimaryContainer),
  1119. ),
  1120. const SizedBox(width: AppSpacing.md),
  1121. Expanded(
  1122. child: Column(
  1123. crossAxisAlignment: CrossAxisAlignment.start,
  1124. children: [
  1125. Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w900)),
  1126. const SizedBox(height: 2),
  1127. Text(subtitle, style: Theme.of(context).textTheme.bodySmall?.copyWith(color: scheme.onSurfaceVariant, height: 1.2)),
  1128. ],
  1129. ),
  1130. ),
  1131. Icon(Icons.chevron_left_rounded, color: scheme.onSurfaceVariant),
  1132. ],
  1133. ),
  1134. ),
  1135. ),
  1136. );
  1137. }
  1138. }
  1139.  
  1140. Code 7 :
  1141. import 'package:flutter/material.dart';
  1142. import 'package:flutter_localizations/flutter_localizations.dart';
  1143.  
  1144. import 'package:banck/nav.dart';
  1145. import 'package:banck/theme.dart';
  1146.  
  1147. void main() {
  1148. runApp(const MyApp());
  1149. }
  1150.  
  1151. class MyApp extends StatelessWidget {
  1152. const MyApp({super.key});
  1153.  
  1154. @override
  1155. Widget build(BuildContext context) {
  1156. return MaterialApp.router(
  1157. title: 'mebanck',
  1158. debugShowCheckedModeBanner: false,
  1159. theme: lightTheme,
  1160. darkTheme: darkTheme,
  1161. themeMode: ThemeMode.system,
  1162. locale: const Locale('ar'),
  1163. supportedLocales: const [Locale('ar'), Locale('fr'), Locale('en')],
  1164. localizationsDelegates: const [
  1165. GlobalMaterialLocalizations.delegate,
  1166. GlobalWidgetsLocalizations.delegate,
  1167. GlobalCupertinoLocalizations.delegate,
  1168. ],
  1169. routerConfig: AppRouter.router,
  1170. );
  1171. }
  1172. }
RAW Paste Data Copied