feat(frontend): #50 — validation CGU et politique de confidentialité

- Modale de validation avec chargement des PDF distants, PdfViewPinch et barre de progression latérale (repli PdfView sous Windows).

- Service documents légaux actifs, correction des URLs média, intégration au formulaire de présentation.

- Documentation juridique et réorganisation (archive, index, tickets).

Made-with: Cursor
This commit is contained in:
2026-04-17 17:28:07 +02:00
parent 241ce36b85
commit 7381ce356d
34 changed files with 2169 additions and 912 deletions
@@ -1,7 +1,8 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:go_router/go_router.dart';
import 'dart:math' as math;
import 'custom_decorated_text_field.dart';
import 'app_custom_checkbox.dart';
@@ -9,6 +10,7 @@ import 'custom_navigation_button.dart';
import 'hover_relief_widget.dart';
import '../models/card_assets.dart';
import '../config/display_config.dart';
import 'cgu_privacy_validation_dialog.dart';
/// Widget générique pour le formulaire de présentation avec texte libre + CGU
/// Supporte mode éditable et readonly, responsive mobile/desktop
@@ -75,6 +77,52 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
widget.onSubmit(_textController.text, _cguAccepted);
}
Future<void> _openCguValidationDialog() async {
final validated = await showDialog<bool>(
context: context,
builder: (context) => const CguPrivacyValidationDialog(),
);
if (validated == true && mounted) {
setState(() => _cguAccepted = true);
}
}
Widget _buildCguValidationControl({
required double fontSize,
bool compact = false,
}) {
final label = compact
? 'Jai validé les CGU et la\nPolitique de confidentialité'
: 'Jai validé les Conditions Générales\ndUtilisation et la Politique de confidentialité';
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Checkbox(
value: _cguAccepted,
onChanged: null,
),
Flexible(
child: Text(
label,
style: GoogleFonts.merienda(fontSize: fontSize),
),
),
],
),
const SizedBox(height: 6),
TextButton.icon(
onPressed: _openCguValidationDialog,
icon: const Icon(Icons.open_in_new, size: 18),
label: const Text('Consulter et valider les CGU'),
),
],
);
}
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
@@ -451,11 +499,13 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
),
),
const SizedBox(height: 20),
AppCustomCheckbox(
label: 'J\'accepte les Conditions Générales\nd\'Utilisation et la Politique de confidentialité',
value: _cguAccepted,
onChanged: config.isReadonly ? (v) {} : (value) => setState(() => _cguAccepted = value ?? false),
),
config.isReadonly
? AppCustomCheckbox(
label: 'J\'accepte les Conditions Générales\nd\'Utilisation et la Politique de confidentialité',
value: _cguAccepted,
onChanged: (v) {},
)
: _buildCguValidationControl(fontSize: 16),
],
),
),
@@ -507,12 +557,17 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
const SizedBox(height: 16),
// Checkbox en bas
Transform.scale(
scale: 0.85,
child: AppCustomCheckbox(
label: 'J\'accepte les CGU et la\nPolitique de confidentialité',
value: _cguAccepted,
onChanged: config.isReadonly ? (v) {} : (value) => setState(() => _cguAccepted = value ?? false),
),
scale: 0.95,
child: config.isReadonly
? AppCustomCheckbox(
label: 'J\'accepte les CGU et la\nPolitique de confidentialité',
value: _cguAccepted,
onChanged: (v) {},
)
: _buildCguValidationControl(
fontSize: 14,
compact: true,
),
),
],
),
@@ -549,13 +604,19 @@ class _PresentationFormScreenState extends State<PresentationFormScreen> {
const SizedBox(width: 16),
Expanded(
child: HoverReliefWidget(
child: CustomNavigationButton(
text: 'Suivant',
style: NavigationButtonStyle.green,
onPressed: _handleSubmit,
width: double.infinity,
height: 50,
fontSize: 16,
child: Opacity(
opacity: _cguAccepted ? 1 : 0.55,
child: AbsorbPointer(
absorbing: !_cguAccepted,
child: CustomNavigationButton(
text: 'Suivant',
style: NavigationButtonStyle.green,
onPressed: _handleSubmit,
width: double.infinity,
height: 50,
fontSize: 16,
),
),
),
),
),