Files
maps-saas/packages/tactical_app/lib/widgets/offline_package_dialog.dart
T

210 lines
8.0 KiB
Dart

import 'package:flutter/material.dart';
import '../services/offline_package_manager.dart';
class OfflinePackageDialog extends StatefulWidget {
final VoidCallback onPackageSynced;
const OfflinePackageDialog({super.key, required this.onPackageSynced});
@override
State<OfflinePackageDialog> createState() => _OfflinePackageDialogState();
}
class _OfflinePackageDialogState extends State<OfflinePackageDialog> {
bool _isDownloading = false;
OfflinePackageInfo? _info;
@override
void initState() {
super.initState();
_loadPackageInfo();
}
Future<void> _loadPackageInfo() async {
final info = await OfflinePackageManager.getPackageInfo();
if (mounted) setState(() => _info = info);
}
Future<void> _startSync({bool force = false}) async {
setState(() => _isDownloading = true);
final success = await OfflinePackageManager.downloadFullPackage(force: force);
if (mounted) {
setState(() => _isDownloading = false);
await _loadPackageInfo();
if (success) {
widget.onPackageSynced();
}
}
}
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: const Color(0xFF0F172A),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20), side: const BorderSide(color: Color(0xFF0071E3), width: 1.5)),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header
Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0x330071E3),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: const Color(0xFF0071E3)),
),
child: const Icon(Icons.download_for_offline, color: Color(0xFF38BDF8), size: 22),
),
const SizedBox(width: 12),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'حزمة بيانات الأردن التكتيكية',
style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold),
),
Text(
'Offline Sovereign Data Package v2.4',
style: TextStyle(color: Color(0xFF94A3B8), fontSize: 10.5),
),
],
),
),
IconButton(
icon: const Icon(Icons.close, color: Colors.white54, size: 18),
onPressed: () => Navigator.pop(context),
),
],
),
const SizedBox(height: 16),
// Package Stats Container
Container(
padding: const EdgeInsets.all(14),
decoration: BoxDecoration(
color: const Color(0xFF020617),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.white12),
),
child: Column(
children: [
_buildStatRow('حجم حزمة التوجيه والطرق:', '3.5 MB (شبكة طوبولوجية كاملة)'),
const Divider(color: Colors.white12, height: 14),
_buildStatRow('حجم معالم PostGIS المفهرسة:', '~25 MB (SQLite FTS5 سريع)'),
const Divider(color: Colors.white12, height: 14),
_buildStatRow('محرك التوجيه غير المتصل:', '100% On-Device (محرك Valhalla الحقيقي)'),
const Divider(color: Colors.white12, height: 14),
_buildStatRow('تحديث الحزم الميدانية:', 'متاح دائماً وفوري عند الطلب'),
if (_info?.lastSyncTime != null) ...[
const Divider(color: Colors.white12, height: 14),
_buildStatRow(
'آخر مزامنة ناجحة:',
'${_info!.lastSyncTime!.day}/${_info!.lastSyncTime!.month}/${_info!.lastSyncTime!.year}',
),
],
],
),
),
const SizedBox(height: 16),
// Live Sync Progress Stream
ValueListenableBuilder<double>(
valueListenable: OfflinePackageManager.syncProgress,
builder: (context, progress, _) {
return ValueListenableBuilder<String>(
valueListenable: OfflinePackageManager.syncStatusMessage,
builder: (context, msg, _) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_isDownloading) ...[
LinearProgressIndicator(
value: progress > 0 ? progress : null,
backgroundColor: const Color(0xFF1E293B),
color: const Color(0xFF0071E3),
borderRadius: BorderRadius.circular(4),
),
const SizedBox(height: 8),
],
Text(
msg,
style: TextStyle(
color: progress == 1.0 ? const Color(0xFF4ADE80) : const Color(0xFF94A3B8),
fontSize: 11,
fontWeight: progress == 1.0 ? FontWeight.bold : FontWeight.normal,
),
),
],
);
},
);
},
),
const SizedBox(height: 18),
// Action Buttons
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _isDownloading
? null
: () => _startSync(force: true),
icon: _isDownloading
? const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white))
: const Icon(Icons.cloud_download, size: 16),
label: Text(
_isDownloading
? 'جاري التنزيل والمزامنة...'
: 'مزامنة وتنزيل الحزمة الآن (غراف الطرق الحقيقي + المعالم)',
style: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.bold),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0071E3),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Color(0xFF0071E3)),
),
),
),
),
],
),
],
),
),
);
}
Widget _buildStatRow(String title, String value) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
title,
style: const TextStyle(color: Color(0xFF94A3B8), fontSize: 11),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 8),
Text(
value,
style: const TextStyle(color: Colors.white, fontSize: 11, fontWeight: FontWeight.bold),
),
],
);
}
}