From 808970d738e6e626f540a1e03a762e7bc0ffb629 Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 27 Mar 2025 10:06:03 -0400 Subject: [PATCH 1/6] feat: Carousel for images in exercise details --- lib/widgets/exercises/exercises.dart | 46 +++++++++++++++++++++++++--- pubspec.lock | 8 +++++ pubspec.yaml | 1 + 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lib/widgets/exercises/exercises.dart b/lib/widgets/exercises/exercises.dart index 25e58bf2..6f3208a7 100644 --- a/lib/widgets/exercises/exercises.dart +++ b/lib/widgets/exercises/exercises.dart @@ -17,6 +17,7 @@ */ import 'package:flutter/material.dart'; +import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; @@ -193,10 +194,23 @@ class ExerciseDetail extends StatelessWidget { // TODO: add carousel for the other images final List out = []; if (_exercise.getMainImage != null) { - out.add(ExerciseImageWidget( - image: _exercise.getMainImage, - height: 250, - )); + out.add( + FlutterCarousel.builder( + itemCount: _exercise.images.length, + options: FlutterCarouselOptions( + showIndicator: true, + slideIndicator: CarouselIndicator(), + ), + itemBuilder: (_, index, __) => ExerciseImageWidget( + image: _exercise.images[index], + height: 250, + ), + ), + ); + // out.add(ExerciseImageWidget( + // image: _exercise.getMainImage, + // height: 250, + // )); out.add(const SizedBox(height: PADDING)); } @@ -356,3 +370,27 @@ class MuscleWidget extends StatelessWidget { ); } } + +class CarouselIndicator implements SlideIndicator { + CarouselIndicator(); + + @override + Widget build(int currentPage, double pageDelta, int itemCount) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: List.generate( + itemCount, + (index) => Container( + height: 8, + width: 8, + margin: EdgeInsets.only(right: index != itemCount - 1 ? 5 : 0), + decoration: BoxDecoration( + color: currentPage == index ? Colors.black : Colors.black26, + shape: BoxShape.circle, + ), + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 0e19b69f..67d5cc79 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -406,6 +406,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.3" + flutter_carousel_widget: + dependency: "direct main" + description: + name: flutter_carousel_widget + sha256: "6473e6df04bfafea70efd58251fe5945d5aa8d19461575c1b9d83643f08e0c77" + url: "https://pub.dev" + source: hosted + version: "3.1.0" flutter_driver: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index e05da616..22b0247d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,6 +69,7 @@ dependencies: video_player: ^2.9.3 logging: ^1.3.0 flutter_riverpod: ^2.6.1 + flutter_carousel_widget: ^3.1.0 #dependency_overrides: # intl: ^0.19.0 From 3716dae2d28296bc6f639316ab21547d96a7f93c Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 27 Mar 2025 10:07:30 -0400 Subject: [PATCH 2/6] update: custom carousel indicator spacing --- lib/widgets/exercises/exercises.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/exercises/exercises.dart b/lib/widgets/exercises/exercises.dart index 6f3208a7..0db379b3 100644 --- a/lib/widgets/exercises/exercises.dart +++ b/lib/widgets/exercises/exercises.dart @@ -379,12 +379,12 @@ class CarouselIndicator implements SlideIndicator { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, + spacing: 5, children: List.generate( itemCount, (index) => Container( height: 8, width: 8, - margin: EdgeInsets.only(right: index != itemCount - 1 ? 5 : 0), decoration: BoxDecoration( color: currentPage == index ? Colors.black : Colors.black26, shape: BoxShape.circle, From 8f9ae5bcc08b78bad9c5bf95a99605b5fc6112cf Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 27 Mar 2025 11:22:03 -0400 Subject: [PATCH 3/6] update: carousel to carousel slider --- lib/widgets/exercises/exercises.dart | 75 ++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/lib/widgets/exercises/exercises.dart b/lib/widgets/exercises/exercises.dart index 0db379b3..a6814334 100644 --- a/lib/widgets/exercises/exercises.dart +++ b/lib/widgets/exercises/exercises.dart @@ -16,6 +16,7 @@ * along with this program. If not, see . */ +import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; import 'package:flutter_html/flutter_html.dart'; @@ -26,6 +27,7 @@ import 'package:wger/helpers/i18n.dart'; import 'package:wger/helpers/platform.dart'; import 'package:wger/l10n/generated/app_localizations.dart'; import 'package:wger/models/exercises/exercise.dart'; +import 'package:wger/models/exercises/image.dart'; import 'package:wger/models/exercises/muscle.dart'; import 'package:wger/models/exercises/translation.dart'; import 'package:wger/providers/exercises.dart'; @@ -38,6 +40,7 @@ class ExerciseDetail extends StatelessWidget { final Exercise _exercise; late Translation _translation; static const PADDING = 9.0; + final CarouselController carouselController = CarouselController(); ExerciseDetail(this._exercise); @@ -193,20 +196,11 @@ class ExerciseDetail extends StatelessWidget { List getImages() { // TODO: add carousel for the other images final List out = []; - if (_exercise.getMainImage != null) { - out.add( - FlutterCarousel.builder( - itemCount: _exercise.images.length, - options: FlutterCarouselOptions( - showIndicator: true, - slideIndicator: CarouselIndicator(), - ), - itemBuilder: (_, index, __) => ExerciseImageWidget( - image: _exercise.images[index], - height: 250, - ), - ), - ); + if (_exercise.images.isNotEmpty) { + out.add(CarouselImages( + images: _exercise.images, + )); + // out.add(ExerciseImageWidget( // image: _exercise.getMainImage, // height: 250, @@ -394,3 +388,56 @@ class CarouselIndicator implements SlideIndicator { ); } } + +class CarouselImages extends StatefulWidget { + final List images; + + const CarouselImages({super.key, required this.images}); + + @override + State createState() => _CarouselImagesState(); +} + +class _CarouselImagesState extends State { + int pageIndex = 0; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: 250, + child: Stack( + children: [ + CarouselSlider( + options: CarouselOptions( + onPageChanged: (index, _) => setState(() => pageIndex = index), + ), + items: List.generate( + widget.images.length, + (index) => ExerciseImageWidget( + image: widget.images[index], + height: 250, + ), + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + spacing: 5, + children: List.generate( + widget.images.length, + (index) => AnimatedContainer( + duration: const Duration(milliseconds: 500), + height: 8, + width: 8, + decoration: BoxDecoration( + color: pageIndex == index ? Colors.black : Colors.black26, + shape: BoxShape.circle, + ), + ), + ), + ), + ], + ), + ); + } +} From 4b529d3a64ea4f6be5966ce77cc54a8f9ee25540 Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Thu, 27 Mar 2025 11:24:06 -0400 Subject: [PATCH 4/6] update: carousel to carousel slider --- pubspec.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 22b0247d..e05da616 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -69,7 +69,6 @@ dependencies: video_player: ^2.9.3 logging: ^1.3.0 flutter_riverpod: ^2.6.1 - flutter_carousel_widget: ^3.1.0 #dependency_overrides: # intl: ^0.19.0 From 6d0d93bd8fddb141272aaea31953745e8578ca4a Mon Sep 17 00:00:00 2001 From: Yashas H Majmudar Date: Fri, 28 Mar 2025 22:08:29 -0400 Subject: [PATCH 5/6] fix: unused import error --- lib/widgets/exercises/exercises.dart | 25 ------------------------- pubspec.lock | 8 -------- 2 files changed, 33 deletions(-) diff --git a/lib/widgets/exercises/exercises.dart b/lib/widgets/exercises/exercises.dart index a6814334..dbdfedf6 100644 --- a/lib/widgets/exercises/exercises.dart +++ b/lib/widgets/exercises/exercises.dart @@ -18,7 +18,6 @@ import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; import 'package:flutter_html/flutter_html.dart'; import 'package:flutter_svg/svg.dart'; import 'package:provider/provider.dart'; @@ -365,30 +364,6 @@ class MuscleWidget extends StatelessWidget { } } -class CarouselIndicator implements SlideIndicator { - CarouselIndicator(); - - @override - Widget build(int currentPage, double pageDelta, int itemCount) { - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - spacing: 5, - children: List.generate( - itemCount, - (index) => Container( - height: 8, - width: 8, - decoration: BoxDecoration( - color: currentPage == index ? Colors.black : Colors.black26, - shape: BoxShape.circle, - ), - ), - ), - ); - } -} - class CarouselImages extends StatefulWidget { final List images; diff --git a/pubspec.lock b/pubspec.lock index 67d5cc79..0e19b69f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -406,14 +406,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.5.3" - flutter_carousel_widget: - dependency: "direct main" - description: - name: flutter_carousel_widget - sha256: "6473e6df04bfafea70efd58251fe5945d5aa8d19461575c1b9d83643f08e0c77" - url: "https://pub.dev" - source: hosted - version: "3.1.0" flutter_driver: dependency: transitive description: flutter From ef003c28ab8e82d87d98819fe9553d104f75ebf4 Mon Sep 17 00:00:00 2001 From: Roland Geider Date: Sat, 29 Mar 2025 14:45:12 +0100 Subject: [PATCH 6/6] Add some padding so that the images don't collide with the info dots --- lib/widgets/exercises/exercises.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/widgets/exercises/exercises.dart b/lib/widgets/exercises/exercises.dart index dbdfedf6..71831426 100644 --- a/lib/widgets/exercises/exercises.dart +++ b/lib/widgets/exercises/exercises.dart @@ -388,9 +388,12 @@ class _CarouselImagesState extends State { ), items: List.generate( widget.images.length, - (index) => ExerciseImageWidget( - image: widget.images[index], - height: 250, + (index) => Padding( + padding: const EdgeInsets.only(top: 15), + child: ExerciseImageWidget( + image: widget.images[index], + height: 260, + ), ), ), ),