Phase 2 du MVP Flutter : vérification PIN locale, application des règles par famille, suivi des mouvements et correction avec plancher à 0. Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.4 KiB
Dart
89 lines
2.4 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../core/theme/app_theme.dart';
|
|
import '../../providers/parent_providers.dart';
|
|
import 'parent_space_screen.dart';
|
|
import 'widgets/pin_entry_card.dart';
|
|
|
|
/// Verrouillage en mémoire : le PIN est redemandé à chaque visite.
|
|
class ParentGateScreen extends ConsumerStatefulWidget {
|
|
const ParentGateScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<ParentGateScreen> createState() => _ParentGateScreenState();
|
|
}
|
|
|
|
class _ParentGateScreenState extends ConsumerState<ParentGateScreen> {
|
|
final _pinController = TextEditingController();
|
|
bool _obscurePin = true;
|
|
bool _isChecking = false;
|
|
String? _error;
|
|
|
|
@override
|
|
void dispose() {
|
|
_pinController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _submitPin() async {
|
|
final pin = _pinController.text;
|
|
if (pin.length < 4) {
|
|
setState(() => _error = 'Le PIN doit contenir au moins 4 chiffres.');
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
_isChecking = true;
|
|
_error = null;
|
|
});
|
|
|
|
final ok = await ref.read(parentRepositoryProvider).verifyPin(pin);
|
|
if (!mounted) return;
|
|
|
|
if (!ok) {
|
|
setState(() {
|
|
_isChecking = false;
|
|
_error = 'Code PIN incorrect.';
|
|
_pinController.clear();
|
|
});
|
|
return;
|
|
}
|
|
|
|
_pinController.clear();
|
|
await Navigator.of(context).pushReplacement(
|
|
MaterialPageRoute<void>(builder: (_) => const ParentSpaceScreen()),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return DecoratedBox(
|
|
decoration: const BoxDecoration(gradient: AppTheme.primaryGradient),
|
|
child: Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
appBar: AppBar(
|
|
leading: IconButton(
|
|
icon: const Icon(Icons.arrow_back),
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
title: const Text('Espace Parents'),
|
|
),
|
|
body: SafeArea(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
child: PinEntryCard(
|
|
pinController: _pinController,
|
|
obscurePin: _obscurePin,
|
|
isLoading: _isChecking,
|
|
error: _error,
|
|
onToggleObscure: () => setState(() => _obscurePin = !_obscurePin),
|
|
onSubmit: _submitPin,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|