Update: 2026-07-30 02:27:45

This commit is contained in:
Hamza-Ayed
2026-07-30 02:27:45 +03:00
parent 5f62455113
commit ca4a7c2e70
56 changed files with 3391 additions and 709 deletions
@@ -17,8 +17,11 @@ class MainShellView extends StatefulWidget {
class _MainShellViewState extends State<MainShellView> {
final MainShellController _shellController = Get.find<MainShellController>();
// Must be find(), not put(): main.dart already registers the permanent
// instance. Re-putting it here swapped in a second, empty instance that other
// controllers were no longer holding, so progress updates went nowhere.
final UploadProgressService _progressService =
Get.put(UploadProgressService());
Get.find<UploadProgressService>();
// 5 pages: Home(0), Invoices(1), [Scanner FAB](2), Notifications(3), Settings(4)
final List<Widget> _pages = const [
@@ -179,13 +182,37 @@ class _MainShellViewState extends State<MainShellView> {
final status = _progressService.status.value;
final progress = _progressService.progress.value;
Color accentColor =
status == 'done' ? const Color(0xFF10B981) : const Color(0xFF0F4C81);
String statusText = status == 'uploading'
? 'جاري رفع الصور...'
: (status == 'processing'
? 'جاري استخراج البيانات...'
: 'اكتملت المعالجة ✓');
// Terminal states must look different from in-progress ones, otherwise a
// failed or partially failed batch is indistinguishable from a success.
final bool isTerminal =
status == 'done' || status == 'partial' || status == 'failed';
final Color accentColor = switch (status) {
'done' => const Color(0xFF10B981),
'partial' => const Color(0xFFF59E0B),
'failed' => const Color(0xFFEF4444),
_ => const Color(0xFF0F4C81),
};
final String statusText = switch (status) {
'uploading' => 'جاري رفع الصور...',
'processing' => 'جاري استخراج البيانات...',
'done' => 'اكتملت المعالجة ✓',
'partial' => 'اكتملت المعالجة مع أخطاء',
'failed' => 'فشلت العملية',
_ => 'جاري المعالجة...',
};
final IconData? terminalIcon = switch (status) {
'done' => Icons.check_circle,
'partial' => Icons.warning_amber_rounded,
'failed' => Icons.error_outline,
_ => null,
};
final String detailText = _progressService.errorMessage.value.isNotEmpty
? _progressService.errorMessage.value
: '${_progressService.companyName.value} • ${_progressService.currentImageIndex.value}/${_progressService.totalImages.value}';
return Card(
elevation: 8,
@@ -199,9 +226,8 @@ class _MainShellViewState extends State<MainShellView> {
children: [
Row(
children: [
status == 'done'
? const Icon(Icons.check_circle,
color: Color(0xFF10B981), size: 24)
terminalIcon != null
? Icon(terminalIcon, color: accentColor, size: 24)
: const SizedBox(
width: 24,
height: 24,
@@ -213,10 +239,14 @@ class _MainShellViewState extends State<MainShellView> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(statusText,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 13)),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 13,
color: status == 'failed' ? accentColor : null)),
Text(
'${_progressService.companyName.value} • ${_progressService.currentImageIndex.value}/${_progressService.totalImages.value}',
detailText,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 11,
color: isDark ? Colors.white38 : Colors.grey),
@@ -224,13 +254,23 @@ class _MainShellViewState extends State<MainShellView> {
],
),
),
Text(
'${(progress * 100).toInt()}%',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: accentColor),
),
if (isTerminal)
// A terminal card no longer moves on its own, so give the user
// a way to clear it instead of waiting out a timer.
IconButton(
icon: const Icon(Icons.close, size: 18),
color: isDark ? Colors.white38 : Colors.grey,
onPressed: _progressService.dismiss,
tooltip: 'إخفاء',
)
else
Text(
'${(progress * 100).toInt()}%',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: accentColor),
),
],
),
const SizedBox(height: 10),