diff --git a/frontend/app_student/assets/fonts/arial.ttf b/frontend/app_student/assets/fonts/arial.ttf new file mode 100644 index 0000000..ad7d8ea Binary files /dev/null and b/frontend/app_student/assets/fonts/arial.ttf differ diff --git a/frontend/app_student/assets/images/3il-icon-blue.png b/frontend/app_student/assets/images/3il-icon-blue.png new file mode 100644 index 0000000..cb7e5b7 Binary files /dev/null and b/frontend/app_student/assets/images/3il-icon-blue.png differ diff --git a/frontend/app_student/assets/images/3il-icon-white.png b/frontend/app_student/assets/images/3il-icon-white.png new file mode 100644 index 0000000..0983585 Binary files /dev/null and b/frontend/app_student/assets/images/3il-icon-white.png differ diff --git a/frontend/app_student/assets/images/3il-icon.png b/frontend/app_student/assets/images/3il-icon.png new file mode 100644 index 0000000..5e45b2e Binary files /dev/null and b/frontend/app_student/assets/images/3il-icon.png differ diff --git a/frontend/app_student/assets/images/3il-logo-white.jpeg b/frontend/app_student/assets/images/3il-logo-white.jpeg new file mode 100644 index 0000000..2a2c509 Binary files /dev/null and b/frontend/app_student/assets/images/3il-logo-white.jpeg differ diff --git a/frontend/app_student/assets/images/eating.svg b/frontend/app_student/assets/images/eating.svg new file mode 100644 index 0000000..096cb2c --- /dev/null +++ b/frontend/app_student/assets/images/eating.svg @@ -0,0 +1,21 @@ + + + + + \ No newline at end of file diff --git a/frontend/app_student/assets/images/school.svg b/frontend/app_student/assets/images/school.svg new file mode 100644 index 0000000..09f871f --- /dev/null +++ b/frontend/app_student/assets/images/school.svg @@ -0,0 +1,49 @@ + + \ No newline at end of file diff --git a/frontend/app_student/assets/images/teams.svg b/frontend/app_student/assets/images/teams.svg new file mode 100644 index 0000000..b61b0cd --- /dev/null +++ b/frontend/app_student/assets/images/teams.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/app_student/flutter_native_splash.yaml b/frontend/app_student/flutter_native_splash.yaml new file mode 100644 index 0000000..98a9f47 --- /dev/null +++ b/frontend/app_student/flutter_native_splash.yaml @@ -0,0 +1,143 @@ +flutter_native_splash: + # This package generates native code to customize Flutter's default white native splash screen + # with background color and splash image. + # Customize the parameters below, and run the following command in the terminal: + # dart run flutter_native_splash:create + # To restore Flutter's default white splash screen, run the following command in the terminal: + # dart run flutter_native_splash:remove + + # IMPORTANT NOTE: These parameter do not affect the configuration of Android 12 and later, which + # handle splash screens differently that prior versions of Android. Android 12 and later must be + # configured specifically in the android_12 section below. + + # color or background_image is the only required parameter. Use color to set the background + # of your splash screen to a solid color. Use background_image to set the background of your + # splash screen to a png image. This is useful for gradients. The image will be stretch to the + # size of the app. Only one parameter can be used, color and background_image cannot both be set. + color: "#42a5f5" + #background_image: "assets/background.png" + + # Optional parameters are listed below. To enable a parameter, uncomment the line by removing + # the leading # character. + + # The image parameter allows you to specify an image used in the splash screen. It must be a + # png file and should be sized for 4x pixel density. + #image: assets/images/3il-logo-white.jpeg + + # The branding property allows you to specify an image used as branding in the splash screen. + # It must be a png file. It is supported for Android, iOS and the Web. For Android 12, + # see the Android 12 section below. + branding: assets/images/3il-logo-white.jpeg + # To position the branding image at the bottom of the screen you can use bottom, bottomRight, + # and bottomLeft. The default values is bottom if not specified or specified something else. + #branding_mode: bottom + + # The color_dark, background_image_dark, image_dark, branding_dark are parameters that set the background + # and image when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. If the image_dark parameter is specified, color_dark or + # background_image_dark must be specified. color_dark and background_image_dark cannot both be + # set. + #color_dark: "#042a49" + #background_image_dark: "assets/dark-background.png" + #image_dark: assets/splash-invert.png + #branding_dark: assets/dart_dark.png + + # From Android 12 onwards, the splash screen is handled differently than in previous versions. + # Please visit https://developer.android.com/guide/topics/ui/splash-screen + # Following are specific parameters for Android 12+. + android_12: + # The image parameter sets the splash screen icon image. If this parameter is not specified, + # the app's launcher icon will be used instead. + # Please note that the splash screen will be clipped to a circle on the center of the screen. + # App icon with an icon background: This should be 960×960 pixels, and fit within a circle + # 640 pixels in diameter. + # App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle + # 768 pixels in diameter. + #image: assets/android12splash.png + + # Splash screen background color. + #color: "#42a5f5" + + # App icon background color. + #icon_background_color: "#111111" + + # The branding property allows you to specify an image used as branding in the splash screen. + branding: assets/images/3il-logo-white.jpeg + + # The image_dark, color_dark, icon_background_color_dark, and branding_dark set values that + # apply when the device is in dark mode. If they are not specified, the app will use the + # parameters from above. + #image_dark: assets/android12splash-invert.png + #color_dark: "#042a49" + #icon_background_color_dark: "#eeeeee" + + # The android, ios and web parameters can be used to disable generating a splash screen on a given + # platform. + #android: false + #ios: false + #web: false + + # Platform specific images can be specified with the following parameters, which will override + # the respective parameter. You may specify all, selected, or none of these parameters: + #color_android: "#42a5f5" + #color_dark_android: "#042a49" + #color_ios: "#42a5f5" + #color_dark_ios: "#042a49" + #color_web: "#42a5f5" + #color_dark_web: "#042a49" + #image_android: assets/splash-android.png + #image_dark_android: assets/splash-invert-android.png + #image_ios: assets/splash-ios.png + #image_dark_ios: assets/splash-invert-ios.png + #image_web: assets/splash-web.gif + #image_dark_web: assets/splash-invert-web.gif + #background_image_android: "assets/background-android.png" + #background_image_dark_android: "assets/dark-background-android.png" + #background_image_ios: "assets/background-ios.png" + #background_image_dark_ios: "assets/dark-background-ios.png" + #background_image_web: "assets/background-web.png" + #background_image_dark_web: "assets/dark-background-web.png" + #branding_android: assets/brand-android.png + #branding_dark_android: assets/dart_dark-android.png + #branding_ios: assets/brand-ios.png + #branding_dark_ios: assets/dart_dark-ios.png + #branding_web: assets/brand-web.gif + #branding_dark_web: assets/dart_dark-web.gif + + # The position of the splash image can be set with android_gravity, ios_content_mode, and + # web_image_mode parameters. All default to center. + # + # android_gravity can be one of the following Android Gravity (see + # https://developer.android.com/reference/android/view/Gravity): bottom, center, + # center_horizontal, center_vertical, clip_horizontal, clip_vertical, end, fill, fill_horizontal, + # fill_vertical, left, right, start, or top. + #android_gravity: center + # + # ios_content_mode can be one of the following iOS UIView.ContentMode (see + # https://developer.apple.com/documentation/uikit/uiview/contentmode): scaleToFill, + # scaleAspectFit, scaleAspectFill, center, top, bottom, left, right, topLeft, topRight, + # bottomLeft, or bottomRight. + #ios_content_mode: center + # + # web_image_mode can be one of the following modes: center, contain, stretch, and cover. + #web_image_mode: center + + # The screen orientation can be set in Android with the android_screen_orientation parameter. + # Valid parameters can be found here: + # https://developer.android.com/guide/topics/manifest/activity-element#screen + #android_screen_orientation: sensorLandscape + + # To hide the notification bar, use the fullscreen parameter. Has no effect in web since web + # has no notification bar. Defaults to false. + # NOTE: Unlike Android, iOS will not automatically show the notification bar when the app loads. + # To show the notification bar, add the following code to your Flutter app: + # WidgetsFlutterBinding.ensureInitialized(); + # SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: [SystemUiOverlay.bottom, SystemUiOverlay.top], ); + #fullscreen: true + + # If you have changed the name(s) of your info.plist file(s), you can specify the filename(s) + # with the info_plist_files parameter. Remove only the # characters in the three lines below, + # do not remove any spaces: + #info_plist_files: + # - 'ios/Runner/Info-Debug.plist' + # - 'ios/Runner/Info-Release.plist' \ No newline at end of file diff --git a/frontend/app_student/l10n.yaml b/frontend/app_student/l10n.yaml new file mode 100644 index 0000000..35d81e9 --- /dev/null +++ b/frontend/app_student/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/l10n +template-arb-file: app_fr.arb +output-localization-file: app_localizations.dart \ No newline at end of file diff --git a/frontend/app_student/lib/api/users/repositories/user_repository.dart b/frontend/app_student/lib/api/users/repositories/user_repository.dart new file mode 100644 index 0000000..6f3d76a --- /dev/null +++ b/frontend/app_student/lib/api/users/repositories/user_repository.dart @@ -0,0 +1,57 @@ +import 'package:app_student/api/users/models/user_model.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../entities/user_entity.dart'; + +class UserRepository { + Future getUser() async { + final SharedPreferences prefs = await SharedPreferences.getInstance(); + + String? ine = prefs.getString('ine'); + String? name = prefs.getString('name'); + String? birthDate = prefs.getString('birthDate'); + String? className = prefs.getString('className'); + if (ine != null && name != null && birthDate != null) { + return UserModel( + entity: UserEntity( + ine: ine, + firstName: name, + birthDate: DateTime.parse(birthDate), + className: className, + ), + ); + } else { + throw Exception('Utilisateur non trouvé'); + } + } + + Future saveUserDetails( + String ine, String name, String birthDate, String className) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + UserModel( + entity: UserEntity( + ine: ine, + firstName: name, + birthDate: DateTime.parse(birthDate), + className: className, + ), + ); + await prefs.setString('ine', ine); + await prefs.setString('name', name); + await prefs.setString('birthDate', birthDate); + await prefs.setString('className', className); + } + + Future deleteUser() async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.remove('ine'); + await prefs.remove('name'); + await prefs.remove('birthDate'); + await prefs.remove('className'); + } + + Future saveUserClass(String className) async { + SharedPreferences prefs = await SharedPreferences.getInstance(); + await prefs.setString('className', className); + } +} diff --git a/frontend/app_student/lib/class_groups/views/class_group_page.dart b/frontend/app_student/lib/class_groups/views/class_group_page.dart new file mode 100644 index 0000000..9b4141d --- /dev/null +++ b/frontend/app_student/lib/class_groups/views/class_group_page.dart @@ -0,0 +1,75 @@ +import 'package:app_student/api/class_groups/repositories/class_group_repository.dart'; +import 'package:app_student/class_groups/cubit/class_group_cubit.dart'; +import 'package:app_student/class_groups/views/widgets/card_list.dart'; +import 'package:app_student/class_groups/views/widgets/header/header_logo.dart'; +import 'package:app_student/class_groups/views/widgets/header/header_text.dart'; +import 'package:app_student/class_groups/views/widgets/header/header_title.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:go_router/go_router.dart'; + +import '../../api/users/models/user_model.dart'; +import '../../api/users/repositories/user_repository.dart'; + +class ClassGroupPage extends StatelessWidget { + const ClassGroupPage({super.key}); + + @override + Widget build(BuildContext context) { + final classRepository = + RepositoryProvider.of(context); + final userRepository = RepositoryProvider.of(context); + final classCubit = ClassGroupCubit( + classRepository: classRepository, userRepository: userRepository); + + return BlocProvider( + create: (context) => classCubit..fetchClasses(), + child: FutureBuilder( + future: context.read().getConnectedUser(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const Center(child: CircularProgressIndicator()); + } else if (snapshot.hasError) { + return Center( + child: Text(AppLocalizations.of(context)! + .genericError(snapshot.error.toString()))); + } else { + final user = snapshot.data; + return Scaffold( + body: BlocBuilder( + builder: (context, state) { + if (state is ClassGroupLoading) { + return const Center(child: CircularProgressIndicator()); + } else if (state is ClassGroupSelected) { + WidgetsBinding.instance.addPostFrameCallback((_) { + context.go('/schedule'); + }); + return const SizedBox.shrink(); + } else if (state is ClassGroupLoaded) { + return Column( + children: [ + const HeaderLogo(), + HeaderTitle(AppLocalizations.of(context)! + .classSelectionTitle(user!.name)), + HeaderText(AppLocalizations.of(context)! + .classSelectionSubtitle), + Expanded( + child: CardList(classesList: state.classes), + ), + ], + ); + } else if (state is ClassGroupError) { + return Center(child: Text(state.message)); + } else { + return const SizedBox.shrink(); + } + }, + ), + ); + } + }, + ), + ); + } +} diff --git a/frontend/app_student/lib/class_groups/views/widgets/card_list.dart b/frontend/app_student/lib/class_groups/views/widgets/card_list.dart new file mode 100644 index 0000000..c20ecb0 --- /dev/null +++ b/frontend/app_student/lib/class_groups/views/widgets/card_list.dart @@ -0,0 +1,31 @@ +import 'package:app_student/api/class_groups/models/class_group_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../../cubit/class_group_cubit.dart'; + +class CardList extends StatelessWidget { + final List classesList; + + const CardList({super.key, required this.classesList}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + itemCount: classesList.length, + itemBuilder: (context, index) { + return Card( + margin: const EdgeInsets.only(left: 25.0, right: 25.0, top: 10.0), + child: ListTile( + title: Text( + classesList[index].name, + ), + onTap: () { + context.read().saveClass(classesList[index]); + }, + ), + ); + }, + ); + } +} diff --git a/frontend/app_student/lib/class_groups/views/widgets/header/header_logo.dart b/frontend/app_student/lib/class_groups/views/widgets/header/header_logo.dart new file mode 100644 index 0000000..3aa3ab3 --- /dev/null +++ b/frontend/app_student/lib/class_groups/views/widgets/header/header_logo.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +class HeaderLogo extends StatelessWidget { + const HeaderLogo({super.key}); + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: const Color(0xFF005067), + toolbarHeight: 70.0, + title: Opacity( + opacity: 0.5, + child: Image.asset( + 'assets/images/3il-icon-white.png', + fit: BoxFit.contain, + ), + ), + centerTitle: true, + ); + } +} diff --git a/frontend/app_student/lib/class_groups/views/widgets/header/header_text.dart b/frontend/app_student/lib/class_groups/views/widgets/header/header_text.dart new file mode 100644 index 0000000..ff6d4b2 --- /dev/null +++ b/frontend/app_student/lib/class_groups/views/widgets/header/header_text.dart @@ -0,0 +1,25 @@ +import 'package:flutter/cupertino.dart'; + +class HeaderText extends StatelessWidget { + final String content; + + const HeaderText(this.content, {super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(top: 5.0, left: 25.0), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + content, + style: const TextStyle( + fontSize: 18.0, + fontFamily: 'Arial', + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} diff --git a/frontend/app_student/lib/class_groups/views/widgets/header/header_title.dart b/frontend/app_student/lib/class_groups/views/widgets/header/header_title.dart new file mode 100644 index 0000000..35f3e0a --- /dev/null +++ b/frontend/app_student/lib/class_groups/views/widgets/header/header_title.dart @@ -0,0 +1,25 @@ +import 'package:flutter/cupertino.dart'; + +class HeaderTitle extends StatelessWidget { + final String content; + + const HeaderTitle(this.content, {super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(top: 20.0, left: 25.0, bottom: 2), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + content, + style: const TextStyle( + fontSize: 34.0, + fontFamily: 'Arial', + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} diff --git a/frontend/app_student/lib/generated/assets.dart b/frontend/app_student/lib/generated/assets.dart new file mode 100644 index 0000000..670f1c5 --- /dev/null +++ b/frontend/app_student/lib/generated/assets.dart @@ -0,0 +1,9 @@ +///This file is automatically generated. DO NOT EDIT, all your changes would be lost. +class Assets { + Assets._(); + + static const String images3ilLogo = 'assets/images/3il-logo.jpg'; + static const String imagesCalendar = 'assets/images/calendar.svg'; + static const String imagesDisconnect = 'assets/images/disconnect.svg'; + static const String imagesProfil = 'assets/images/profil.svg'; +} diff --git a/frontend/app_student/lib/l10n/app_fr.arb b/frontend/app_student/lib/l10n/app_fr.arb new file mode 100644 index 0000000..57e0c37 --- /dev/null +++ b/frontend/app_student/lib/l10n/app_fr.arb @@ -0,0 +1,72 @@ +{ + "error404": "Page non trouvée {pageUri}", + "@error404": { + "description": "Message d'erreur pour une page non trouvée", + "placeholders": { + "pageUri": { + "type": "String", + "example": "/login" + } + } + }, + "genericError": "Une erreur est survenue", + "@genericError": { + "description": "Message d'erreur générique", + "placeholders": { + "error": { + "type": "String", + "example": "Une erreur est survenue" + } + } + }, + "loginButton": "Connexion", + "@loginButton": { + "description": "Texte du bouton de connexion" + }, + "loginFirstNameLabel": "Prénom", + "@loginFirstName": { + "description": "Texte du label pour le prénom" + }, + "loginFirstNameHint": "Entrez votre prénom", + "@loginFirstNameHint": { + "description": "Texte de l'attribut placeholder pour le prénom" + }, + "loginIneLabel": "INE", + "@loginIneLabel": { + "description": "Texte du label pour le numéro INE" + }, + "loginIneHint": "Entrez votre numéro INE", + "@loginIneHint": { + "description": "Texte de l'attribut placeholder pour le numéro INE" + }, + "loginBirthDateLabel": "Date de naissance", + "@loginBirthDateLabel": { + "description": "Texte du label pour la date de naissance" + }, + "loginWelcomeTitle": "Bonjour :)", + "@loginWelcomeTitle": { + "description": "Texte d'accueil de la page de connexion" + }, + "loginWelcomeTitleError": "Oops, ca va aller", + "@loginWelcomeTitleError": { + "description": "Texte d'erreur d'accueil de la page de connexion" + }, + "loginFieldError": "Veuillez remplir tous les champs", + "@loginFieldError": { + "description": "Message d'erreur pour les champs de connexion" + }, + "classSelectionTitle": "Salut {firstName} !", + "@classSelectionTitle": { + "description": "Texte d'accueil de la page de sélection de classe", + "placeholders": { + "firstName": { + "type": "String", + "example": "John" + } + } + }, + "classSelectionSubtitle": "Sélectionne ta classe", + "@classSelectionSubtitle": { + "description": "Texte de sous-titre de la page de sélection de classe" + } +} \ No newline at end of file diff --git a/frontend/app_student/lib/routes.dart b/frontend/app_student/lib/routes.dart new file mode 100644 index 0000000..f0417d9 --- /dev/null +++ b/frontend/app_student/lib/routes.dart @@ -0,0 +1,75 @@ +// lib/routes.dart +import 'package:app_student/api/api_service.dart'; +import 'package:app_student/api/class_groups/repositories/class_group_repository.dart'; +import 'package:app_student/api/users/repositories/user_repository.dart'; +import 'package:app_student/api/week_schedule/repositories/week_schedule_repository.dart'; +import 'package:app_student/class_groups/cubit/class_group_cubit.dart'; +import 'package:app_student/config/config.dart'; +import 'package:app_student/week_schedule/cubit/week_schedule_cubit.dart'; +import 'package:app_student/week_schedule/views/week_schedule.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:go_router/go_router.dart'; + +import 'class_groups/views/class_group_page.dart'; +import 'login/cubit/login_cubit.dart'; +import 'login/views/login_page.dart'; + +class AppRoutes { + static const classListPage = '/classList'; + static const loginPage = '/login'; + static const schedulePage = '/schedule'; + + static final routes = [ + GoRoute( + path: classListPage, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: MultiRepositoryProvider( + providers: [ + RepositoryProvider( + create: (context) => ClassGroupRepository( + apiService: ApiService( + apiUrl: context.read().apiUrl))), + RepositoryProvider(create: (context) => UserRepository()), + ], + child: BlocProvider( + create: (context) => ClassGroupCubit( + classRepository: context.read(), + userRepository: context.read()), + child: const ClassGroupPage())))), + GoRoute( + path: loginPage, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: RepositoryProvider( + create: (context) => UserRepository(), + child: BlocProvider( + create: (context) => LoginCubit(context.read()), + child: const LoginPage(), + ), + ), + ), + ), + GoRoute( + path: schedulePage, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + child: MultiRepositoryProvider( + providers: [ + RepositoryProvider(create: (context) { + return WeekScheduleRepository( + apiService: + ApiService(apiUrl: context.read().apiUrl)); + }), + RepositoryProvider(create: (context) => UserRepository()), + ], + child: BlocProvider( + create: (context) => WeekScheduleCubit( + weekScheduleRepository: + context.read(), + userRepository: context.read(), + ), + child: const WeekSchedulePage())))), + ]; +} diff --git a/frontend/app_student/lib/week_schedule/views/widgets/components/custom_appbar.dart b/frontend/app_student/lib/week_schedule/views/widgets/components/custom_appbar.dart new file mode 100644 index 0000000..bb524d4 --- /dev/null +++ b/frontend/app_student/lib/week_schedule/views/widgets/components/custom_appbar.dart @@ -0,0 +1,23 @@ +import 'package:app_student/week_schedule/views/widgets/components/datepicker_button.dart'; +import 'package:flutter/material.dart'; + +class AppBarWeekSchedule extends StatelessWidget + implements PreferredSizeWidget { + const AppBarWeekSchedule({super.key}); + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: const Color(0xFF005067), + leading: Image.asset('assets/images/3il-logo.jpg'), + title: const Center( + child: Text('Classe Name', style: TextStyle(color: Colors.white))), + actions: const [ + DatePickerButton(), + ], + ); + } + + @override + Size get preferredSize => const Size.fromHeight(70.0); +} diff --git a/frontend/app_student/lib/week_schedule/views/widgets/components/datepicker_button.dart b/frontend/app_student/lib/week_schedule/views/widgets/components/datepicker_button.dart new file mode 100644 index 0000000..73e05d3 --- /dev/null +++ b/frontend/app_student/lib/week_schedule/views/widgets/components/datepicker_button.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class DatePickerButton extends StatelessWidget { + const DatePickerButton({super.key}); + + @override + Widget build(BuildContext context) { + return IconButton( + icon: const Icon(Icons.calendar_month, color: Colors.white), + onPressed: () async { + final date = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2000), + lastDate: DateTime(2100), + ); + if (date != null) { + // Utilisez la date sélectionnée + } + }, + ); + } +} diff --git a/frontend/app_student/lib/week_schedule/views/widgets/events/event_card.dart b/frontend/app_student/lib/week_schedule/views/widgets/events/event_card.dart new file mode 100644 index 0000000..c800d90 --- /dev/null +++ b/frontend/app_student/lib/week_schedule/views/widgets/events/event_card.dart @@ -0,0 +1,81 @@ +import 'package:app_student/api/events/models/event_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/svg.dart'; + +class EventCard extends StatelessWidget { + const EventCard({ + super.key, + required this.event, + }); + + final EventModel event; + + @override + Widget build(BuildContext context) { + return Card( + color: const Color(0xFF007A8D).withOpacity(0.3), + child: Container( + decoration: const BoxDecoration( + border: Border( + left: BorderSide( + color: Color(0xFF005067), + width: 10.0, + ), + ), + ), + width: 300, + height: 90, + child: Padding( + padding: + const EdgeInsets.only(left: 20.0, right: 20, bottom: 3, top: 3), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: event.creneau == 3 + ? MainAxisAlignment.center + : MainAxisAlignment.spaceEvenly, + children: event.creneau == 3 + ? [ + Center( + child: ColorFiltered( + colorFilter: const ColorFilter.mode( + Colors.white, BlendMode.srcIn), + child: SvgPicture.asset( + 'assets/images/eating.svg', + width: 40, + height: 40, + ), + ), + ) + ] + : [ + const Text('1h30', + style: TextStyle(color: Colors.white, fontSize: 12)), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(event.activite, + style: const TextStyle( + fontSize: 18, fontWeight: FontWeight.bold)), + ColorFiltered( + colorFilter: const ColorFilter.mode( + Colors.white, BlendMode.srcIn), + child: SvgPicture.asset( + event.visio + ? 'assets/images/teams.svg' + : 'assets/images/school.svg', + width: 40, + height: 40, + ), + ), + ], + ), + Text('Salle ${event.salle}', + style: const TextStyle( + fontSize: 15, fontWeight: FontWeight.bold)), + ], + ), + ), + ), + ); + } +} diff --git a/frontend/app_student/lib/week_schedule/views/widgets/events/event_details.dart b/frontend/app_student/lib/week_schedule/views/widgets/events/event_details.dart new file mode 100644 index 0000000..d61ad2d --- /dev/null +++ b/frontend/app_student/lib/week_schedule/views/widgets/events/event_details.dart @@ -0,0 +1,21 @@ +import 'package:app_student/api/events/models/event_model.dart'; +import 'package:app_student/week_schedule/views/widgets/events/event_card.dart'; +import 'package:app_student/week_schedule/views/widgets/events/event_hours.dart'; +import 'package:flutter/material.dart'; + +class EventDetails extends StatelessWidget { + final EventModel event; + + const EventDetails({super.key, required this.event}); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + EventHours(event: event), + EventCard(event: event), + ], + ); + } +} diff --git a/frontend/app_student/lib/week_schedule/views/widgets/events/event_hours.dart b/frontend/app_student/lib/week_schedule/views/widgets/events/event_hours.dart new file mode 100644 index 0000000..93c8228 --- /dev/null +++ b/frontend/app_student/lib/week_schedule/views/widgets/events/event_hours.dart @@ -0,0 +1,26 @@ +import 'package:app_student/api/events/models/event_model.dart'; +import 'package:flutter/material.dart'; + +class EventHours extends StatelessWidget { + const EventHours({ + super.key, + required this.event, + }); + + final EventModel event; + + @override + Widget build(BuildContext context) { + return SizedBox( + width: 50, + child: Column( + children: [ + Text(event.horaires.startAt, + style: const TextStyle(fontWeight: FontWeight.bold)), + Text(event.horaires.endAt, + style: const TextStyle(fontWeight: FontWeight.bold)), + ], + ), + ); + } +} diff --git a/frontend/app_student/pubspec.lock b/frontend/app_student/pubspec.lock index 4d39df3..21eeab5 100644 --- a/frontend/app_student/pubspec.lock +++ b/frontend/app_student/pubspec.lock @@ -102,6 +102,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.4" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" flutter_lints: dependency: "direct dev" description: @@ -110,6 +118,11 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" flutter_svg: dependency: "direct main" description: @@ -128,6 +141,14 @@ packages: description: flutter source: sdk version: "0.0.0" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "170c46e237d6eb0e6e9f0e8b3f56101e14fb64f787016e42edd74c39cf8b176a" + url: "https://pub.dev" + source: hosted + version: "13.2.0" http: dependency: "direct main" description: @@ -144,6 +165,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" leak_tracker: dependency: transitive description: @@ -176,6 +205,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: diff --git a/frontend/app_student/pubspec.yaml b/frontend/app_student/pubspec.yaml index 68f785d..3f05856 100644 --- a/frontend/app_student/pubspec.yaml +++ b/frontend/app_student/pubspec.yaml @@ -42,6 +42,11 @@ dependencies: flutter_bloc: ^8.1.4 meta: ^1.11.0 flutter_svg: ^2.0.10+1 + go_router: ^13.2.0 + flutter_localizations: + sdk: flutter + intl: any + flutter_dotenv: ^5.1.0 dev_dependencies: flutter_test: @@ -59,7 +64,7 @@ dev_dependencies: # The following section is specific to Flutter packages. flutter: - + generate: true # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. @@ -72,6 +77,7 @@ flutter: assets: - assets/images/ + - .env # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware @@ -95,5 +101,11 @@ flutter: # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # + + fonts: + - family: Arial + fonts: + - asset: assets/fonts/arial.ttf + # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages + # see https://flutter.dev/custom-fonts/#from-packages \ No newline at end of file