From c2df7f251261d3d445a0287ecdc60bf7d22feae0 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Mon, 14 Aug 2023 23:12:44 +0200 Subject: [PATCH 1/5] change password --- .../justMUSIC/assets/images/password_icon.png | Bin 0 -> 3503 bytes Sources/justMUSIC/lib/config/routes.dart | 19 ++ .../lib/screens/change_password_screen.dart | 307 ++++++++++++++++++ .../justMUSIC/lib/screens/profile_screen.dart | 9 + .../justMUSIC/lib/screens/user_screen.dart | 6 +- Sources/justMUSIC/lib/values/icons.dart | 6 +- 6 files changed, 343 insertions(+), 4 deletions(-) create mode 100644 Sources/justMUSIC/assets/images/password_icon.png create mode 100644 Sources/justMUSIC/lib/screens/change_password_screen.dart diff --git a/Sources/justMUSIC/assets/images/password_icon.png b/Sources/justMUSIC/assets/images/password_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..769b019646f9789fd315055040f5e07ad43514ec GIT binary patch literal 3503 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 Xx(8s2$F}G971J#<8`EZE_muwyUHQbb literal 0 HcmV?d00001 diff --git a/Sources/justMUSIC/lib/config/routes.dart b/Sources/justMUSIC/lib/config/routes.dart index 1c4ed4b..a9f0df0 100644 --- a/Sources/justMUSIC/lib/config/routes.dart +++ b/Sources/justMUSIC/lib/config/routes.dart @@ -1,5 +1,6 @@ import 'package:flutter/Material.dart'; import 'package:justmusic/screens/add_friend_screen.dart'; +import 'package:justmusic/screens/change_password_screen.dart'; import 'package:justmusic/screens/feed_screen.dart'; import 'package:justmusic/screens/profile_screen.dart'; import 'package:justmusic/screens/user_screen.dart'; @@ -71,3 +72,21 @@ Route routeUser(User user) { }, ); } + +Route routePassword() { + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => const ChangePasswordScreen(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0.0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + ); +} diff --git a/Sources/justMUSIC/lib/screens/change_password_screen.dart b/Sources/justMUSIC/lib/screens/change_password_screen.dart new file mode 100644 index 0000000..0965a74 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/change_password_screen.dart @@ -0,0 +1,307 @@ +import 'package:firebase_auth/firebase_auth.dart'; + +import 'package:flutter/Material.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:justmusic/main.dart'; + +import '../values/constants.dart'; + +class ChangePasswordScreen extends StatefulWidget { + const ChangePasswordScreen({super.key}); + + @override + State createState() => _ChangePasswordScreenState(); +} + +class _ChangePasswordScreenState extends State { + final _currentPasswordTextField = TextEditingController(); + final _newPasswordTextField = TextEditingController(); + final _confirmPasswordTextField = TextEditingController(); + final _formKey = GlobalKey(); + Future resetFullScreen() async { + await SystemChannels.platform.invokeMethod( + 'SystemChrome.restoreSystemUIOverlays', + ); + } + + handleChange() async { + print("test"); + if (_formKey.currentState!.validate()) { + var error; + try { + await FirebaseAuth.instance.signInWithEmailAndPassword( + email: MyApp.userViewModel.userCurrent.mail, + password: _currentPasswordTextField.text, + ); + if (_newPasswordTextField.text == _confirmPasswordTextField.text) { + await FirebaseAuth.instance.currentUser?.updatePassword(_confirmPasswordTextField.text); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Mot de passe mis à jour", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 15.h), + ), + backgroundColor: primaryColor, + closeIconColor: Colors.white, + ), + ); + } else { + throw FirebaseAuthException(code: "not-same", message: "Les mots de passe ne correspondent pas"); + } + } on FirebaseAuthException catch (e) { + if (e.code == "wrong-password") { + error = "Mot de passe incorrect"; + } else if (e.code == "too-many-requests") { + error = "Trop de tentatives infructueuses. Veuillez réessayer plus tard"; + } else if (e.code == "channel-error") { + error = "Impossible de vérifier le mot de passe"; + } else if (e.code == "weak-password") { + error = "Le mot de passe doit contenir 6 caractères minimum"; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + error ?? e.message, + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 15.h), + ), + backgroundColor: Colors.red, + closeIconColor: Colors.white, + ), + ); + } + setState(() { + _currentPasswordTextField.clear(); + _newPasswordTextField.clear(); + _confirmPasswordTextField.clear(); + }); + } + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + resetFullScreen(); + } + }, + child: Scaffold( + appBar: PreferredSize( + preferredSize: Size(double.infinity, 58), + child: Container( + height: double.infinity, + color: bgAppBar, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: defaultPadding), + child: Stack( + alignment: Alignment.centerLeft, + children: [ + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context, true); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + height: 30, + width: 30, + child: Image( + image: AssetImage("assets/images/return_icon.png"), + height: 8, + ), + )), + Align( + child: Text( + "Mettre le mot de passe à jour", + style: + GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), + ), + ) + ], + ), + ), + ), + ), + body: Container( + width: double.infinity, + height: double.infinity, + color: bgColor, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: settingPadding), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 30, bottom: 40), + child: SizedBox( + width: double.infinity, + child: Form( + key: _formKey, + child: Stack( + alignment: Alignment.center, + children: [ + Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 10), + child: Text( + "Mot de passe actuel", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w800, fontSize: 16), + ), + )), + Expanded( + child: TextFormField( + controller: _currentPasswordTextField, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when you click the TextField + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when the TextField is disabled + disabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + filled: true, + hintText: '6 caractères minimum', + hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), + maxLines: 1, + obscureText: true, + cursorColor: primaryColor, + style: GoogleFonts.plusJakartaSans( + color: grayText, fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ], + ), + SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 10), + child: Text( + "Nouveau mot de passe", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w800, fontSize: 16), + ), + )), + Expanded( + child: TextField( + controller: _newPasswordTextField, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when you click the TextField + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when the TextField is disabled + disabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + filled: true, + hintText: '6 caractères minimum', + hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), + maxLines: 1, + obscureText: true, + cursorColor: primaryColor, + style: GoogleFonts.plusJakartaSans( + color: grayText, fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ], + ), + SizedBox( + height: 10, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 10), + child: Text( + "Confirmer", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, fontWeight: FontWeight.w800, fontSize: 16), + ), + )), + Expanded( + child: TextField( + obscureText: true, + controller: _confirmPasswordTextField, + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when you click the TextField + focusedBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + // Hides the border when the TextField is disabled + disabledBorder: OutlineInputBorder( + borderSide: const BorderSide(color: Colors.transparent), + ), + filled: true, + hintText: '6 caractères minimum', + hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), + maxLines: 1, + cursorColor: primaryColor, + style: GoogleFonts.plusJakartaSans( + color: grayText, fontWeight: FontWeight.w400, fontSize: 16), + ), + ), + ], + ), + ], + ) + ], + ), + ), + ), + ), + GestureDetector( + onTap: handleChange, + child: Align( + child: Container( + height: 35, + width: 160, + decoration: + BoxDecoration(color: primaryColor, borderRadius: BorderRadius.all(Radius.circular(10))), + child: Center( + child: Text( + "Mettre à jour", + style: GoogleFonts.plusJakartaSans(color: Colors.white), + ), + ), + ), + ), + ) + ], + ), + ), + ), + ), + )); + } +} diff --git a/Sources/justMUSIC/lib/screens/profile_screen.dart b/Sources/justMUSIC/lib/screens/profile_screen.dart index 1a5fafe..ab9835d 100644 --- a/Sources/justMUSIC/lib/screens/profile_screen.dart +++ b/Sources/justMUSIC/lib/screens/profile_screen.dart @@ -30,6 +30,10 @@ class _ProfileScreenState extends State { Navigator.of(context).push(routeUser(MyApp.userViewModel.userCurrent)); } + void _openPassword() { + Navigator.of(context).push(routePassword()); + } + return Scaffold( appBar: PreferredSize( preferredSize: Size(double.infinity, 58), @@ -113,6 +117,11 @@ class _ProfileScreenState extends State { label: 'Lier un compte Spotify', action: null, ), + SettingPartComponent( + icon: JustMusicIcon.password, + label: 'Modifier mon mot de passe', + action: _openPassword, + ), const SettingPartComponent( icon: JustMusicIcon.trash, label: 'Supprimer mon compte', diff --git a/Sources/justMUSIC/lib/screens/user_screen.dart b/Sources/justMUSIC/lib/screens/user_screen.dart index 4ee6494..30eb974 100644 --- a/Sources/justMUSIC/lib/screens/user_screen.dart +++ b/Sources/justMUSIC/lib/screens/user_screen.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/Material.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; @@ -10,11 +12,11 @@ import 'package:image_picker/image_picker.dart'; import '../components/profile_component.dart'; import '../components/recap_component.dart'; import '../main.dart'; -import '../model/User.dart'; +import '../model/User.dart' as UserJstMusic; import '../values/constants.dart'; class UserScreen extends StatefulWidget { - final User user; + final UserJstMusic.User user; const UserScreen({super.key, required this.user}); @override diff --git a/Sources/justMUSIC/lib/values/icons.dart b/Sources/justMUSIC/lib/values/icons.dart index 1cd01d1..f08140b 100644 --- a/Sources/justMUSIC/lib/values/icons.dart +++ b/Sources/justMUSIC/lib/values/icons.dart @@ -5,7 +5,8 @@ enum JustMusicIcon { cross, history, theme, - notification + notification, + password, } extension MyIconExtension on JustMusicIcon { @@ -25,7 +26,8 @@ extension MyIconExtension on JustMusicIcon { return 'assets/images/theme_icon.png'; case JustMusicIcon.notification: return 'assets/images/notification_icon.png'; - + case JustMusicIcon.password: + return 'assets/images/password_icon.png'; default: throw 'assets/images/unknown.png'; } From 8a561bd4ed0e923b1b1ac9bbcc7590d916bda9a2 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Mon, 14 Aug 2023 23:33:19 +0200 Subject: [PATCH 2/5] change password --- .../lib/components/comment_component.dart | 1 + .../components/profil_picture_component.dart | 2 +- .../lib/screens/change_password_screen.dart | 170 +++++++++--------- 3 files changed, 89 insertions(+), 84 deletions(-) diff --git a/Sources/justMUSIC/lib/components/comment_component.dart b/Sources/justMUSIC/lib/components/comment_component.dart index 36d9c95..a2c8965 100644 --- a/Sources/justMUSIC/lib/components/comment_component.dart +++ b/Sources/justMUSIC/lib/components/comment_component.dart @@ -32,6 +32,7 @@ class CommentComponent extends StatelessWidget { // Image radius child: FadeInImage.assetNetwork( image: comment.user.pp, + fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 100), placeholder: "assets/images/loadingPlaceholder.gif", ), diff --git a/Sources/justMUSIC/lib/components/profil_picture_component.dart b/Sources/justMUSIC/lib/components/profil_picture_component.dart index 01f8b3f..48b734a 100644 --- a/Sources/justMUSIC/lib/components/profil_picture_component.dart +++ b/Sources/justMUSIC/lib/components/profil_picture_component.dart @@ -24,7 +24,7 @@ class ProfilPictureComponent extends StatelessWidget { // Image radius child: FadeInImage.assetNetwork( image: user.pp, - fit: BoxFit.fill, + fit: BoxFit.cover, fadeInDuration: const Duration(milliseconds: 100), placeholder: "assets/images/loadingPlaceholder.gif", ), diff --git a/Sources/justMUSIC/lib/screens/change_password_screen.dart b/Sources/justMUSIC/lib/screens/change_password_screen.dart index 0965a74..d9d8beb 100644 --- a/Sources/justMUSIC/lib/screens/change_password_screen.dart +++ b/Sources/justMUSIC/lib/screens/change_password_screen.dart @@ -83,72 +83,74 @@ class _ChangePasswordScreenState extends State { @override Widget build(BuildContext context) { return GestureDetector( - onTap: () { - FocusScopeNode currentFocus = FocusScope.of(context); - if (!currentFocus.hasPrimaryFocus) { - currentFocus.unfocus(); - resetFullScreen(); - } - }, - child: Scaffold( - appBar: PreferredSize( - preferredSize: Size(double.infinity, 58), - child: Container( - height: double.infinity, - color: bgAppBar, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: defaultPadding), - child: Stack( - alignment: Alignment.centerLeft, - children: [ - GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context, true); - }, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 10), - height: 30, - width: 30, - child: Image( - image: AssetImage("assets/images/return_icon.png"), - height: 8, - ), - )), - Align( - child: Text( - "Mettre le mot de passe à jour", - style: - GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), - ), - ) - ], - ), + onTap: () { + FocusScopeNode currentFocus = FocusScope.of(context); + if (!currentFocus.hasPrimaryFocus) { + currentFocus.unfocus(); + resetFullScreen(); + } + }, + child: Scaffold( + appBar: PreferredSize( + preferredSize: Size(double.infinity, 58), + child: Container( + height: double.infinity, + color: bgAppBar, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: defaultPadding), + child: Stack( + alignment: Alignment.centerLeft, + children: [ + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context, true); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + height: 30, + width: 30, + child: Image( + image: AssetImage("assets/images/return_icon.png"), + height: 8, + ), + )), + Align( + child: Text( + "Mettre le mot de passe à jour", + style: + GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), + ), + ) + ], ), ), ), - body: Container( - width: double.infinity, - height: double.infinity, - color: bgColor, - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: settingPadding), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.only(top: 30, bottom: 40), - child: SizedBox( - width: double.infinity, - child: Form( - key: _formKey, - child: Stack( - alignment: Alignment.center, - children: [ - Column( + ), + body: Container( + width: double.infinity, + height: double.infinity, + color: bgColor, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: settingPadding), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 30, bottom: 40), + child: SizedBox( + width: double.infinity, + child: Form( + key: _formKey, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + constraints: BoxConstraints(maxWidth: 600), + child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -274,34 +276,36 @@ class _ChangePasswordScreenState extends State { ], ), ], - ) - ], - ), + ), + ) + ], ), ), ), - GestureDetector( - onTap: handleChange, - child: Align( - child: Container( - height: 35, - width: 160, - decoration: - BoxDecoration(color: primaryColor, borderRadius: BorderRadius.all(Radius.circular(10))), - child: Center( - child: Text( - "Mettre à jour", - style: GoogleFonts.plusJakartaSans(color: Colors.white), - ), + ), + GestureDetector( + onTap: handleChange, + child: Align( + child: Container( + height: 35, + width: 160, + decoration: + BoxDecoration(color: primaryColor, borderRadius: BorderRadius.all(Radius.circular(10))), + child: Center( + child: Text( + "Mettre à jour", + style: GoogleFonts.plusJakartaSans(color: Colors.white), ), ), ), - ) - ], - ), + ), + ) + ], ), ), ), - )); + ), + ), + ); } } From a96d17891f2ab892ff571aaea772e4cd3a420564 Mon Sep 17 00:00:00 2001 From: Emre Date: Tue, 15 Aug 2023 21:19:46 +0200 Subject: [PATCH 3/5] Forgot password done :white_check_mark: --- Sources/justMUSIC/assets/images/key_icon.png | Bin 0 -> 983 bytes .../lib/components/login_button.dart | 5 +- Sources/justMUSIC/lib/main.dart | 2 + .../lib/screens/forget_password_screen.dart | 234 ++++++++++++++++++ .../lib/screens/registration_screen.dart | 3 +- .../lib/screens/verify_email_screen.dart | 3 +- 6 files changed, 243 insertions(+), 4 deletions(-) create mode 100644 Sources/justMUSIC/assets/images/key_icon.png create mode 100644 Sources/justMUSIC/lib/screens/forget_password_screen.dart diff --git a/Sources/justMUSIC/assets/images/key_icon.png b/Sources/justMUSIC/assets/images/key_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b869f0ebbc99a564b2e7dee24b0be70025bcdeba GIT binary patch literal 983 zcmV;|11S87P)gKp{jBwDE<4idI5w0`?LAhbR%v!zAY=FAHzqU=S@*1fMCsV7=GmFOu_50h0+Qd*8n@=Pma$F9D!>oO`t*B;6paY z3%H%qfM^JpHXNfe0S{4k1Nf!ajnOJggA>;*-c>G6`;Yne%%ttCjb%8(zX) zWD?vkqlLT3%H|!vFR^`Q;SDzV>7M1VJf~D5hUK7kPCwga8s3I`$TYZVk5<{R;c)li zDE!Rw^WQwncgm;mCd*HTo5%(%*R{N1sg?I}d33Ws%vnxQE8t34$}3W=U}9M66Gp#w zPKM(n{G{In}G-dJB|? zA)cYS0NsbN;0PX@ljWt)lNxN?F9y6%Y-&%K5{xM=S3S36#@JM?jXt zQg6Jz&Sg2ARg^aTaNSxj3@GKb5yPc6pgt`1MZA=CE?oi9ph2yH`ZE{Sb2FN$3#c-$ zl?{c2`wG`knkg2rK+pa^0Xh1{x$**X_^_ createState() => _LoginButtonState(); @@ -57,7 +58,7 @@ class _LoginButtonState extends State { ), alignment: Alignment.center, child: Text( - "Se connecter", + widget.text, textAlign: TextAlign.center, style: TextStyle(color: Colors.white, fontSize: 18), ), diff --git a/Sources/justMUSIC/lib/main.dart b/Sources/justMUSIC/lib/main.dart index 45e9b19..4ac0733 100644 --- a/Sources/justMUSIC/lib/main.dart +++ b/Sources/justMUSIC/lib/main.dart @@ -11,6 +11,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:justmusic/screens/add_friend_screen.dart'; import 'package:justmusic/screens/explanations_screen.dart'; import 'package:justmusic/screens/feed_screen.dart'; +import 'package:justmusic/screens/forget_password_screen.dart'; import 'package:justmusic/screens/login_screen.dart'; import 'package:justmusic/screens/launching_rocker_screen.dart'; import 'package:justmusic/screens/post_screen.dart'; @@ -102,6 +103,7 @@ class _MyAppState extends State { '/addFriend': (context) => const AddFriendScreen(), '/launchingRocket': (context) => const LaunchingRocketScreen(), '/verifyEmail': (context) => const VerifyEmailScreen(), + '/forgetPassword': (context) => const ForgetPasswordScreen(), }, debugShowCheckedModeBanner: false, theme: ThemeData( diff --git a/Sources/justMUSIC/lib/screens/forget_password_screen.dart b/Sources/justMUSIC/lib/screens/forget_password_screen.dart new file mode 100644 index 0000000..f43c889 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/forget_password_screen.dart @@ -0,0 +1,234 @@ +import 'dart:async'; + +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/Material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../components/login_button.dart'; +import '../values/constants.dart'; + +class ForgetPasswordScreen extends StatefulWidget { + const ForgetPasswordScreen({Key? key}) : super(key: key); + + @override + State createState() => _ForgetPasswordScreenState(); +} + +class _ForgetPasswordScreenState extends State { + bool canResendEmail = true; + Timer? timer; + final _formKey = GlobalKey(); + final _mailTextField = TextEditingController(); + + @override + void dispose() { + timer?.cancel(); + + super.dispose(); + } + + Future sendForgetPasswordEmail() async { + if (_formKey.currentState!.validate()) { + var error; + try { + await FirebaseAuth.instance + .sendPasswordResetEmail(email: _mailTextField.text); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + "Un e-mail de réinitialisation a été envoyé. Veuillez patienter pendant 30 secondes avant la prochaine utilisation.", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 15.h), + ), + backgroundColor: primaryColor, + ), + ); + setState(() => canResendEmail = false); + await Future.delayed(Duration(minutes: 1)); + setState(() => canResendEmail = true); + } on FirebaseAuthException catch (e) { + if (e.code == "invalid-email") { + error = "Mail incorrect"; + } else if (e.code == "user-not-found") { + error = "Format de mail incorrect"; + } else if (e.code == "too-many-requests") { + error = + "Trop de tentatives. Veuillez réessayer plus tard"; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + error, + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20.h), + ), + backgroundColor: Colors.red, + ), + ); + } + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: bgColor, + body: Form( + key: _formKey, + child: Stack( + children: [ + SingleChildScrollView( + child: SizedBox( + width: double.infinity, + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 185.h), + child: Align( + child: SizedBox( + width: 56.h, + child: Image( + image: AssetImage( + "assets/images/key_icon.png")), + ), + )), + Padding( + padding: EdgeInsets.only(top: 28.h), + child: AutoSizeText( + "Mot de passe oublié", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w600, + fontSize: 24.w), + maxLines: 1, + maxFontSize: 30, + overflow: TextOverflow.fade, + ), + ), + Padding( + padding: + EdgeInsets.symmetric(horizontal: defaultPadding), + child: Padding( + padding: EdgeInsets.only(bottom: 20.h), + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + SizedBox( + height: 15.h, + ), + SizedBox( + width: 346.h, + child: AutoSizeText( + "Afin de procéder à la récupération de votre mot de passe, veuillez renseigner votre adresse mail correspondant a votre compte JustMusic.", + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w100, + fontSize: 16.w), + maxFontSize: 20, + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + ), + ConstrainedBox( + constraints: BoxConstraints(maxWidth: 600), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only( + bottom: 68.h, + left: defaultPadding, + right: defaultPadding), + child: TextFormField( + controller: _mailTextField, + keyboardAppearance: Brightness.dark, + validator: (value) { + if (value == null || value.isEmpty) { + return 'entrez un email valide'; + } + return null; + }, + cursorColor: primaryColor, + keyboardType: + TextInputType.emailAddress, + style: GoogleFonts.plusJakartaSans( + color: primaryColor), + decoration: InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + suffix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + fillColor: bgTextField, + filled: true, + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + hintText: 'Email', + hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), + )), + Padding( + padding: EdgeInsets.symmetric( + horizontal: defaultPadding), + child: SizedBox( + width: 600, + child: LoginButton( + callback: () { + canResendEmail + ? sendForgetPasswordEmail() + : null; + }, + text: "Envoyer", + )), + ), + ])), + Align( + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pushNamed(context, '/login'); + }, + child: Padding( + padding: EdgeInsets.only(top: 101), + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: 'Revenir a l’étape précédente', + style: GoogleFonts.plusJakartaSans( + fontSize: 15, + fontWeight: FontWeight.w400, + color: primaryColor), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ], + ))); + } +} diff --git a/Sources/justMUSIC/lib/screens/registration_screen.dart b/Sources/justMUSIC/lib/screens/registration_screen.dart index 9ff5692..9d03be5 100644 --- a/Sources/justMUSIC/lib/screens/registration_screen.dart +++ b/Sources/justMUSIC/lib/screens/registration_screen.dart @@ -36,7 +36,7 @@ class _RegistrationScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", + e.toString(), style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), ), backgroundColor: Colors.red, @@ -276,6 +276,7 @@ class _RegistrationScreenState extends State { width: 600, child: LoginButton( callback: handleRegister, + text: "Continuer", )), ), Align( diff --git a/Sources/justMUSIC/lib/screens/verify_email_screen.dart b/Sources/justMUSIC/lib/screens/verify_email_screen.dart index 6d964e9..63b0e16 100644 --- a/Sources/justMUSIC/lib/screens/verify_email_screen.dart +++ b/Sources/justMUSIC/lib/screens/verify_email_screen.dart @@ -75,7 +75,7 @@ class _VerifyEmailScreenState extends State { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", + e.toString(), style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), ), backgroundColor: Colors.red, @@ -144,6 +144,7 @@ class _VerifyEmailScreenState extends State { width: 600, child: LoginButton( callback: checkEmailVerified, + text: "Continuer", )), ), Align( From cb1fbb43db28ffb523bc3d28b3429a265885086f Mon Sep 17 00:00:00 2001 From: Emre Date: Tue, 15 Aug 2023 21:22:05 +0200 Subject: [PATCH 4/5] Forgot password done :white_check_mark: --- .../justMUSIC/lib/screens/login_screen.dart | 241 +++++++++++++----- 1 file changed, 171 insertions(+), 70 deletions(-) diff --git a/Sources/justMUSIC/lib/screens/login_screen.dart b/Sources/justMUSIC/lib/screens/login_screen.dart index 0cbddf1..10d3be2 100644 --- a/Sources/justMUSIC/lib/screens/login_screen.dart +++ b/Sources/justMUSIC/lib/screens/login_screen.dart @@ -1,4 +1,3 @@ -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -27,14 +26,18 @@ class _LoginScreenState extends State { handleLogin() async { if (_formKey.currentState!.validate()) { try { - await MyApp.userViewModel.login(_userMailTextField.text, _passwordTextField.text); + await MyApp.userViewModel + .login(_userMailTextField.text, _passwordTextField.text); Navigator.pushNamed(context, '/feed'); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - e.toString() ?? "", - style: GoogleFonts.plusJakartaSans(color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + e.toString(), + style: GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20.h), ), backgroundColor: Colors.red, ), @@ -63,19 +66,25 @@ class _LoginScreenState extends State { child: Form( key: _formKey, child: Column( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ Flexible( flex: 4, child: Padding( padding: EdgeInsets.only(bottom: 60), child: Column( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.end, children: [ Text( "Te revoilà!", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.w600, fontSize: 38.h), + style: + GoogleFonts.plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w600, + fontSize: 38.h), ), SizedBox( height: 10, @@ -84,8 +93,12 @@ class _LoginScreenState extends State { width: 230.w, child: Text( "Bon retour parmis nous tu nous as manqué!", - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.w400, fontSize: 20.h), + style: GoogleFonts + .plusJakartaSans( + color: Colors.white, + fontWeight: + FontWeight.w400, + fontSize: 20.h), textAlign: TextAlign.center, ), ), @@ -96,33 +109,51 @@ class _LoginScreenState extends State { Expanded( flex: 5, child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.center, children: [ TextFormField( controller: _userMailTextField, - keyboardAppearance: Brightness.dark, + keyboardAppearance: + Brightness.dark, validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || + value.isEmpty) { return 'entrez un email valide'; } return null; }, cursorColor: primaryColor, - keyboardType: TextInputType.emailAddress, - style: GoogleFonts.plusJakartaSans(color: primaryColor), + keyboardType: + TextInputType.emailAddress, + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), decoration: InputDecoration( focusedBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), - prefix: const Padding(padding: EdgeInsets.only(left: 20.0)), - suffix: const Padding(padding: EdgeInsets.only(left: 20.0)), + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: BorderRadius.all( + Radius.circular(10))), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), + suffix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), fillColor: bgTextField, filled: true, - errorStyle: TextStyle(fontSize: 9, height: 0.3), - focusColor: Color.fromRGBO(255, 255, 255, 0.30), + errorStyle: TextStyle( + fontSize: 9, height: 0.3), + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), enabledBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), + borderSide: + BorderSide(width: 1, color: strokeTextField), borderRadius: BorderRadius.all(Radius.circular(10))), hintText: 'Email', hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField)), @@ -132,31 +163,55 @@ class _LoginScreenState extends State { ), TextFormField( controller: _passwordTextField, - keyboardAppearance: Brightness.dark, + keyboardAppearance: + Brightness.dark, obscureText: passenable, validator: (value) { - if (value == null || value.isEmpty) { + if (value == null || + value.isEmpty) { return 'entrez un mot de passe valide'; } return null; }, cursorColor: primaryColor, - style: GoogleFonts.plusJakartaSans(color: primaryColor), + style: + GoogleFonts.plusJakartaSans( + color: primaryColor), decoration: InputDecoration( - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), + focusedBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), fillColor: bgTextField, filled: true, - focusColor: Color.fromRGBO(255, 255, 255, 0.30), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide(width: 1, color: strokeTextField), - borderRadius: BorderRadius.all(Radius.circular(10))), + focusColor: Color.fromRGBO( + 255, 255, 255, 0.30), + enabledBorder: + OutlineInputBorder( + borderSide: BorderSide( + width: 1, + color: + strokeTextField), + borderRadius: + BorderRadius.all( + Radius.circular( + 10))), hintText: 'Mot de passe', - hintStyle: GoogleFonts.plusJakartaSans(color: strokeTextField), - prefix: const Padding(padding: EdgeInsets.only(left: 20.0)), + hintStyle: + GoogleFonts.plusJakartaSans( + color: strokeTextField), + prefix: const Padding( + padding: EdgeInsets.only( + left: 20.0)), suffixIcon: Container( - padding: EdgeInsets.only(right: 10), + padding: EdgeInsets.only( + right: 10), margin: EdgeInsets.all(5), height: 3, child: InkWell( @@ -170,25 +225,40 @@ class _LoginScreenState extends State { }); }, // Image tapped - splashColor: Colors.white10, + splashColor: + Colors.white10, // Splash color over image child: Image( image: passenable - ? AssetImage("assets/images/show_icon.png") - : AssetImage("assets/images/hide_icon.png"), + ? AssetImage( + "assets/images/show_icon.png") + : AssetImage( + "assets/images/hide_icon.png"), height: 2, ), )), - errorStyle: TextStyle(fontSize: 9, height: 0.3), - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: Text( - "Mot de passe oublié?", - style: GoogleFonts.plusJakartaSans(color: Colors.white), + errorStyle: TextStyle( + fontSize: 9, height: 0.3), ), ), + GestureDetector( + behavior: + HitTestBehavior.translucent, + onTap: () { + Navigator.pushNamed( + context, '/forgetPassword'); + }, + child: Padding( + padding: + EdgeInsets.only(top: 10), + child: Text( + "Mot de passe oublié?", + style: GoogleFonts + .plusJakartaSans( + color: + Colors.white), + ), + )), SizedBox( height: defaultPadding, ), @@ -196,30 +266,44 @@ class _LoginScreenState extends State { width: 600, child: LoginButton( callback: handleLogin, + text: "Se connecter", )), Align( child: GestureDetector( - behavior: HitTestBehavior.translucent, + behavior: + HitTestBehavior.translucent, onTap: () { - Navigator.pushNamed(context, '/register'); + Navigator.pushNamed( + context, '/register'); }, child: Padding( - padding: EdgeInsets.only(top: 20), + padding: + EdgeInsets.only(top: 20), child: RichText( textAlign: TextAlign.center, text: TextSpan( - text: 'Pas encore inscrit?', - style: GoogleFonts.plusJakartaSans( - color: Colors.white, - fontWeight: FontWeight.w400, - fontSize: 15), + text: + 'Pas encore inscrit?', + style: GoogleFonts + .plusJakartaSans( + color: + Colors.white, + fontWeight: + FontWeight + .w400, + fontSize: 15), children: [ TextSpan( text: " S’inscire", - style: GoogleFonts.plusJakartaSans( - fontSize: 15, - fontWeight: FontWeight.w400, - color: primaryColor)), + style: GoogleFonts + .plusJakartaSans( + fontSize: + 15, + fontWeight: + FontWeight + .w400, + color: + primaryColor)), ], ), ), @@ -234,38 +318,55 @@ class _LoginScreenState extends State { child: Padding( padding: EdgeInsets.only(top: 20), child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ ConstrainedBox( - constraints: BoxConstraints(maxWidth: 600), + constraints: BoxConstraints( + maxWidth: 600), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + mainAxisAlignment: + MainAxisAlignment + .spaceEvenly, children: [ Expanded( child: Container( - color: Color(0xFF3D3D3D), + color: + Color(0xFF3D3D3D), height: 1, ), ), Padding( - padding: const EdgeInsets.only( - left: defaultPadding, right: defaultPadding), + padding: const EdgeInsets + .only( + left: + defaultPadding, + right: + defaultPadding), child: Text( 'Ou', - style: GoogleFonts.plusJakartaSans( - color: Colors.white, fontWeight: FontWeight.bold), + style: GoogleFonts + .plusJakartaSans( + color: Colors + .white, + fontWeight: + FontWeight + .bold), ), ), Expanded( child: Container( height: 1, - color: Color(0xFF3D3D3D), + color: + Color(0xFF3D3D3D), )), ], ), ), - SizedBox(height: defaultPadding), + SizedBox( + height: defaultPadding), SignInButton( Buttons.Google, text: "Login with Google", From 55294f9b8adbc7d6d8d449d8e21cc6ecf1a768c9 Mon Sep 17 00:00:00 2001 From: Lucas Delanier Date: Tue, 15 Aug 2023 22:59:06 +0200 Subject: [PATCH 5/5] perisst --- .../lib/components/historic_component.dart | 43 +++++++++ Sources/justMUSIC/lib/config/routes.dart | 19 ++++ .../lib/screens/capsule_historic_screen.dart | 94 +++++++++++++++++++ .../justMUSIC/lib/screens/profile_screen.dart | 8 +- 4 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 Sources/justMUSIC/lib/components/historic_component.dart create mode 100644 Sources/justMUSIC/lib/screens/capsule_historic_screen.dart diff --git a/Sources/justMUSIC/lib/components/historic_component.dart b/Sources/justMUSIC/lib/components/historic_component.dart new file mode 100644 index 0000000..7d0e758 --- /dev/null +++ b/Sources/justMUSIC/lib/components/historic_component.dart @@ -0,0 +1,43 @@ +import 'package:flutter/Material.dart'; + +class HistoricComponent extends StatefulWidget { + final int month; + const HistoricComponent({super.key, required this.month}); + + @override + State createState() => _HistoricComponentState(); +} + +class _HistoricComponentState extends State { + int getNumberOfDaysInMonth(int year, int month) { + if (month < 1 || month > 12) { + throw ArgumentError("Le numéro de mois doit être compris entre 1 et 12."); + } + + return DateTime(year, month + 1, 0).day; + } + + @override + Widget build(BuildContext context) { + return Wrap( + spacing: 14, + runSpacing: 14, + children: List.generate(getNumberOfDaysInMonth(DateTime.now().year, widget.month), (index) { + // Generate widgets + return LimitedBox( + maxWidth: MediaQuery.of(context).size.width - 40 / 5, + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xFF1E1E1E).withOpacity(0.7), + Color(0xFF1E1E1E).withOpacity(0), + ], begin: Alignment.topCenter, end: Alignment.bottomCenter), + borderRadius: BorderRadius.circular(3)), + height: 60, + width: 60, + ), + ); + }), + ); + } +} diff --git a/Sources/justMUSIC/lib/config/routes.dart b/Sources/justMUSIC/lib/config/routes.dart index a9f0df0..4b36efa 100644 --- a/Sources/justMUSIC/lib/config/routes.dart +++ b/Sources/justMUSIC/lib/config/routes.dart @@ -1,5 +1,6 @@ import 'package:flutter/Material.dart'; import 'package:justmusic/screens/add_friend_screen.dart'; +import 'package:justmusic/screens/capsule_historic_screen.dart'; import 'package:justmusic/screens/change_password_screen.dart'; import 'package:justmusic/screens/feed_screen.dart'; import 'package:justmusic/screens/profile_screen.dart'; @@ -90,3 +91,21 @@ Route routePassword() { }, ); } + +Route routeHistoric() { + return PageRouteBuilder( + pageBuilder: (context, animation, secondaryAnimation) => const CapsuleHistoricScreen(), + transitionsBuilder: (context, animation, secondaryAnimation, child) { + const begin = Offset(1.0, 0.0); + const end = Offset.zero; + const curve = Curves.ease; + + var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + ); +} diff --git a/Sources/justMUSIC/lib/screens/capsule_historic_screen.dart b/Sources/justMUSIC/lib/screens/capsule_historic_screen.dart new file mode 100644 index 0000000..d6fe2c7 --- /dev/null +++ b/Sources/justMUSIC/lib/screens/capsule_historic_screen.dart @@ -0,0 +1,94 @@ +import 'package:flutter/Material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +import '../components/historic_component.dart'; +import '../values/constants.dart'; + +class CapsuleHistoricScreen extends StatefulWidget { + const CapsuleHistoricScreen({super.key}); + + @override + State createState() => _CapsuleHistoricScreenState(); +} + +class _CapsuleHistoricScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: PreferredSize( + preferredSize: Size(double.infinity, 58), + child: Container( + height: double.infinity, + color: bgAppBar, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: defaultPadding), + child: Stack( + alignment: Alignment.centerLeft, + children: [ + GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context, true); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 10), + height: 30, + width: 30, + child: Image( + image: AssetImage("assets/images/return_icon.png"), + height: 8, + ), + )), + Align( + child: Text( + "Historique des capsules", + style: GoogleFonts.plusJakartaSans(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), + ), + ) + ], + ), + ), + ), + ), + body: Container( + width: double.infinity, + height: double.infinity, + color: bgColor, + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(decelerationRate: ScrollDecelerationRate.fast), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: settingPadding), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 30, bottom: 40), + child: SizedBox( + width: double.infinity, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + padding: EdgeInsets.symmetric(horizontal: 15), + constraints: BoxConstraints(maxWidth: 600), + child: Column( + children: [ + HistoricComponent( + month: DateTime.now().month, + ), + ], + ), + ) + ], + ), + ), + ), + ], + ), + ), + ), + ), + ); + } +} diff --git a/Sources/justMUSIC/lib/screens/profile_screen.dart b/Sources/justMUSIC/lib/screens/profile_screen.dart index ab9835d..54cf845 100644 --- a/Sources/justMUSIC/lib/screens/profile_screen.dart +++ b/Sources/justMUSIC/lib/screens/profile_screen.dart @@ -26,6 +26,10 @@ class _ProfileScreenState extends State { Navigator.pushNamed(context, '/welcome'); } + void _openHistoric() { + Navigator.of(context).push(routeHistoric()); + } + void _openDetail() { Navigator.of(context).push(routeUser(MyApp.userViewModel.userCurrent)); } @@ -107,10 +111,10 @@ class _ProfileScreenState extends State { label: 'Compte', action: _openDetail, ), - const SettingPartComponent( + SettingPartComponent( icon: JustMusicIcon.history, label: 'Historiques des capsules', - action: null, + action: _openHistoric, ), const SettingPartComponent( icon: JustMusicIcon.spotify,