From 264171b42abc5ba095c755a164956d6f15b8e228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C3=ABl=20Perret?= Date: Sat, 30 Aug 2025 15:24:43 +0200 Subject: [PATCH] feat : EventDetails : Back button + read more option --- .dart_tool/package_config.json | 6 + .dart_tool/package_config_subset | 4 + build/flutter_assets/NOTICES | 1 + lib/ui/common/post_card_widget.dart | 10 +- .../event_details/event_details_view.dart | 489 +++++++++--------- .../event_details_viewmodel.dart | 11 + pubspec.lock | 8 + pubspec.yaml | 1 + 8 files changed, 296 insertions(+), 234 deletions(-) diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json index 65d9905..597875c 100644 --- a/.dart_tool/package_config.json +++ b/.dart_tool/package_config.json @@ -445,6 +445,12 @@ "packageUri": "lib/", "languageVersion": "3.0" }, + { + "name": "readmore", + "rootUri": "file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/readmore-3.0.0", + "packageUri": "lib/", + "languageVersion": "3.0" + }, { "name": "recase", "rootUri": "file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/recase-4.1.0", diff --git a/.dart_tool/package_config_subset b/.dart_tool/package_config_subset index 91beb2f..6736c23 100644 --- a/.dart_tool/package_config_subset +++ b/.dart_tool/package_config_subset @@ -278,6 +278,10 @@ pubspec_parse 3.0 file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/pubspec_parse-1.3.0/ file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/pubspec_parse-1.3.0/lib/ +readmore +3.0 +file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/readmore-3.0.0/ +file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/readmore-3.0.0/lib/ recase 2.12 file:///C:/Users/Yael/AppData/Local/Pub/Cache/hosted/pub.dev/recase-4.1.0/ diff --git a/build/flutter_assets/NOTICES b/build/flutter_assets/NOTICES index 628dd69..5434b7d 100644 --- a/build/flutter_assets/NOTICES +++ b/build/flutter_assets/NOTICES @@ -6686,6 +6686,7 @@ the License, but only in their entirety and only with respect to the Combined Software. -------------------------------------------------------------------------------- get +readmore MIT License diff --git a/lib/ui/common/post_card_widget.dart b/lib/ui/common/post_card_widget.dart index 1f2942c..53090df 100644 --- a/lib/ui/common/post_card_widget.dart +++ b/lib/ui/common/post_card_widget.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'dart:async'; +import 'package:readmore/readmore.dart'; class PostCardWidget extends StatefulWidget { final String title; @@ -105,9 +106,14 @@ class _PostCardWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Contenu - Text( + ReadMoreText( widget.content, - style: Theme.of(context).textTheme.bodyMedium?.copyWith( + trimMode: TrimMode.Line, + trimLines: 2, + colorClickableText: Theme.of(context).colorScheme.primary, + trimCollapsedText: 'Voir plus', + trimExpandedText: 'Voir moins', + moreStyle: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Colors.white, height: 1.4, ), diff --git a/lib/ui/views/event_details/event_details_view.dart b/lib/ui/views/event_details/event_details_view.dart index d790a82..ddf57ae 100644 --- a/lib/ui/views/event_details/event_details_view.dart +++ b/lib/ui/views/event_details/event_details_view.dart @@ -14,249 +14,274 @@ class EventDetailsView extends StackedView { EventDetailsViewModel viewModel, Widget? child, ) { - return DefaultTabController( - length: 2, - child: Scaffold( - backgroundColor: Colors.white, - body: SingleChildScrollView( - child: Column( - children: [ - Container( - width: double.infinity, - height: MediaQuery.of(context).size.width * 9 / 16, - child: const Image( - image: AssetImage('assets/images/Affiche.jpg'), - fit: BoxFit.cover, - alignment: Alignment.center, - ), - ), - Container( - color: Colors.white, - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - // Titre de l'événement - Text( - 'Disc\'Octonelle 2', - style: Theme.of(context).textTheme.headlineLarge?.copyWith( - color: Colors.black - ), - ), - const SizedBox(height: 16), - - Center( - child: Container( - width: MediaQuery.of(context).size.width * 0.8, - child: Table( - columnWidths: const { - 0: FixedColumnWidth(80.0), // Largeur fixe pour les icônes - 1: FlexColumnWidth(), // Prend l'espace restant - }, - children: [ - // Date - TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Align( - alignment: Alignment.centerLeft, - child: Icon( - Icons.calendar_today, - size: 30, - color: Theme.of(context).colorScheme.tertiary, - ), - ), - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text( - '29.04.2023', - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Colors.black, - ), - ), - ), - ), - ], - ), - // Lieu - TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Align( - alignment: Alignment.centerLeft, - child: Icon( - Icons.location_on, - size: 30, - color: Theme.of(context).colorScheme.tertiary, - ), - ), - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Anim-Halle', - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Colors.black, - fontWeight: FontWeight.w500, - ), - ), - Text( - 'En Bas-les-Barres 6', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Colors.grey[800], - ), - ), - Text( - '2316 Les Ponts-de-martel', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Colors.grey[800], - ), - ), - ], - ), - ), - ), - ], - ), - // Organisation - TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Align( - alignment: Alignment.centerLeft, - child: Container( - width: 40, - height: 40, - child: Image.asset( - 'images/OCTONELLE.jpg', - fit: BoxFit.cover, - ), - ), - ), - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 4.0), - child: Text( - 'L\'Octonelle', - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - color: Colors.black, - ), - ), - ), - ), - ], - ), - ], + return PopScope( + canPop: true, + onPopInvokedWithResult: (bool didPop, Object? result) { + viewModel.onBackPressed(); + }, + child: Stack( + children: [ + DefaultTabController( + length: 2, + child: Scaffold( + backgroundColor: Colors.white, + body: SingleChildScrollView( + child: Column( + children: [ + Container( + width: double.infinity, + height: MediaQuery.of(context).size.width * 9 / 16, + child: const Image( + image: AssetImage('assets/images/Affiche.jpg'), + fit: BoxFit.cover, + alignment: Alignment.center, ), ), - ), - - const SizedBox(height: 16), - - // TabBar - TabBar( - tabs: const [ - Tab(text: 'Publications'), - Tab(text: 'À propos'), - ], - labelColor: Theme.of(context).colorScheme.primary, - unselectedLabelColor: Colors.black, - indicatorColor: Theme.of(context).colorScheme.primary, - tabAlignment: TabAlignment.start, - isScrollable: true, - labelStyle: Theme.of(context).textTheme.titleLarge, - dividerColor: Colors.transparent, - onTap: (index) { - viewModel.setSelectedTab(index); - }, - ), - - ], - ), - ), - - // Contenu des onglets basé sur l'index sélectionné - Container( - color: const Color(0xFFEFF0FF), - padding: const EdgeInsets.all(16.0), - child: viewModel.selectedTabIndex == 0 - ? Column( - mainAxisSize: MainAxisSize.min, - children: List.generate(10, (index) { - return PostCardWidget( - title: 'Publication ${index + 1}', - content: 'Voici le contenu de la publication ${index + 1}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - authorName: 'L\'Octonelle', - authorImageUrl: '', // URL vide pour utiliser l'icône par défaut - publishDate: DateTime.now().subtract(Duration(days: index)), - imageUrls: index % 3 == 0 ? ['assets/images/Affiche.jpg'] : null, - likesCount: (index + 1) * 5, - commentsCount: (index + 1) * 2, - aspectRatio: 4/5, - onLike: () { - // Action lors du clic sur "J'aime" - print('Like publication ${index + 1}'); - }, - onComment: () { - // Action lors du clic sur "Commenter" - print('Comment publication ${index + 1}'); - }, - onShare: () { - // Action lors du clic sur "Partager" - print('Share publication ${index + 1}'); - }, - ); - }), - ) - : Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ + Container( + color: Colors.white, + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Titre de l'événement Text( - 'À propos de L\'Octonelle', - style: Theme.of(context).textTheme.headlineSmall?.copyWith( - color: Colors.black, - fontWeight: FontWeight.bold, + 'Disc\'Octonelle 2', + style: Theme.of(context).textTheme.headlineLarge?.copyWith( + color: Colors.black ), ), const SizedBox(height: 16), - const Text( - 'Description détaillée de l\'organisation L\'Octonelle et de ses activités...', - style: TextStyle(color: Colors.black87), + + Center( + child: Container( + width: MediaQuery.of(context).size.width * 0.8, + child: Table( + columnWidths: const { + 0: FixedColumnWidth(80.0), // Largeur fixe pour les icônes + 1: FlexColumnWidth(), // Prend l'espace restant + }, + children: [ + // Date + TableRow( + children: [ + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Align( + alignment: Alignment.centerLeft, + child: Icon( + Icons.calendar_today, + size: 30, + color: Theme.of(context).colorScheme.tertiary, + ), + ), + ), + ), + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Text( + '29.04.2023', + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Colors.black, + ), + ), + ), + ), + ], + ), + // Lieu + TableRow( + children: [ + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Align( + alignment: Alignment.centerLeft, + child: Icon( + Icons.location_on, + size: 30, + color: Theme.of(context).colorScheme.tertiary, + ), + ), + ), + ), + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Anim-Halle', + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ), + Text( + 'En Bas-les-Barres 6', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.grey[800], + ), + ), + Text( + '2316 Les Ponts-de-martel', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Colors.grey[800], + ), + ), + ], + ), + ), + ), + ], + ), + // Organisation + TableRow( + children: [ + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Align( + alignment: Alignment.centerLeft, + child: Container( + width: 40, + height: 40, + child: Image.asset( + 'images/OCTONELLE.jpg', + fit: BoxFit.cover, + ), + ), + ), + ), + ), + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 4.0), + child: Text( + 'L\'Octonelle', + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Colors.black, + ), + ), + ), + ), + ], + ), + ], + ), + ), ), - // Contenu supplémentaire pour tester le scroll - ...List.generate(20, (index) => Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Text('Ligne de contenu ${index + 1}'), - )), + + const SizedBox(height: 16), + + // TabBar + TabBar( + tabs: const [ + Tab(text: 'Publications'), + Tab(text: 'À propos'), + ], + labelColor: Theme.of(context).colorScheme.primary, + unselectedLabelColor: Colors.black, + indicatorColor: Theme.of(context).colorScheme.primary, + tabAlignment: TabAlignment.start, + isScrollable: true, + labelStyle: Theme.of(context).textTheme.titleLarge, + dividerColor: Colors.transparent, + onTap: (index) { + viewModel.setSelectedTab(index); + }, + ), + ], ), - ), - ], + ), + + // Contenu des onglets basé sur l'index sélectionné + Container( + color: const Color(0xFFEFF0FF), + padding: const EdgeInsets.all(16.0), + child: viewModel.selectedTabIndex == 0 + ? Column( + mainAxisSize: MainAxisSize.min, + children: List.generate(10, (index) { + return PostCardWidget( + title: 'Publication ${index + 1}', + content: 'Voici le contenu de la publication ${index + 1}. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + authorName: 'L\'Octonelle', + authorImageUrl: '', // URL vide pour utiliser l'icône par défaut + publishDate: DateTime.now().subtract(Duration(days: index)), + imageUrls: index % 3 == 0 ? ['assets/images/Affiche.jpg'] : null, + likesCount: (index + 1) * 5, + commentsCount: (index + 1) * 2, + aspectRatio: 4/5, + onLike: () { + // Action lors du clic sur "J'aime" + print('Like publication ${index + 1}'); + }, + onComment: () { + // Action lors du clic sur "Commenter" + print('Comment publication ${index + 1}'); + }, + onShare: () { + // Action lors du clic sur "Partager" + print('Share publication ${index + 1}'); + }, + ); + }), + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'À propos de L\'Octonelle', + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 16), + const Text( + 'Description détaillée de l\'organisation L\'Octonelle et de ses activités...', + style: TextStyle(color: Colors.black87), + ), + // Contenu supplémentaire pour tester le scroll + ...List.generate(20, (index) => Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Text('Ligne de contenu ${index + 1}'), + )), + ], + ), + ), + ], + ), + ), ), ), + Positioned( + top: 20, + left: 20, + child: Container( + //padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.6), + borderRadius: BorderRadius.circular(20), + ), + child: IconButton( + onPressed: viewModel.onBackPressed, + icon: const Icon(Icons.arrow_back, size: 20), + ) + ), + ), + ], ), ); } diff --git a/lib/ui/views/event_details/event_details_viewmodel.dart b/lib/ui/views/event_details/event_details_viewmodel.dart index 3f7c1a2..3688fe7 100644 --- a/lib/ui/views/event_details/event_details_viewmodel.dart +++ b/lib/ui/views/event_details/event_details_viewmodel.dart @@ -1,6 +1,10 @@ +import 'package:bahla_front/app/app.locator.dart'; import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; class EventDetailsViewModel extends BaseViewModel { + final _navigationService = locator(); + int _selectedTabIndex = 0; int get selectedTabIndex => _selectedTabIndex; @@ -9,6 +13,13 @@ class EventDetailsViewModel extends BaseViewModel { _selectedTabIndex = index; notifyListeners(); } + + void onBackPressed() { + // Handle back button press logic here + print('Back button pressed'); + _navigationService.back(); + } + } class Post { diff --git a/pubspec.lock b/pubspec.lock index 50b99e9..cdbef08 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -581,6 +581,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + readmore: + dependency: "direct main" + description: + name: readmore + sha256: e8fca2bd397b86342483b409e2ec26f06560a5963aceaa39b27f30722b506187 + url: "https://pub.dev" + source: hosted + version: "3.0.0" recase: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 2b3268d..891bd77 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ dependencies: google_fonts: ^6.2.1 http: ^1.2.2 intl: any + readmore: ^3.0.0 stacked: ^3.4.0 stacked_services: ^1.1.0