Files
gestion_prix_produit/lib/screens/demarrage_screen.dart
T
2026-07-22 12:55:43 +02:00

148 lines
4.7 KiB
Dart

import 'package:flutter/material.dart';
import '../services/produit_repository.dart';
import '../theme.dart';
import 'home_shell.dart';
/// Écran affiché au lancement pendant la connexion au serveur.
/// Évite l'écran blanc : on voit le loader et l'étape en cours, et en cas
/// d'échec on peut réessayer ou continuer avec les données hors ligne.
class DemarrageScreen extends StatefulWidget {
const DemarrageScreen({super.key});
@override
State<DemarrageScreen> createState() => _DemarrageScreenState();
}
class _DemarrageScreenState extends State<DemarrageScreen> {
bool _fini = false;
@override
void initState() {
super.initState();
_lancer();
}
Future<void> _lancer() async {
final repo = ProduitRepository.instance;
await repo.initialiser();
if (!mounted) return;
// Serveur joignable (ou cache déjà rempli) : on entre directement dans l'app.
if (repo.connecte || repo.charge) {
setState(() => _fini = true);
} else {
setState(() {}); // affiche l'erreur + bouton Réessayer
}
}
Future<void> _reessayer() async {
await ProduitRepository.instance.charger();
if (!mounted) return;
final repo = ProduitRepository.instance;
if (repo.connecte || repo.charge) setState(() => _fini = true);
}
@override
Widget build(BuildContext context) {
if (_fini) return const HomeShell();
final repo = ProduitRepository.instance;
return Scaffold(
body: SafeArea(
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: ListenableBuilder(
listenable: repo,
builder: (context, _) {
final echec = !repo.enCours && repo.erreur != null;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
echec ? Icons.cloud_off_rounded : Icons.storefront_rounded,
size: 56,
color: echec ? const Color(0xFFB26B00) : AppTheme.accent,
),
const SizedBox(height: 20),
const Text(
'Gestion Prix',
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
),
),
const SizedBox(height: 36),
if (echec) ..._echec(repo) else ..._chargement(repo),
],
);
},
),
),
),
),
),
);
}
/// Loader + étape en cours juste en dessous.
List<Widget> _chargement(ProduitRepository repo) => [
const SizedBox(
width: 34,
height: 34,
child: CircularProgressIndicator(strokeWidth: 3),
),
const SizedBox(height: 18),
Text(
repo.etape.isEmpty ? 'Démarrage…' : repo.etape,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 14.5,
fontWeight: FontWeight.w500,
color: AppTheme.grisTexte,
),
),
const SizedBox(height: 6),
Text(
repo.serveurUrl,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 12, color: AppTheme.grisTexte),
),
];
/// Serveur injoignable et aucun produit en cache : on explique et on propose.
List<Widget> _echec(ProduitRepository repo) => [
const Text(
'Serveur injoignable',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w700),
),
const SizedBox(height: 8),
Text(
repo.serveurUrl,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 12.5, color: AppTheme.grisTexte),
),
const SizedBox(height: 10),
const Text(
'Vérifie que le serveur est allumé et que la tablette est bien '
'connectée au réseau (Tailscale actif).',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 13, color: AppTheme.grisTexte),
),
const SizedBox(height: 28),
FilledButton.icon(
onPressed: _reessayer,
icon: const Icon(Icons.refresh),
label: const Text('Réessayer'),
),
const SizedBox(height: 10),
TextButton(
onPressed: () => setState(() => _fini = true),
child: const Text('Continuer hors ligne'),
),
];
}