import 'package:flutter/material.dart'; /// Constantes UI partagées (étape 5 — layout). abstract final class SwiftyUi { static const Color brand = Color(0xFF00BABC); /// Largeur max du contenu sur tablette / paysage. static const double contentMaxWidth = 960; /// Largeur max vue recherche (formulaire centré). static const double searchMaxWidth = 480; static const double wideBreakpoint = 720; static EdgeInsets pagePadding(BoxConstraints constraints) { final horizontal = constraints.maxWidth >= 600 ? 32.0 : 16.0; return EdgeInsets.fromLTRB(horizontal, 24, horizontal, 24); } static PreferredSizeWidget appBar({ required String title, List? actions, bool showBack = false, }) { return AppBar( title: Text(title), backgroundColor: brand, foregroundColor: Colors.black, automaticallyImplyLeading: showBack, actions: actions, ); } } /// Corps scrollable centré avec largeur max (clavier + petits écrans). class ResponsiveScrollBody extends StatelessWidget { const ResponsiveScrollBody({ super.key, required this.child, this.maxWidth = SwiftyUi.contentMaxWidth, this.center = true, }); final Widget child; final double maxWidth; final bool center; @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) { final content = ConstrainedBox( constraints: BoxConstraints(maxWidth: maxWidth), child: child, ); return SingleChildScrollView( padding: SwiftyUi.pagePadding(constraints), keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag, child: center ? Align(alignment: Alignment.topCenter, child: content) : content, ); }, ); } } class ErrorMessage extends StatelessWidget { const ErrorMessage({super.key, required this.message}); final String message; @override Widget build(BuildContext context) { return SelectableText( message, textAlign: TextAlign.center, style: TextStyle(color: Theme.of(context).colorScheme.error), ); } } class LoadingFilledButton extends StatelessWidget { const LoadingFilledButton({ super.key, required this.label, required this.loading, required this.onPressed, }); final String label; final bool loading; final VoidCallback? onPressed; @override Widget build(BuildContext context) { return FilledButton( onPressed: loading ? null : onPressed, child: loading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : Text(label), ); } }