From f4c211e0dd93ce7cc5e30de590253349d3258e21 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Wed, 30 Apr 2025 18:26:40 +0200 Subject: [PATCH] =?UTF-8?q?feat(login):=20=EF=BF=BD=20Refote=20visuelle=20?= =?UTF-8?q?du=20login=20-=20Fond=20paper2=20et=20image=20river=5Flogo=5Fde?= =?UTF-8?q?sktop=20positionn=C3=A9e=20=C3=A0=201/4=20de=20la=20largeur=20r?= =?UTF-8?q?estante=20-=20=E2=9C=A8=20S=C3=A9paration=20desktop/mobile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/lib/screens/auth/login_screen.dart | 270 +++++++++----------- frontend/pubspec.yaml | 45 ++-- 2 files changed, 146 insertions(+), 169 deletions(-) diff --git a/frontend/lib/screens/auth/login_screen.dart b/frontend/lib/screens/auth/login_screen.dart index 2a301ce..6468a02 100644 --- a/frontend/lib/screens/auth/login_screen.dart +++ b/frontend/lib/screens/auth/login_screen.dart @@ -1,155 +1,139 @@ +import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; -import '../../services/auth_service.dart'; -import '../../theme/theme_provider.dart'; -import '../../theme/app_theme.dart'; -import 'package:provider/provider.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; -class LoginScreen extends StatefulWidget { - const LoginScreen({super.key}); - - @override - State createState() => _LoginScreenState(); -} - -class _LoginScreenState extends State { - final _formKey = GlobalKey(); - final _emailController = TextEditingController(); - final _passwordController = TextEditingController(); - bool _isLoading = false; - - String _getThemeName(ThemeType type) { - switch (type) { - case ThemeType.defaultTheme: - return "P'titsPas"; - case ThemeType.pastelTheme: - return "Pastel"; - case ThemeType.darkTheme: - return "Sombre"; - } - } - - @override - void dispose() { - _emailController.dispose(); - _passwordController.dispose(); - super.dispose(); - } - - Future _login() async { - if (_formKey.currentState!.validate()) { - setState(() => _isLoading = true); - try { - await AuthService.login( - _emailController.text, - _passwordController.text, - ); - - if (mounted) { - context.go('/home'); - } - } catch (e) { - if (mounted) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Erreur lors de la connexion: $e'), - backgroundColor: Colors.red, - ), - ); - } - } finally { - if (mounted) { - setState(() => _isLoading = false); - } - } - } - } +class LoginPage extends StatelessWidget { + const LoginPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: const Text('Connexion'), - actions: [ - Consumer( - builder: (context, themeProvider, child) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: DropdownButton( - value: themeProvider.currentTheme, - items: ThemeType.values.map((ThemeType type) { - return DropdownMenuItem( - value: type, - child: Text(_getThemeName(type)), - ); - }).toList(), - onChanged: (ThemeType? newValue) { - if (newValue != null) { - themeProvider.setTheme(newValue); - } - }, - ), - ); - }, - ), - ], + backgroundColor: Colors.transparent, + body: LayoutBuilder( + builder: (context, constraints) { + // Version desktop (web) + if (kIsWeb) { + final w = constraints.maxWidth; + final h = constraints.maxHeight; + + return FutureBuilder( + future: _getImageDimensions(), + builder: (context, snapshot) { + if (!snapshot.hasData) { + return const Center(child: CircularProgressIndicator()); + } + + final imageDimensions = snapshot.data!; + final imageHeight = h; + final imageWidth = imageHeight * (imageDimensions.width / imageDimensions.height); + final remainingWidth = w - imageWidth; + final leftMargin = remainingWidth / 4; + + return Stack( + children: [ + // Fond en papier + Positioned.fill( + child: Image.asset( + 'assets/images/paper2.png', + fit: BoxFit.cover, + repeat: ImageRepeat.repeat, + ), + ), + // Image principale + Positioned( + left: leftMargin, + top: 0, + height: imageHeight, + width: imageWidth, + child: Image.asset( + 'assets/images/river_logo_desktop.png', + fit: BoxFit.contain, + ), + ), + // Contenu + const Center( + child: Text('Formulaire de connexion à implémenter'), + ), + ], + ); + }, + ); + } + + // Version mobile (à implémenter) + return const Center( + child: Text('Version mobile à implémenter'), + ); + }, ), - body: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.all(16.0), - child: Form( - key: _formKey, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - TextFormField( - controller: _emailController, - decoration: const InputDecoration( - labelText: 'Email', - border: OutlineInputBorder(), - ), - keyboardType: TextInputType.emailAddress, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre email'; - } - if (!value.contains('@')) { - return 'Veuillez entrer un email valide'; - } - return null; - }, - ), - const SizedBox(height: 16), - TextFormField( - controller: _passwordController, - decoration: const InputDecoration( - labelText: 'Mot de passe', - border: OutlineInputBorder(), - ), - obscureText: true, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Veuillez entrer votre mot de passe'; - } - return null; - }, - ), - const SizedBox(height: 24), - ElevatedButton( - onPressed: _isLoading ? null : _login, - child: _isLoading - ? const CircularProgressIndicator() - : const Text('Se connecter'), - ), - const SizedBox(height: 16), - TextButton( - onPressed: () => context.go('/parent-register'), - child: const Text('Créer un compte parent'), - ), - ], + ); + } + + Future _getImageDimensions() async { + final image = Image.asset('assets/images/river_logo_desktop.png'); + final completer = Completer(); + image.image.resolve(const ImageConfiguration()).addListener( + ImageStreamListener((info, _) { + completer.complete(ImageDimensions( + width: info.image.width.toDouble(), + height: info.image.height.toDouble(), + )); + }), + ); + return completer.future; + } +} + +class ImageDimensions { + final double width; + final double height; + + ImageDimensions({required this.width, required this.height}); +} + +// ─────────────────────────────────────────────────────────────── +// Champ texte avec fond image +// ─────────────────────────────────────────────────────────────── +class _ImageTextField extends StatelessWidget { + final String bg; + final double width; + final double height; + final String hint; + final bool obscure; + const _ImageTextField({ + required this.bg, + required this.width, + required this.height, + required this.hint, + this.obscure = false, + }); + + @override + Widget build(BuildContext context) { + return SizedBox( + width: width, + height: height, + child: Stack( + children: [ + Positioned.fill(child: Image.asset(bg, fit: BoxFit.fill)), + TextField( + obscureText: obscure, + style: GoogleFonts.merienda(fontSize: width * 0.045), + decoration: InputDecoration( + border: InputBorder.none, + hintText: hint, + hintStyle: GoogleFonts.merienda( + fontSize: width * 0.045, + color: Colors.black54, + ), + contentPadding: EdgeInsets.symmetric( + horizontal: width * 0.07, // 7 % latéral + vertical: height * 0.22, // 22 % vertical + ), ), ), - ), + ], ), ); } diff --git a/frontend/pubspec.yaml b/frontend/pubspec.yaml index 11d7a2f..2bfc58b 100644 --- a/frontend/pubspec.yaml +++ b/frontend/pubspec.yaml @@ -1,43 +1,36 @@ -name: petitspas +name: p_tits_pas description: Application de gestion de la garde d'enfants pour les collectivités locales. publish_to: 'none' -version: 1.0.0+1 +version: 0.1.0 environment: - sdk: '>=3.0.0 <4.0.0' + sdk: '>=3.2.6 <4.0.0' dependencies: flutter: sdk: flutter - cupertino_icons: ^1.0.2 - # Gestion d'état - provider: ^6.1.4 - # Navigation - go_router: ^13.0.0 - # API - dio: ^5.0.0 - # Local storage - shared_preferences: ^2.2.0 - # UI - flutter_svg: ^2.0.0 - google_fonts: ^6.2.1 - # Formulaires - form_validator: ^2.1.1 - # Dates - intl: ^0.18.0 - # Images - image_picker: ^1.0.0 - # PDF - pdf: ^3.10.0 - printing: ^5.11.0 + provider: ^6.1.1 + go_router: ^13.2.5 + google_fonts: ^6.1.0 + shared_preferences: ^2.2.2 + image_picker: ^1.0.7 + js: ^0.6.7 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 - build_runner: ^2.4.0 flutter: uses-material-design: true + assets: - - assets/images/ \ No newline at end of file + - assets/images/logo.png + - assets/images/river_logo_desktop.png + - assets/images/paper2.png + + fonts: + - family: Merienda + fonts: + - asset: assets/fonts/Merienda-VariableFont_wght.ttf + style: normal \ No newline at end of file