main
dart 167 lines 6.19 KB
Raw
1 import 'package:hugeicons/hugeicons.dart';
2 import 'package:flutter/material.dart';
3 import 'package:flutter_localizations/flutter_localizations.dart';
4 import 'package:loading_animation_widget/loading_animation_widget.dart';
5 import '../core/theme/colors.dart';
6 import '../core/utils/locale_utils.dart';
7 import '../l10n/app_localizations.dart';
8 import 'bootstrap_state.dart';
9
10 class BootstrapScreen extends StatelessWidget {
11 final BootstrapState state;
12 final VoidCallback? onRetry;
13 final Locale? locale;
14
15 const BootstrapScreen({
16 super.key,
17 required this.state,
18 this.onRetry,
19 this.locale,
20 });
21
22 String _stageMessage(AppLocalizations l10n) {
23 switch (state.stage) {
24 case BootstrapStage.initializing:
25 return l10n.initializing;
26 case BootstrapStage.preparingApp:
27 return l10n.preparing_app;
28 case BootstrapStage.initializingServices:
29 return l10n.initializing_services;
30 case BootstrapStage.configuringServer:
31 return l10n.configuring_server;
32 case BootstrapStage.done:
33 return l10n.ready;
34 case BootstrapStage.error:
35 return l10n.startup_failed;
36 }
37 }
38
39 @override
40 Widget build(BuildContext context) {
41 final brightness =
42 WidgetsBinding.instance.platformDispatcher.platformBrightness;
43 final isDark = brightness == Brightness.dark;
44 final requestedLocale =
45 this.locale ?? WidgetsBinding.instance.platformDispatcher.locale;
46 final locale =
47 findSupportedLocale(
48 requestedLocale.toLanguageTag(),
49 AppLocalizations.supportedLocales,
50 ) ??
51 const Locale('en');
52
53 return Localizations(
54 locale: locale,
55 delegates: [
56 AppLocalizations.delegate,
57 GlobalMaterialLocalizations.delegate,
58 GlobalWidgetsLocalizations.delegate,
59 ],
60 child: Builder(
61 builder: (context) {
62 final l10n = AppLocalizations.of(context)!;
63 return Directionality(
64 textDirection: locale.languageCode.startsWith('ar')
65 ? TextDirection.rtl
66 : TextDirection.ltr,
67 child: Material(
68 color: isDark
69 ? AppColors.darkBackground
70 : AppColors.lightBackground,
71 child: SafeArea(
72 child: Center(
73 child: Padding(
74 padding: const EdgeInsets.symmetric(horizontal: 32),
75 child: Column(
76 mainAxisSize: MainAxisSize.min,
77 children: [
78 ClipRRect(
79 borderRadius: BorderRadius.circular(12),
80 child: Image.asset(
81 'assets/images/logo.webp',
82 width: 72,
83 height: 72,
84 ),
85 ),
86 const SizedBox(height: 24),
87 Text(
88 l10n.app_name,
89 style: TextStyle(
90 fontSize: 28,
91 fontWeight: FontWeight.bold,
92 color: isDark
93 ? AppColors.darkPrimaryText
94 : AppColors.lightPrimaryText,
95 letterSpacing: 1,
96 ),
97 ),
98 const SizedBox(height: 48),
99 if (state.stage != BootstrapStage.error) ...[
100 LoadingAnimationWidget.fourRotatingDots(
101 size: 32,
102 color: isDark
103 ? AppColors.darkPrimaryText
104 : AppColors.lightPrimaryText,
105 ),
106 const SizedBox(height: 24),
107 Text(
108 _stageMessage(l10n),
109 textAlign: TextAlign.center,
110 style: TextStyle(
111 fontSize: 14,
112 color: isDark
113 ? AppColors.darkMutedText
114 : AppColors.lightMutedText,
115 ),
116 ),
117 ] else ...[
118 HugeIcon(
119 icon: HugeIcons.strokeRoundedInformationCircle,
120 size: 40,
121 color: AppColors.error,
122 ),
123 const SizedBox(height: 16),
124 Text(
125 l10n.something_went_wrong,
126 style: TextStyle(
127 fontSize: 16,
128 fontWeight: FontWeight.w600,
129 color: isDark
130 ? AppColors.darkPrimaryText
131 : AppColors.lightPrimaryText,
132 ),
133 ),
134 const SizedBox(height: 8),
135 Text(
136 state.error?.toString() ?? l10n.unknown_error,
137 textAlign: TextAlign.center,
138 style: TextStyle(
139 fontSize: 13,
140 color: isDark
141 ? AppColors.darkMutedText
142 : AppColors.lightMutedText,
143 ),
144 ),
145 const SizedBox(height: 24),
146 if (onRetry != null)
147 ElevatedButton.icon(
148 onPressed: onRetry,
149 icon: const HugeIcon(
150 icon: HugeIcons.strokeRoundedRefresh,
151 size: 18,
152 ),
153 label: Text(l10n.retry),
154 ),
155 ],
156 ],
157 ),
158 ),
159 ),
160 ),
161 ),
162 );
163 },
164 ),
165 );
166 }
167 }