feat(online): partage sortant et boîte de réception (ticket #69)

Ajoute l'écran de partage sortant (presentation/share_screen.dart) et
la boîte de réception des partages (presentation/share_inbox_screen.dart),
avec les points d'entrée sur profile_screen.dart, home_screen.dart,
program_screen.dart et workout_template_screen.dart. flutter analyze
propre (mêmes infos préexistantes), 132/132 tests verts, build APK
debug validé. Dernier ticket de développement du chantier "Ajouter
les features serveur au client" (#63) — il ne reste que la QA finale
(#70).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 07:23:14 +02:00
parent eee4348b52
commit d16a017743
11 changed files with 1598 additions and 22 deletions

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import '../application/application.dart';
import '../domain/domain.dart';
import 'share_screen.dart';
import 'workout_execution_screen.dart';
final class WorkoutTemplateListScreen extends StatefulWidget {
@ -15,6 +16,9 @@ final class WorkoutTemplateListScreen extends StatefulWidget {
required this.historyUseCases,
this.mediaUseCases,
this.stepUseCases,
this.shareUseCases,
this.authUseCases,
this.syncUseCases,
super.key,
});
@ -25,6 +29,9 @@ final class WorkoutTemplateListScreen extends StatefulWidget {
final CloseWorkoutSessionUseCase closeUseCase;
final WorkoutHistoryUseCases historyUseCases;
final MediaUseCases? mediaUseCases;
final ShareUseCases? shareUseCases;
final AuthUseCases? authUseCases;
final SyncUseCases? syncUseCases;
@override
State<WorkoutTemplateListScreen> createState() =>
@ -109,6 +116,9 @@ final class _WorkoutTemplateListScreenState
builder: (context) => WorkoutTemplateFormScreen(
workoutTemplateUseCases: widget.workoutTemplateUseCases,
programUseCases: widget.programUseCases,
shareUseCases: widget.shareUseCases,
authUseCases: widget.authUseCases,
syncUseCases: widget.syncUseCases,
template: template,
),
),
@ -193,12 +203,18 @@ final class WorkoutTemplateFormScreen extends StatefulWidget {
const WorkoutTemplateFormScreen({
required this.workoutTemplateUseCases,
required this.programUseCases,
this.shareUseCases,
this.authUseCases,
this.syncUseCases,
this.template,
super.key,
});
final WorkoutTemplateUseCases workoutTemplateUseCases;
final ProgramUseCases programUseCases;
final ShareUseCases? shareUseCases;
final AuthUseCases? authUseCases;
final SyncUseCases? syncUseCases;
final WorkoutTemplate? template;
@override
@ -241,6 +257,14 @@ final class _WorkoutTemplateFormScreenState
return Scaffold(
appBar: AppBar(
title: Text(_isEditing ? 'Modifier la séance' : 'Créer une séance'),
actions: [
if (_isEditing && widget.shareUseCases != null)
IconButton(
tooltip: 'Partager',
icon: const Icon(Icons.ios_share),
onPressed: _shareTemplate,
),
],
),
bottomNavigationBar: SafeArea(
minimum: const EdgeInsets.all(16),
@ -390,6 +414,25 @@ final class _WorkoutTemplateFormScreenState
}
}
Future<void> _shareTemplate() async {
final template = widget.template;
final shareUseCases = widget.shareUseCases;
if (template == null || shareUseCases == null) return;
await Navigator.of(context).push<void>(
MaterialPageRoute(
builder: (context) => ShareFormScreen(
shareUseCases: shareUseCases,
authUseCases: widget.authUseCases,
syncUseCases: widget.syncUseCases,
resourceType: ShareResourceType.workoutTemplate,
localResourceId: template.metadata.id,
resourceName: template.name,
resourceSummary: _templateSummary(template),
),
),
);
}
void _showSnackBar(String message) {
if (!mounted) return;
ScaffoldMessenger.of(