diff --git a/README.md b/README.md index 8ddf340..5cb1409 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ TODO: Description ## Getting Started -This project is a starting point for a Flutter application. +### Web +We host a **[SmartFit Web](https://smartfit-9b86c.web.app/)** instance on Firebase. +TODO: Build -A few resources to get you started if this is your first Flutter project: +### Mobile +TODO: Installation and Build -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +## Docs +You can find **[here](https://codefirst.iut.uca.fr/documentation/SmartFit/SmartFit_Docs/docusaurus/)** +the docusaurus for SmartFit! diff --git a/assets/img/group.svg b/assets/img/group.svg new file mode 100644 index 0000000..36bd496 --- /dev/null +++ b/assets/img/group.svg @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/common_widget/container/workout_row.dart b/lib/common_widget/container/workout_row.dart index 7017f70..e4d5f85 100644 --- a/lib/common_widget/container/workout_row.dart +++ b/lib/common_widget/container/workout_row.dart @@ -4,83 +4,99 @@ import 'package:flutter/material.dart'; class WorkoutRow extends StatelessWidget { final Map wObj; + final bool isFirstActivity; // Ajouter la propriété isFirstActivity final VoidCallback onDelete; final VoidCallback onClick; - const WorkoutRow( - {Key? key, - required this.wObj, - required this.onDelete, - required this.onClick}) - : super(key: key); + + const WorkoutRow({ + Key? key, + required this.wObj, + required this.onDelete, + required this.onClick, + required this.isFirstActivity, + }) : super(key: key); @override Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2), - padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15), - decoration: BoxDecoration( - color: TColor.white, - borderRadius: BorderRadius.circular(20), - boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 2)], - ), - child: Row( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(30), - child: SvgPicture.asset( - wObj["image"].toString(), - width: 60, - height: 60, - fit: BoxFit.cover, - ), + return InkWell( + onTap: onClick, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 2), + decoration: BoxDecoration( + border: Border.all( + color: isFirstActivity + ? Color.fromARGB(255, 144, 252, 148) + : Colors.transparent, + width: 2.0, ), - const SizedBox(width: 15), - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + borderRadius: BorderRadius.circular(10), + ), + child: Material( + color: isFirstActivity + ? Color.fromARGB(255, 240, 255, 240) + : Colors.transparent, + child: InkWell( + borderRadius: + BorderRadius.circular(10), // Utiliser le même borderRadius + splashColor: Color.fromARGB(255, 42, 94, 44) + .withOpacity(0.3), // Couleur du fond au survol + onTap: onClick, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 15), + child: Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: SvgPicture.asset( + wObj["image"].toString(), + width: 60, + height: 60, + fit: BoxFit.cover, + ), + ), + const SizedBox(width: 15), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + wObj["nomActivite"].toString(), + style: TextStyle( + color: TColor.black, + fontSize: 12, + ), + ), + ], + ), + ), + Column( + crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - wObj["nomActivite"].toString(), - style: TextStyle( - color: TColor.black, - fontSize: 12, + IconButton( + onPressed: onClick, + icon: Image.asset( + "assets/img/next_icon.png", + width: 30, + height: 30, + fit: BoxFit.contain, + ), + ), + IconButton( + onPressed: onDelete, + icon: Image.asset( + "assets/img/corbeille.png", + width: 30, + height: 30, + fit: BoxFit.contain, ), ), ], ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - IconButton( - onPressed: onClick, - icon: Image.asset( - "assets/img/next_icon.png", - width: 30, - height: 30, - fit: BoxFit.contain, - ), - ), - IconButton( - // ici pour remove l'activité - onPressed: onDelete, - icon: Image.asset( - "assets/img/corbeille.png", - width: 30, - height: 30, - fit: BoxFit.contain, - ), - ), - ], - ), - ], + ], + ), ), ), - ], + ), ), ); } diff --git a/lib/view/activity/activity.dart b/lib/view/activity/activity.dart index dac64eb..5ada537 100644 --- a/lib/view/activity/activity.dart +++ b/lib/view/activity/activity.dart @@ -4,27 +4,21 @@ import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/view/activity/mobile/mobile_Activity_view.dart'; import 'package:smartfit_app_mobile/view/activity/web/web_Activity_view.dart'; import 'package:flutter/material.dart'; +import 'package:smartfit_app_mobile/view/home/no_activity_view.dart'; class Activity extends StatelessWidget { const Activity({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - if (context.watch().listActivity.isEmpty) { - return const Scaffold( - body: Column( - children: [ - Text("C'est vide"), - Text("C'est vide"), - Text("C'est vide"), - Text("C'est vide") - ], - )); - } else { - return ScreenTypeLayout.builder( - mobile: (_) => const MobileActivity(), - desktop: (_) => const WebActivity(), - ); - } + return context.watch().listActivity.isEmpty + ? ScreenTypeLayout.builder( + mobile: (_) => const NoActivityView(), + desktop: (_) => const NoActivityView(), + ) + : ScreenTypeLayout.builder( + mobile: (_) => const MobileActivity(), + desktop: (_) => const WebActivity(), + ); } } diff --git a/lib/view/activity/mobile/mobile_list_activity.dart b/lib/view/activity/mobile/mobile_list_activity.dart index 5f8a7f0..307110f 100644 --- a/lib/view/activity/mobile/mobile_list_activity.dart +++ b/lib/view/activity/mobile/mobile_list_activity.dart @@ -1,16 +1,16 @@ import 'package:file_picker/file_picker.dart'; +import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smartfit_app_mobile/common/colo_extension.dart'; +import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/modele/api/i_data_strategy.dart'; import 'package:smartfit_app_mobile/modele/api/request_api.dart'; -import 'package:smartfit_app_mobile/modele/activity.dart'; import 'package:smartfit_app_mobile/modele/manager_file.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/common_widget/container/workout_row.dart'; -import 'package:flutter/material.dart'; class MobileListActivity extends StatefulWidget { - const MobileListActivity({super.key}); + const MobileListActivity({Key? key}) : super(key: key); @override State createState() => _MobileListActivity(); @@ -38,6 +38,7 @@ class _MobileListActivity extends State { @override Widget build(BuildContext context) { var media = MediaQuery.of(context).size; + int firstActivityIndex = 0; return Scaffold( backgroundColor: TColor.white, @@ -96,20 +97,30 @@ class _MobileListActivity extends State { ), ) ]) - : ListView.builder( - padding: EdgeInsets.zero, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: Provider.of(context, listen: true) - .listActivity - .length, - itemBuilder: (context, index) { - var activityObj = - Provider.of(context, listen: true) - .listActivity[index] as ActivityOfUser; - var activityMap = activityObj.toMap(); - return InkWell( + : Material( + color: Colors.transparent, + child: ListView.builder( + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: Provider.of(context, listen: true) + .listActivity + .length, + itemBuilder: (context, index) { + var activityObj = + Provider.of(context, listen: true) + .listActivity[index] as ActivityOfUser; + var activityMap = activityObj.toMap(); + + bool isFirstActivity = false; + if (index == firstActivityIndex) { + isFirstActivity = true; + } + return InkWell( onTap: () { + setState(() { + firstActivityIndex = index; + }); Provider.of(context, listen: false) .removeActivity(activityObj); Provider.of(context, listen: false) @@ -127,8 +138,12 @@ class _MobileListActivity extends State { Provider.of(context, listen: false) .insertActivity(0, activityObj); }, - )); - }), + isFirstActivity: isFirstActivity, + ), + ); + }, + ), + ), SizedBox( height: media.width * 0.1, ), diff --git a/lib/view/activity/web/web_list_activity.dart b/lib/view/activity/web/web_list_activity.dart index cebb8c8..aef0e23 100644 --- a/lib/view/activity/web/web_list_activity.dart +++ b/lib/view/activity/web/web_list_activity.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:smartfit_app_mobile/modele/manager_file.dart'; @@ -23,20 +22,9 @@ class WebListActivity extends StatefulWidget { class _WebListActivityState extends State { FilePickerResult? result; IDataStrategy strategy = RequestApi(); + int firstActivityIndex = 0; //late File x = File(file.path); - List parseFile(Uint8List bytes) { - String csvString = - utf8.decode(bytes); // Convertit les bytes en chaîne UTF-8 - List lines = - LineSplitter.split(csvString).toList(); // Sépare les lignes - - for (String line in lines) { - print(line); // Affiche chaque ligne du fichier - } - - return lines; // Ou retournez les lignes du fichier - } void readFile(html.File file) async { ManagerFile x = ManagerFile(); @@ -117,20 +105,30 @@ class _WebListActivityState extends State { ), ) ]) - : ListView.builder( - padding: EdgeInsets.zero, - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: Provider.of(context, listen: true) - .listActivity - .length, - itemBuilder: (context, index) { - var activityObj = - Provider.of(context, listen: true) - .listActivity[index] as ActivityOfUser; - var activityMap = activityObj.toMap(); - return InkWell( + : Material( + color: Colors.transparent, + child: ListView.builder( + padding: EdgeInsets.zero, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: Provider.of(context, listen: true) + .listActivity + .length, + itemBuilder: (context, index) { + var activityObj = + Provider.of(context, listen: true) + .listActivity[index] as ActivityOfUser; + var activityMap = activityObj.toMap(); + + bool isFirstActivity = false; + if (index == firstActivityIndex) { + isFirstActivity = true; + } + return InkWell( onTap: () { + setState(() { + firstActivityIndex = index; + }); Provider.of(context, listen: false) .removeActivity(activityObj); Provider.of(context, listen: false) @@ -148,8 +146,12 @@ class _WebListActivityState extends State { Provider.of(context, listen: false) .insertActivity(0, activityObj); }, - )); - }), + isFirstActivity: isFirstActivity, + ), + ); + }, + ), + ), SizedBox( height: media.width * 0.1, ), diff --git a/lib/view/home/home_view.dart b/lib/view/home/home_view.dart index 4695ac0..c8d2ba9 100644 --- a/lib/view/home/home_view.dart +++ b/lib/view/home/home_view.dart @@ -3,6 +3,7 @@ import 'package:provider/provider.dart'; import 'package:responsive_builder/responsive_builder.dart'; import 'package:smartfit_app_mobile/modele/user.dart'; import 'package:smartfit_app_mobile/view/home/mobile/mobile_homeview.dart'; +import 'package:smartfit_app_mobile/view/home/no_activity_view.dart'; import 'package:smartfit_app_mobile/view/home/web/web_homeview.dart'; class HomeView extends StatefulWidget { @@ -15,21 +16,14 @@ class HomeView extends StatefulWidget { class _HomeViewState extends State { @override Widget build(BuildContext context) { - if (context.watch().listActivity.isEmpty) { - return const Scaffold( - body: Column( - children: [ - Text("C'est vide"), - Text("C'est vide"), - Text("C'est vide"), - Text("C'est vide") - ], - )); - } else { - return ScreenTypeLayout.builder( - mobile: (_) => const MobileHomeView(), - desktop: (_) => const WebHomeView(), - ); - } + return context.watch().listActivity.isEmpty + ? ScreenTypeLayout.builder( + mobile: (_) => const NoActivityView(), + desktop: (_) => const NoActivityView(), + ) + : ScreenTypeLayout.builder( + mobile: (_) => const MobileHomeView(), + desktop: (_) => const WebHomeView(), + ); } } diff --git a/lib/view/home/no_activity_view.dart b/lib/view/home/no_activity_view.dart new file mode 100644 index 0000000..698b7ee --- /dev/null +++ b/lib/view/home/no_activity_view.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +import '../../common/colo_extension.dart'; + +class NoActivityView extends StatefulWidget { + const NoActivityView({super.key}); + + @override + State createState() => _NoActivityViewState(); +} + +class _NoActivityViewState extends State { + @override + Widget build(BuildContext context) { + var media = MediaQuery.of(context).size; + return Scaffold( + backgroundColor: TColor.white, + body: SafeArea( + child: Center( + // Utilisation du widget Center pour centrer verticalement + child: Container( + width: media.width, + padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 25), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize + .min, // Utilisation de MainAxisSize.min pour que la colonne prenne la hauteur minimale nécessaire + children: [ + SizedBox( + height: media.height * 0.1, + ), + SvgPicture.asset( + "assets/img/group.svg", + width: media.width * 0.75, + height: media.height * 0.4, + fit: BoxFit.fitWidth, + ), + SizedBox( + height: media.height * 0.1, + ), + Text( + "Pas d'activité sélectionnée", + style: TextStyle( + color: TColor.black, + fontSize: 20, + fontWeight: FontWeight.w700, + ), + ), + Text( + "Veuillez sélectionner une activité en cliquant sur la loupe ci-dessous", + textAlign: TextAlign.center, + style: TextStyle(color: TColor.gray, fontSize: 12), + ), + Spacer(), + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/view/main_tab/main_tab_view.dart b/lib/view/main_tab/main_tab_view.dart index 28641a4..44b7b75 100644 --- a/lib/view/main_tab/main_tab_view.dart +++ b/lib/view/main_tab/main_tab_view.dart @@ -17,7 +17,7 @@ class MainTabView extends StatefulWidget { class _MainTabViewState extends State { int selectTab = 0; final PageStorageBucket pageBucket = PageStorageBucket(); - Widget currentTab = const HomeView(); + Widget currentTab = const ListActivity(); @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/view/profile/change_password.dart b/lib/view/profile/change_password.dart new file mode 100644 index 0000000..fcd0213 --- /dev/null +++ b/lib/view/profile/change_password.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; +import 'package:smartfit_app_mobile/common_widget/text_field/round_text_field.dart'; + +import '../../common/colo_extension.dart'; + +class ChangePasswordView extends StatefulWidget { + const ChangePasswordView({super.key}); + + @override + State createState() => _ChangeUsernameViewState(); +} + +class _ChangeUsernameViewState extends State { + final TextEditingController controllerTextEmail = TextEditingController(); + final TextEditingController controllerTextPassword = TextEditingController(); + + + @override + Widget build(BuildContext context) { + var media = MediaQuery.of(context).size; + + return Scaffold( + appBar: AppBar( + backgroundColor: TColor.white, + centerTitle: true, + elevation: 0, + leading: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Container( + margin: const EdgeInsets.all(8), + height: 40, + width: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: TColor.lightGray, + borderRadius: BorderRadius.circular(10)), + child: Image.asset( + "assets/img/black_btn.png", + width: 15, + height: 15, + fit: BoxFit.contain, + ), + + ), + + ), + title: Text( + "Changer son Mot de passe", + style: TextStyle( + color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), + ), + ), + backgroundColor: TColor.white, + body: Column( + children: [ + SizedBox( + height: media.width * 0.05, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 200.0), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + RoundTextField( + hitText: "Ancien mot de passe", + icon: "assets/img/lock.svg", + keyboardType: TextInputType.text, + controller: controllerTextEmail, + ), + SizedBox(height: media.width * 0.04), + RoundTextField( + controller: controllerTextPassword, + hitText: "Nouveau mot de passe", + icon: "assets/img/lock.svg", + obscureText: true, + rigtIcon: TextButton( + onPressed: () {}, + child: Container( + alignment: Alignment.center, + width: 20, + height: 20, + child: SvgPicture.asset( + "assets/img/show_password.svg", + width: 20, + height: 20, + fit: BoxFit.contain, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/view/profile/change_username.dart b/lib/view/profile/change_username.dart new file mode 100644 index 0000000..ad71734 --- /dev/null +++ b/lib/view/profile/change_username.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:smartfit_app_mobile/common_widget/button/round_button.dart'; +import 'package:smartfit_app_mobile/common_widget/text_field/round_text_field.dart'; + +import '../../common/colo_extension.dart'; + +class ChangeUsernameView extends StatefulWidget { + const ChangeUsernameView({super.key}); + + @override + State createState() => _ChangeUsernameViewState(); +} + +class _ChangeUsernameViewState extends State { + final TextEditingController controllerTextEmail = TextEditingController(); + final TextEditingController controllerTextPassword = TextEditingController(); + + @override + Widget build(BuildContext context) { + var media = MediaQuery.of(context).size; + + return Scaffold( + appBar: AppBar( + backgroundColor: TColor.white, + centerTitle: true, + elevation: 0, + leading: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Container( + margin: const EdgeInsets.all(8), + height: 40, + width: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: TColor.lightGray, + borderRadius: BorderRadius.circular(10)), + child: Image.asset( + "assets/img/black_btn.png", + width: 15, + height: 15, + fit: BoxFit.contain, + ), + ), + ), + title: Text( + "Changer son pseudo", + style: TextStyle( + color: TColor.black, fontSize: 16, fontWeight: FontWeight.w700), + ), + ), + backgroundColor: TColor.white, + body: Column( + children: [ + SizedBox( + height: media.width * 0.05, + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 200.0), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(15), + ), + child: Column( + children: [ + RoundTextField( + hitText: "Nouveau pseudo", + icon: "assets/img/email.svg", + keyboardType: TextInputType.text, + controller: controllerTextEmail, + ), + SizedBox(height: media.width * 0.04), + RoundButton(title: "Confirmer", onPressed: () {}), + ], + ), + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/view/profile/web/web_profile_view.dart b/lib/view/profile/web/web_profile_view.dart index a58a07d..7da5b1d 100644 --- a/lib/view/profile/web/web_profile_view.dart +++ b/lib/view/profile/web/web_profile_view.dart @@ -4,6 +4,8 @@ import 'package:smartfit_app_mobile/common/colo_extension.dart'; import 'package:smartfit_app_mobile/common_widget/button/round_button.dart'; import 'package:smartfit_app_mobile/common_widget/setting_row.dart'; import 'package:smartfit_app_mobile/common_widget/title_subtitle_cell.dart'; +import 'package:smartfit_app_mobile/view/profile/change_password.dart'; +import 'package:smartfit_app_mobile/view/profile/change_username.dart'; class WebProfileView extends StatefulWidget { const WebProfileView({super.key}); @@ -18,9 +20,14 @@ class _WebProfileView extends State { List accountArr = [ { "image": "assets/img/p_personal.png", - "name": "Données personnelles", + "name": "Changer son pseudo", "tag": "1" }, + { + "image": "assets/img/p_personal.png", + "name": "Changer son mot de passe", + "tag": "2" + }, ]; List otherArr = [ @@ -190,14 +197,32 @@ class _WebProfileView extends State { shrinkWrap: true, itemCount: accountArr.length, itemBuilder: (context, index) { - var iObj = accountArr[index] as Map? ?? {}; + var iObj = accountArr[index]; return SettingRow( - icon: iObj["image"].toString(), - title: iObj["name"].toString(), - onPressed: () {}, + icon: iObj["image"]!, + title: iObj["name"]!, + onPressed: () { + if (iObj["tag"] == "1") { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChangeUsernameView(), + ), + ); + } else if (iObj["tag"] == "2") { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => ChangePasswordView(), + ), + ); + } else { + // Autre logique si nécessaire pour d'autres éléments de la liste + } + }, ); }, - ) + ), ], ), ),