import 'package:flutter/material.dart'; import '../application/application.dart'; import '../domain/domain.dart'; import 'profile_screen.dart'; import 'theme.dart'; final class ShareFormScreen extends StatefulWidget { const ShareFormScreen({ required this.shareUseCases, required this.resourceType, required this.localResourceId, required this.resourceName, required this.resourceSummary, this.authUseCases, this.syncUseCases, super.key, }); final ShareUseCases shareUseCases; final AuthUseCases? authUseCases; final SyncUseCases? syncUseCases; final ShareResourceType resourceType; final String localResourceId; final String resourceName; final String resourceSummary; @override State createState() => _ShareFormScreenState(); } final class _ShareFormScreenState extends State { final _formKey = GlobalKey(); final _emailsController = TextEditingController(); var _sending = false; String? _message; @override void dispose() { _emailsController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(_shareTitle(widget.resourceType))), body: ListView( padding: const EdgeInsets.all(16), children: [ CourtBlazerAccentPanel( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( '${_resourceTitle(widget.resourceType)} à partager', style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: 8), Text(widget.resourceName), const SizedBox(height: 4), Text(widget.resourceSummary), const SizedBox(height: 16), Form( key: _formKey, child: TextFormField( controller: _emailsController, decoration: const InputDecoration( labelText: 'Emails destinataires', helperText: 'Sépare plusieurs emails par une virgule.', ), keyboardType: TextInputType.emailAddress, validator: _emailsValidator, ), ), if (_message != null) ...[ const SizedBox(height: 12), Text(_message!), ], const SizedBox(height: 16), FilledButton.icon( onPressed: _sending ? null : _send, icon: _sending ? const SizedBox.square( dimension: 18, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.ios_share), label: const Text('Envoyer le partage'), ), ], ), ), ], ), ); } Future _send() async { if (!_formKey.currentState!.validate()) return; setState(() { _sending = true; _message = null; }); try { final result = await widget.shareUseCases.sendShare( resourceType: widget.resourceType, localResourceId: widget.localResourceId, recipientEmails: _parseEmails(_emailsController.text), ); if (!mounted) return; setState(() { _sending = false; _message = _shareResultMessage(result); }); if (result.status == ShareSendStatus.notConnected) { await Navigator.of(context).push( MaterialPageRoute( builder: (context) => ShareAccountRequiredScreen( resourceType: widget.resourceType, shareUseCases: widget.shareUseCases, authUseCases: widget.authUseCases, syncUseCases: widget.syncUseCases, ), ), ); } } on DomainException { if (!mounted) return; setState(() { _sending = false; _message = 'Partage indisponible pour le moment.'; }); } } } final class ShareAccountRequiredScreen extends StatelessWidget { const ShareAccountRequiredScreen({ required this.resourceType, this.shareUseCases, this.authUseCases, this.syncUseCases, super.key, }); final ShareResourceType resourceType; final ShareUseCases? shareUseCases; final AuthUseCases? authUseCases; final SyncUseCases? syncUseCases; @override Widget build(BuildContext context) { final targetLabel = switch (resourceType) { ShareResourceType.program => 'ce programme', ShareResourceType.workoutTemplate => 'cette séance', }; final canOpenAuth = authUseCases != null && syncUseCases != null; return Scaffold( appBar: AppBar(title: const Text('Compte requis pour partager')), body: ListView( padding: const EdgeInsets.all(16), children: [ CourtBlazerAccentPanel( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Compte requis pour partager', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text( 'Connecte-toi pour envoyer $targetLabel à un autre compte ' 'GameTime. Le reste de l’app reste utilisable sans compte.', ), const SizedBox(height: 16), FilledButton( onPressed: canOpenAuth ? () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => LoginScreen( authUseCases: authUseCases!, syncUseCases: syncUseCases!, shareUseCases: shareUseCases, ), ), ) : null, child: const Text('Se connecter'), ), const SizedBox(height: 8), OutlinedButton( onPressed: canOpenAuth ? () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => RegisterScreen( authUseCases: authUseCases!, syncUseCases: syncUseCases!, shareUseCases: shareUseCases, ), ), ) : null, child: const Text('Créer un compte'), ), const SizedBox(height: 8), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Annuler'), ), ], ), ), ], ), ); } } String? _emailsValidator(String? value) { final emails = _parseEmails(value ?? ''); if (emails.isEmpty) { return "Saisis l'email du destinataire."; } final invalid = emails.any( (email) => !RegExp(r'^[^@\s]+@[^@\s]+\.[^@\s]+$').hasMatch(email), ); if (invalid) { return "Saisis l'email du destinataire."; } return null; } List _parseEmails(String value) { return value .split(RegExp(r'[,;\n]')) .map((email) => email.trim()) .where((email) => email.isNotEmpty) .toList(growable: false); } String _shareResultMessage(ShareSendResult result) { return switch (result.status) { ShareSendStatus.notConnected => 'Compte requis pour partager.', ShareSendStatus.queued => 'Partage enregistré. Envoi dès que possible.', ShareSendStatus.sent when result.unresolvedEmails.isNotEmpty => 'Partage envoyé. Non trouvés : ${result.unresolvedEmails.join(', ')}.', ShareSendStatus.sent => 'Partage envoyé.', }; } String _shareTitle(ShareResourceType type) { return switch (type) { ShareResourceType.program => 'Partager le programme', ShareResourceType.workoutTemplate => 'Partager la séance', }; } String _resourceTitle(ShareResourceType type) { return switch (type) { ShareResourceType.program => 'Programme', ShareResourceType.workoutTemplate => 'Séance', }; }