From a32ba46d43fa281738dccfd83642d4dfd8ae97ba Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Thu, 6 Jan 2022 00:22:55 +0100 Subject: [PATCH 1/6] The design of the main screen looks good but there are many bugs and I will refactor the CarouselSliders. --- lib/ui/screens/main_screen.dart | 18 ++- lib/ui/widgets/carousel_slider.dart | 161 +++++++++++++----------- lib/ui/widgets/new_carousel_slider.dart | 0 3 files changed, 97 insertions(+), 82 deletions(-) create mode 100644 lib/ui/widgets/new_carousel_slider.dart diff --git a/lib/ui/screens/main_screen.dart b/lib/ui/screens/main_screen.dart index 6d660ec..a81d914 100644 --- a/lib/ui/screens/main_screen.dart +++ b/lib/ui/screens/main_screen.dart @@ -31,20 +31,18 @@ class MainScreen extends StatelessWidget { orientation == Orientation.portrait ? constraints.maxHeight / 2 : constraints.maxHeight); - return ListView.builder( - scrollDirection: Axis.vertical, - itemCount: 2, - itemBuilder: (BuildContext context, int i) { - return i == 0 - ? CarouselSliderCampusBox( + return Column( + children: [ + CarouselSliderCampusBox( campusExhibition: artworkService.campusExhibition, boxSize: boxSize, - ) - : CarouselSliderBoxExhibition( + ), + CarouselSliderBoxExhibition( exhibitionList: artworkService.exhibitionList, boxSize: boxSize, - ); - }); + ) + ], + ); }, ); }, diff --git a/lib/ui/widgets/carousel_slider.dart b/lib/ui/widgets/carousel_slider.dart index a04cdc9..4b8bf5a 100644 --- a/lib/ui/widgets/carousel_slider.dart +++ b/lib/ui/widgets/carousel_slider.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; import 'package:provider/provider.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; /// A enum for choosing the type of the [CarouselSliderBox]. enum CarouselSliderIndicator { @@ -63,6 +64,9 @@ class _CarouselSliderBoxState extends State { /// The index of the image which is currently shown. int position = 0; + /// To controller for the CarouselSlider to swipe to the next page with the [AnimatedSmoothIndicator] + CarouselController carouselController = CarouselController(); + @override void didChangeDependencies() { // Run the precache method after the widget is built @@ -129,9 +133,11 @@ class _CarouselSliderBoxState extends State { child: Align( alignment: Alignment.center, child: _PageIndicator( - position: position, - elementCount: widget.elementCount, - ), + position: position, + elementCount: widget.elementCount, + onTap: (index) => setState(() { + position = index; + })), ), ); } @@ -149,22 +155,51 @@ class _CarouselSliderBoxState extends State { /// Builds a [CarouselSlider] widget containing the images. /// The images shown are built using the [_buildImage] method. Widget _buildCarouselSlider() { - return CarouselSlider.builder( - options: CarouselOptions( - enlargeCenterPage: widget.type == CarouselSliderIndicator.insideText, - aspectRatio: 1, - // Only enable infinite scrolling when at least 2 artworks are to be shown - enableInfiniteScroll: widget.elementCount > 1, - viewportFraction: 1, - onPageChanged: (index, reason) { - setState(() { - position = index; - }); - _precacheNeighbours(index); - }, - ), - itemCount: widget.elementCount, - itemBuilder: (context, index, realIndex) => _buildImage(index), + final appSetting = Provider.of(context); + return Stack( + fit: StackFit.expand, + children: [ + CarouselSlider.builder( + carouselController: carouselController, + options: CarouselOptions( + enlargeCenterPage: + widget.type == CarouselSliderIndicator.insideText, + aspectRatio: 1, + // Only enable infinite scrolling when at least 2 artworks are to be shown + enableInfiniteScroll: widget.elementCount > 1, + viewportFraction: 1, + onPageChanged: (index, reason) { + setState(() { + position = index; + }); + _precacheNeighbours(index); + }, + ), + itemCount: widget.elementCount, + itemBuilder: (context, index, realIndex) => _buildImage(index), + ), + Positioned( + top: 20, + left: 20, + child: Text( + AppLocalizations.of(context)!.campusArt.toUpperCase(), + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTitleFontSize+4, + fontWeight: FontWeight.w900, + ), + ) + ), + Positioned( + right: 20, + bottom: 20, + child: _PageIndicator( + position: position, + elementCount: widget.elementCount, + onTap: (index) => carouselController.animateToPage(index))), + //) + ], ); } @@ -178,10 +213,10 @@ class _CarouselSliderBoxState extends State { child = _ImageOverlay( size: widget.boxSize, title: _Title(text: widget.provideText!(position)), - pageIndicator: _PageIndicator( + /*pageIndicator: _PageIndicator( position: position, elementCount: widget.elementCount, - ), + ),*/ ); break; case CarouselSliderIndicator.below: @@ -218,51 +253,24 @@ class _CarouselSliderBoxState extends State { /// A [StatelessWidget] used to overlay information on an image. /// The [size] are the dimensions of the image viewport. /// The [title] is displayed on the upper left corner. -/// The [pageIndicator] is shown on the lower right corner. class _ImageOverlay extends StatelessWidget { const _ImageOverlay({ Key? key, required this.size, required this.title, - required this.pageIndicator, }) : super(key: key); final Size size; final Widget title; - final Widget pageIndicator; @override Widget build(BuildContext context) { return Container( - padding: EdgeInsets.only(left: 20), - width: size.width, - height: size.height, - color: Colors.transparent, - child: Column( - children: [ - Expanded( - flex: 2, - child: Align( - alignment: Alignment.topLeft, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: title, - ), - ), - ), - Flexible( - flex: 1, - child: Align( - alignment: Alignment.bottomRight, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: pageIndicator, - ), - ), - ), - ], - ), - ); + width: size.width, + height: size.height, + color: Colors.transparent, + child: title + ); } } @@ -278,22 +286,30 @@ class _Title extends StatelessWidget { @override Widget build(BuildContext context) { final appSetting = Provider.of(context); - return Container( - child: AutoSizeText( - text, - maxLines: 1, - style: TextStyle( - color: Colors.white, - fontFamily: 'Avenir', - fontSize: appSetting.bodyTitleFontSize, - fontWeight: FontWeight.w900, + child: Padding( + padding: EdgeInsets.fromLTRB(26, 46, 12, 12), + child: Text( + text, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTextFontSize, + fontWeight: FontWeight.w700, + ), ), ), - padding: EdgeInsets.fromLTRB(8, 5, 8, 5), decoration: BoxDecoration( - color: Colors.black.withOpacity(.7), - borderRadius: BorderRadius.circular(7), + color: Colors.white, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.6), + Colors.black.withOpacity(0.0), + ], + stops: [0, 0.5], + ), ), ); } @@ -307,27 +323,28 @@ class _PageIndicator extends StatelessWidget { Key? key, required this.position, required this.elementCount, + required this.onTap, }) : super(key: key); final int position; final int elementCount; + final Function(int) onTap; @override Widget build(BuildContext context) { final appSetting = Provider.of(context); - final displaySize = MediaQuery.of(context).size; + final double dotScale = MediaQuery.of(context).size.width * 0.025; return AnimatedSmoothIndicator( activeIndex: position, count: elementCount, + onDotClicked: onTap, effect: ScrollingDotsEffect( activeDotColor: appSetting.primaryColor, - dotColor: appSetting.primaryColor.withOpacity(0.5), - activeDotScale: 1.6, - maxVisibleDots: 5, - dotWidth: displaySize.width * 0.015, - dotHeight: displaySize.width * 0.015, - spacing: 15, + dotColor: Colors.white, + dotWidth: dotScale, + dotHeight: dotScale, + spacing: 17, ), ); } diff --git a/lib/ui/widgets/new_carousel_slider.dart b/lib/ui/widgets/new_carousel_slider.dart new file mode 100644 index 0000000..e69de29 -- GitLab From 5209502fc4637d99af1f86faeb979ea558b76cc7 Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Thu, 6 Jan 2022 01:40:22 +0100 Subject: [PATCH 2/6] Some Bug fixes and refactoring. Further work is necessary --- lib/ui/widgets/carousel_slider.dart | 160 +++++------- lib/ui/widgets/carousel_slider_artwork.dart | 2 +- lib/ui/widgets/carousel_slider_campus.dart | 6 +- .../widgets/carousel_slider_exhibition.dart | 4 +- lib/ui/widgets/image_slider.dart | 228 ++++++++++++++++++ 5 files changed, 297 insertions(+), 103 deletions(-) create mode 100644 lib/ui/widgets/image_slider.dart diff --git a/lib/ui/widgets/carousel_slider.dart b/lib/ui/widgets/carousel_slider.dart index 4b8bf5a..c12a370 100644 --- a/lib/ui/widgets/carousel_slider.dart +++ b/lib/ui/widgets/carousel_slider.dart @@ -6,20 +6,16 @@ import 'package:provider/provider.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -/// A enum for choosing the type of the [CarouselSliderBox]. -enum CarouselSliderIndicator { - /// The page indicator and the given text are overlayed on top of the image. - insideText, - - /// The image is displayed at maximum size and the page indicator in the middle underneath it. - /// For this type it's not possible to overlay any text. - below, +/// A enum for choosing if and how titles should be displayed. +enum ImageNameStyle { + none, + + title, + + subtitle } class CarouselSliderBox extends StatefulWidget { - /// The [type] determines the location of the page indication and whether text is shown or not. - /// See [CarouselSliderIndicator] for more information. - final CarouselSliderIndicator type; /// The [BoxFit] of the displayed images in the carousel. /// If not set, it defaults to [BoxFit.contain]. @@ -45,16 +41,28 @@ class CarouselSliderBox extends StatefulWidget { /// is guaranteed to be 0 <= index < elementCount. final void Function(int index)? onTap; + final bool showPageIndicator; + + final String? title; + + final ImageNameStyle imageNameStyle; + + final bool enlargeCenterPage; + CarouselSliderBox({ Key? key, - required this.type, required this.boxSize, required this.elementCount, required this.provideImage, this.imageFit = BoxFit.contain, this.provideText, this.onTap, - }) : super(key: key); + this.showPageIndicator = true, + this.title, + this.imageNameStyle = ImageNameStyle.title, this.enlargeCenterPage = true, + }) : assert(title == null || imageNameStyle != ImageNameStyle.title), + assert(provideText != null || imageNameStyle == ImageNameStyle.none), + super(key: key); @override _CarouselSliderBoxState createState() => _CarouselSliderBoxState(); @@ -99,57 +107,12 @@ class _CarouselSliderBoxState extends State { @override Widget build(BuildContext context) { - switch (widget.type) { - case CarouselSliderIndicator.below: - return _buildIndicatorsBelow(); - case CarouselSliderIndicator.insideText: - return _buildIndicatorsInsideText(); - } - } - - /// Builds the full widget for the option [CarouselSliderIndicator.below]. - /// The indicator is shown below the image. - Widget _buildIndicatorsBelow() { - return Column( - children: [ - Expanded( - flex: 8, - child: _buildCarouselSlider(), - ), - // Only show indicator when more than one artwork is to be shown - if (widget.elementCount > 1) - Flexible( - flex: 1, - child: _buildCenteredPageIndicator(), - ), - ], - ); - } - - /// Centers the [_PageIndicator] widget. - Widget _buildCenteredPageIndicator() { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Align( - alignment: Alignment.center, - child: _PageIndicator( - position: position, - elementCount: widget.elementCount, - onTap: (index) => setState(() { - position = index; - })), - ), - ); - } - - /// Builds the full widget for the option [CarouselSliderIndicator.insideText]. - /// The indicator and a text is put on top of the image. - Widget _buildIndicatorsInsideText() { return Container( width: widget.boxSize.width, height: widget.boxSize.height, child: _buildCarouselSlider(), ); + } /// Builds a [CarouselSlider] widget containing the images. @@ -163,7 +126,7 @@ class _CarouselSliderBoxState extends State { carouselController: carouselController, options: CarouselOptions( enlargeCenterPage: - widget.type == CarouselSliderIndicator.insideText, + widget.enlargeCenterPage, aspectRatio: 1, // Only enable infinite scrolling when at least 2 artworks are to be shown enableInfiniteScroll: widget.elementCount > 1, @@ -178,19 +141,19 @@ class _CarouselSliderBoxState extends State { itemCount: widget.elementCount, itemBuilder: (context, index, realIndex) => _buildImage(index), ), + if(widget.title != null) Positioned( - top: 20, - left: 20, - child: Text( - AppLocalizations.of(context)!.campusArt.toUpperCase(), - style: TextStyle( - color: Colors.white, - fontFamily: 'Avenir', - fontSize: appSetting.bodyTitleFontSize+4, - fontWeight: FontWeight.w900, - ), - ) - ), + top: 20, + left: 20, + child: Text( + widget.title!, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTitleFontSize + 4, + fontWeight: FontWeight.w900, + ), + )), Positioned( right: 20, bottom: 20, @@ -205,25 +168,6 @@ class _CarouselSliderBoxState extends State { /// Builds the correct image widget for the [widget.type]. Widget _buildImage(int index) { - final Widget? child; - - // Determine the child of the Container with the images based on the indicator type. - switch (widget.type) { - case CarouselSliderIndicator.insideText: - child = _ImageOverlay( - size: widget.boxSize, - title: _Title(text: widget.provideText!(position)), - /*pageIndicator: _PageIndicator( - position: position, - elementCount: widget.elementCount, - ),*/ - ); - break; - case CarouselSliderIndicator.below: - child = null; - break; - } - return GestureDetector( onTap: () { // An assignment is required for the Dart compiler to be sure that the @@ -235,7 +179,11 @@ class _CarouselSliderBoxState extends State { decoration: BoxDecoration( image: _buildDecorationImage(index), ), - child: child, + child: _ImageOverlay( + size: widget.boxSize, + title: (widget.title != null || widget.imageNameStyle != ImageNameStyle.none) ? + _Title(text: widget.provideText!(position), imageNameStyle: widget.imageNameStyle) : null + ), ), ); } @@ -257,11 +205,11 @@ class _ImageOverlay extends StatelessWidget { const _ImageOverlay({ Key? key, required this.size, - required this.title, + this.title, }) : super(key: key); final Size size; - final Widget title; + final Widget? title; @override Widget build(BuildContext context) { @@ -269,8 +217,7 @@ class _ImageOverlay extends StatelessWidget { width: size.width, height: size.height, color: Colors.transparent, - child: title - ); + child: title); } } @@ -278,16 +225,18 @@ class _ImageOverlay extends StatelessWidget { class _Title extends StatelessWidget { const _Title({ Key? key, - required this.text, + required this.text, required this.imageNameStyle, }) : super(key: key); final String text; + final ImageNameStyle imageNameStyle; @override Widget build(BuildContext context) { final appSetting = Provider.of(context); return Container( - child: Padding( + child: imageNameStyle == ImageNameStyle.subtitle ? + Padding( padding: EdgeInsets.fromLTRB(26, 46, 12, 12), child: Text( text, @@ -298,7 +247,20 @@ class _Title extends StatelessWidget { fontWeight: FontWeight.w700, ), ), - ), + ) : + Padding( + padding: EdgeInsets.fromLTRB(12, 12, 12, 12), + child: Text( + text, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTitleFontSize + 4, + fontWeight: FontWeight.w900, + ), + ) + ) + , decoration: BoxDecoration( color: Colors.white, gradient: LinearGradient( diff --git a/lib/ui/widgets/carousel_slider_artwork.dart b/lib/ui/widgets/carousel_slider_artwork.dart index 558c8a8..fa61369 100644 --- a/lib/ui/widgets/carousel_slider_artwork.dart +++ b/lib/ui/widgets/carousel_slider_artwork.dart @@ -19,10 +19,10 @@ class CarouselSliderBoxImage extends StatelessWidget { @override Widget build(BuildContext context) { return CarouselSliderBox( - type: CarouselSliderIndicator.below, boxSize: boxSize, elementCount: imageLinks.length, provideImage: (index) => NetworkImage(imageLinks[index]), + imageNameStyle: ImageNameStyle.none, ); } } diff --git a/lib/ui/widgets/carousel_slider_campus.dart b/lib/ui/widgets/carousel_slider_campus.dart index 10dbda8..deccf1b 100644 --- a/lib/ui/widgets/carousel_slider_campus.dart +++ b/lib/ui/widgets/carousel_slider_campus.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:kunstforum_tu_darmstadt/config/route_generator.dart'; import 'package:kunstforum_tu_darmstadt/models/exhibition.dart'; import 'package:kunstforum_tu_darmstadt/ui/widgets/carousel_slider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; /// Builds a carousel slider for displaying images provided by [campusExhibition]. /// The page indicator and a text is shown on top of the image. @@ -23,14 +24,15 @@ class CarouselSliderCampusBox extends StatelessWidget { @override Widget build(BuildContext context) { return CarouselSliderBox( - type: CarouselSliderIndicator.insideText, + title: AppLocalizations.of(context)!.campusArt.toUpperCase(), imageFit: BoxFit.cover, boxSize: boxSize, elementCount: campusExhibition.artworkList.length, provideImage: (index) => NetworkImage( campusExhibition.artworkList[index].images!.first, ), - provideText: (_) => campusExhibition.name, + imageNameStyle: ImageNameStyle.subtitle, + provideText: (index) => campusExhibition.artworkList[index].name, onTap: (index) { Navigator.of(context).pushNamed( RouteGenerator.audioGuideScreenRouteName, diff --git a/lib/ui/widgets/carousel_slider_exhibition.dart b/lib/ui/widgets/carousel_slider_exhibition.dart index da04df5..dfba419 100644 --- a/lib/ui/widgets/carousel_slider_exhibition.dart +++ b/lib/ui/widgets/carousel_slider_exhibition.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:kunstforum_tu_darmstadt/config/route_generator.dart'; import 'package:kunstforum_tu_darmstadt/models/exhibition.dart'; import 'package:kunstforum_tu_darmstadt/ui/widgets/carousel_slider.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; /// Builds a carousel slider for displaying the first images for each exhibition. /// The exhibitions are provided by the [exhibitionList]. @@ -25,7 +26,8 @@ class CarouselSliderBoxExhibition extends StatelessWidget { @override Widget build(BuildContext context) { return CarouselSliderBox( - type: CarouselSliderIndicator.insideText, + title: AppLocalizations.of(context)!.exhibition.toUpperCase(), + imageNameStyle: ImageNameStyle.subtitle, imageFit: BoxFit.cover, boxSize: boxSize, elementCount: exhibitionList.length, diff --git a/lib/ui/widgets/image_slider.dart b/lib/ui/widgets/image_slider.dart new file mode 100644 index 0000000..13b1aae --- /dev/null +++ b/lib/ui/widgets/image_slider.dart @@ -0,0 +1,228 @@ +import 'package:carousel_slider/carousel_slider.dart'; +import 'package:flutter/material.dart'; +import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; +import 'package:provider/provider.dart'; + +class ImageSlider extends StatefulWidget { + const ImageSlider({ + Key? key, + this.enlargeCenterPage = true, + this.title, + this.imageNameStyle = ImageNameStyle.title, + this.carouselController, + required this.elementCount, + required this.provideImage, + required this.boxSize, + this.provideText, + this.onTap, + this.imageFit = BoxFit.contain, + }) : assert(title == null || + imageNameStyle != + ImageNameStyle + .title), // if a title is provided the image name cannot be displayed as a title + super(key: key); + final bool enlargeCenterPage; + final String? title; + final ImageNameStyle imageNameStyle; + final CarouselController? carouselController; + final int elementCount; + + /// The size of the box + final Size boxSize; + + /// A function to provide an [ImageProvider] for a given index. + /// The parameter [index] is guaranteed to be 0 <= index < elementCount. + final ImageProvider Function(int index) provideImage; + + /// A function to provide a text for a given index. + /// The parameter [index] is guaranteed to be 0 <= index < elementCount. + /// Only required if the [type] is set to [CarouselSliderIndicator.insideText]. + final String Function(int index)? provideText; + + /// A function which will be called if a image has been tapped by a user. + /// The parameter [index] is the number of the currently displayed image and + /// is guaranteed to be 0 <= index < elementCount. + final void Function(int index)? onTap; + + /// The [BoxFit] of the displayed images in the carousel. + /// If not set, it defaults to [BoxFit.contain]. + final BoxFit imageFit; + + @override + _ImageSliderState createState() => _ImageSliderState(); +} + +class _ImageSliderState extends State { + /// The index of the image which is currently shown. + int position = 0; + + @override + void didChangeDependencies() { + // Run the precache method after the widget is built + _precacheNeighbours(position); + super.didChangeDependencies(); + } + + /// Loads the previous and the next image into the cache. + /// The method is called when the widget is initialized and + /// if the user swipes to change the image. + void _precacheNeighbours(int index) async { + // Precaches the next image in the carousel if there at least two images + if (widget.elementCount >= 2) { + final nextIndex = (index + 1) % widget.elementCount; + final next = widget.provideImage(nextIndex); + if (next is NetworkImage) { + precacheImage(next, context); + } + } + + // Precaches the previous image in the carousel if there at least three images + if (widget.elementCount >= 3) { + final previousIndex = (index - 1) % widget.elementCount; + final previous = widget.provideImage(previousIndex); + if (previous is NetworkImage) { + precacheImage(previous, context); + } + } + } + + @override + Widget build(BuildContext context) { + return CarouselSlider.builder( + carouselController: widget.carouselController, + options: CarouselOptions( + enlargeCenterPage: widget.enlargeCenterPage, + aspectRatio: 1, + // Only enable infinite scrolling when at least 2 artworks are to be shown + enableInfiniteScroll: widget.elementCount > 1, + viewportFraction: 1, + onPageChanged: (index, reason) { + setState(() { + position = index; + }); + _precacheNeighbours(index); + }, + ), + itemCount: widget.elementCount, + itemBuilder: (context, index, realIndex) => _buildImage(index), + ); + } + + /// Builds the correct image widget for the [widget.type]. + Widget _buildImage(int index) { + final Widget? child; + + // Determine the child of the Container with the images based on the indicator type. + /*switch (widget.type) { + case CarouselSliderIndicator.insideText:*/ + child = _ImageOverlay( + size: widget.boxSize, + title: _Title(text: widget.provideText!(position)), + /*pageIndicator: _PageIndicator( + position: position, + elementCount: widget.elementCount, + ),*/ + ); + /*break; + case CarouselSliderIndicator.below: + child = null; + break; + }*/ + + return GestureDetector( + onTap: () { + // An assignment is required for the Dart compiler to be sure that the + // onTap method is not null after the if-check. + final onTap = widget.onTap; + if (onTap != null) onTap(index); + }, + child: Container( + decoration: BoxDecoration( + image: _buildDecorationImage(index), + ), + child: child, + ), + ); + } + + /// Builds a [DecorationImage] which can be used in [Container]s for + /// displaying the image provided by [widget.provideImage] at the [index]. + DecorationImage _buildDecorationImage(int index) { + return DecorationImage( + image: widget.provideImage(index), + fit: widget.imageFit, + ); + } +} + +/// A [StatelessWidget] used to overlay information on an image. +/// The [size] are the dimensions of the image viewport. +/// The [title] is displayed on the upper left corner. +class _ImageOverlay extends StatelessWidget { + const _ImageOverlay({ + Key? key, + required this.size, + required this.title, + }) : super(key: key); + + final Size size; + final Widget title; + + @override + Widget build(BuildContext context) { + return Container( + width: size.width, + height: size.height, + color: Colors.transparent, + child: title); + } +} + +/// A [StatelessWidget] displaying the given [text] formatted as a title. +class _Title extends StatelessWidget { + const _Title({ + Key? key, + required this.text, + }) : super(key: key); + + final String text; + + @override + Widget build(BuildContext context) { + final appSetting = Provider.of(context); + return Container( + child: Padding( + padding: EdgeInsets.fromLTRB(26, 46, 12, 12), + child: Text( + text, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTextFontSize, + fontWeight: FontWeight.w700, + ), + ), + ), + decoration: BoxDecoration( + color: Colors.white, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.6), + Colors.black.withOpacity(0.0), + ], + stops: [0, 0.5], + ), + ), + ); + } +} + +enum ImageNameStyle { + none, + + title, + + subtitle +} -- GitLab From 889e87cde71613e1822df205171db1bd24e998ba Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Fri, 7 Jan 2022 00:41:51 +0100 Subject: [PATCH 3/6] Bug fixes and adjustments for mockup: - like in the last commit the page indicator and title of the slider are fix - only the subtitle oder if the the title is the exhibition name the title moves with the slider - the text ist displayed before a black gradient - on the MainScreen you cannot swipe vertically - on the ExhibitionsScreen the exhibitions are presented with the first image - the other images are not displayed, the slider is deleted like shown in the mockup --- lib/ui/screens/exhibitions_screen.dart | 28 +-- lib/ui/screens/main_screen.dart | 12 +- lib/ui/widgets/carousel_slider.dart | 142 ++++----------- lib/ui/widgets/image_overlay.dart | 85 +++++++++ lib/ui/widgets/image_slider.dart | 228 ------------------------ lib/ui/widgets/new_carousel_slider.dart | 0 6 files changed, 140 insertions(+), 355 deletions(-) create mode 100644 lib/ui/widgets/image_overlay.dart delete mode 100644 lib/ui/widgets/image_slider.dart delete mode 100644 lib/ui/widgets/new_carousel_slider.dart diff --git a/lib/ui/screens/exhibitions_screen.dart b/lib/ui/screens/exhibitions_screen.dart index 21f0bc7..ff91f6c 100644 --- a/lib/ui/screens/exhibitions_screen.dart +++ b/lib/ui/screens/exhibitions_screen.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:kunstforum_tu_darmstadt/ui/widgets/image_overlay.dart'; import 'package:provider/provider.dart'; //*********************************************** //***** Custom Imports ******* //*********************************************** -import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; -import 'package:kunstforum_tu_darmstadt/ui/widgets/carousel_slider_campus.dart'; import 'package:kunstforum_tu_darmstadt/ui/widgets/custom_app_bar.dart'; import 'package:kunstforum_tu_darmstadt/api/artwork_service.dart'; @@ -31,14 +30,23 @@ class ExhibitionsScreen extends StatelessWidget { ? constraints.maxHeight / 2 : constraints.maxHeight); return ListView.builder( - scrollDirection: Axis.vertical, - itemCount: artworkService.exhibitionList.length, - itemBuilder: (BuildContext context, int i) { - return CarouselSliderCampusBox( - campusExhibition: artworkService.exhibitionList[i], - boxSize: boxSize, - ); - }); + scrollDirection: Axis.vertical, + itemCount: artworkService.exhibitionList.length, + itemBuilder: (BuildContext context, int i) { + return Container( + decoration: BoxDecoration( + image: DecorationImage( + image: NetworkImage(artworkService + .exhibitionList[i].artworkList[0].images!.first), + fit: BoxFit.cover, + ), + ), + child: ImageOverlay( + size: boxSize, + title: artworkService.exhibitionList[i].name), + ); + }, + ); }, ); }, diff --git a/lib/ui/screens/main_screen.dart b/lib/ui/screens/main_screen.dart index a81d914..0f28e69 100644 --- a/lib/ui/screens/main_screen.dart +++ b/lib/ui/screens/main_screen.dart @@ -34,13 +34,13 @@ class MainScreen extends StatelessWidget { return Column( children: [ CarouselSliderCampusBox( - campusExhibition: artworkService.campusExhibition, - boxSize: boxSize, - ), + campusExhibition: artworkService.campusExhibition, + boxSize: boxSize, + ), CarouselSliderBoxExhibition( - exhibitionList: artworkService.exhibitionList, - boxSize: boxSize, - ) + exhibitionList: artworkService.exhibitionList, + boxSize: boxSize, + ) ], ); }, diff --git a/lib/ui/widgets/carousel_slider.dart b/lib/ui/widgets/carousel_slider.dart index c12a370..ee8617a 100644 --- a/lib/ui/widgets/carousel_slider.dart +++ b/lib/ui/widgets/carousel_slider.dart @@ -1,10 +1,9 @@ -import 'package:auto_size_text/auto_size_text.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:flutter/material.dart'; import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; +import 'package:kunstforum_tu_darmstadt/ui/widgets/image_overlay.dart'; import 'package:provider/provider.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; /// A enum for choosing if and how titles should be displayed. enum ImageNameStyle { @@ -16,7 +15,6 @@ enum ImageNameStyle { } class CarouselSliderBox extends StatefulWidget { - /// The [BoxFit] of the displayed images in the carousel. /// If not set, it defaults to [BoxFit.contain]. final BoxFit imageFit; @@ -59,9 +57,10 @@ class CarouselSliderBox extends StatefulWidget { this.onTap, this.showPageIndicator = true, this.title, - this.imageNameStyle = ImageNameStyle.title, this.enlargeCenterPage = true, + this.imageNameStyle = ImageNameStyle.title, + this.enlargeCenterPage = true, }) : assert(title == null || imageNameStyle != ImageNameStyle.title), - assert(provideText != null || imageNameStyle == ImageNameStyle.none), + assert(provideText == null || imageNameStyle != ImageNameStyle.none), super(key: key); @override @@ -112,7 +111,6 @@ class _CarouselSliderBoxState extends State { height: widget.boxSize.height, child: _buildCarouselSlider(), ); - } /// Builds a [CarouselSlider] widget containing the images. @@ -125,8 +123,7 @@ class _CarouselSliderBoxState extends State { CarouselSlider.builder( carouselController: carouselController, options: CarouselOptions( - enlargeCenterPage: - widget.enlargeCenterPage, + enlargeCenterPage: widget.enlargeCenterPage, aspectRatio: 1, // Only enable infinite scrolling when at least 2 artworks are to be shown enableInfiniteScroll: widget.elementCount > 1, @@ -141,8 +138,8 @@ class _CarouselSliderBoxState extends State { itemCount: widget.elementCount, itemBuilder: (context, index, realIndex) => _buildImage(index), ), - if(widget.title != null) - Positioned( + if (widget.title != null) + Positioned( top: 20, left: 20, child: Text( @@ -153,14 +150,16 @@ class _CarouselSliderBoxState extends State { fontSize: appSetting.bodyTitleFontSize + 4, fontWeight: FontWeight.w900, ), - )), - Positioned( - right: 20, - bottom: 20, - child: _PageIndicator( - position: position, - elementCount: widget.elementCount, - onTap: (index) => carouselController.animateToPage(index))), + ), + ), + if (widget.elementCount >= 2) + Positioned( + right: 20, + bottom: 20, + child: _PageIndicator( + position: position, + elementCount: widget.elementCount, + onTap: (index) => carouselController.animateToPage(index))), //) ], ); @@ -177,101 +176,22 @@ class _CarouselSliderBoxState extends State { }, child: Container( decoration: BoxDecoration( - image: _buildDecorationImage(index), - ), - child: _ImageOverlay( - size: widget.boxSize, - title: (widget.title != null || widget.imageNameStyle != ImageNameStyle.none) ? - _Title(text: widget.provideText!(position), imageNameStyle: widget.imageNameStyle) : null - ), - ), - ); - } - - /// Builds a [DecorationImage] which can be used in [Container]s for - /// displaying the image provided by [widget.provideImage] at the [index]. - DecorationImage _buildDecorationImage(int index) { - return DecorationImage( - image: widget.provideImage(index), - fit: widget.imageFit, - ); - } -} - -/// A [StatelessWidget] used to overlay information on an image. -/// The [size] are the dimensions of the image viewport. -/// The [title] is displayed on the upper left corner. -class _ImageOverlay extends StatelessWidget { - const _ImageOverlay({ - Key? key, - required this.size, - this.title, - }) : super(key: key); - - final Size size; - final Widget? title; - - @override - Widget build(BuildContext context) { - return Container( - width: size.width, - height: size.height, - color: Colors.transparent, - child: title); - } -} - -/// A [StatelessWidget] displaying the given [text] formatted as a title. -class _Title extends StatelessWidget { - const _Title({ - Key? key, - required this.text, required this.imageNameStyle, - }) : super(key: key); - - final String text; - final ImageNameStyle imageNameStyle; - - @override - Widget build(BuildContext context) { - final appSetting = Provider.of(context); - return Container( - child: imageNameStyle == ImageNameStyle.subtitle ? - Padding( - padding: EdgeInsets.fromLTRB(26, 46, 12, 12), - child: Text( - text, - style: TextStyle( - color: Colors.white, - fontFamily: 'Avenir', - fontSize: appSetting.bodyTextFontSize, - fontWeight: FontWeight.w700, + image: DecorationImage( + image: widget.provideImage(index), + fit: widget.imageFit, ), ), - ) : - Padding( - padding: EdgeInsets.fromLTRB(12, 12, 12, 12), - child: Text( - text, - style: TextStyle( - color: Colors.white, - fontFamily: 'Avenir', - fontSize: appSetting.bodyTitleFontSize + 4, - fontWeight: FontWeight.w900, - ), - ) - ) - , - decoration: BoxDecoration( - color: Colors.white, - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withOpacity(0.6), - Colors.black.withOpacity(0.0), - ], - stops: [0, 0.5], - ), + child: (widget.provideText != null && + widget.imageNameStyle != ImageNameStyle.none) + ? ImageOverlay( + size: widget.boxSize, + title: widget.imageNameStyle == ImageNameStyle.title + ? widget.provideText!(position) + : null, + subtitle: widget.imageNameStyle == ImageNameStyle.subtitle + ? widget.provideText!(position) + : null) + : null, ), ); } diff --git a/lib/ui/widgets/image_overlay.dart b/lib/ui/widgets/image_overlay.dart new file mode 100644 index 0000000..e2e3307 --- /dev/null +++ b/lib/ui/widgets/image_overlay.dart @@ -0,0 +1,85 @@ +import 'package:flutter/material.dart'; +import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; +import 'package:provider/provider.dart'; + +class ImageOverlay extends StatelessWidget { + const ImageOverlay({Key? key, required this.size, this.title, this.subtitle}) + : assert(title != null || subtitle != null), + super(key: key); + + final Size size; + final String? title; + final String? subtitle; + + @override + Widget build(BuildContext context) { + return Container( + width: size.width, + height: size.height, + color: Colors.transparent, + child: _Title(title: title, subtitle: subtitle), + ); + } +} + +/// A [StatelessWidget] displaying the given [text] formatted as a title. +class _Title extends StatelessWidget { + const _Title({ + Key? key, + this.title, + this.subtitle, + }) : assert(title != null || subtitle != null), + super(key: key); + + final String? title; + final String? subtitle; + + @override + Widget build(BuildContext context) { + final appSetting = Provider.of(context); + return Container( + child: Stack( + children: [ + if (title != null) + Padding( + padding: EdgeInsets.fromLTRB(20, 20, 12, 12), + child: Text( + title!, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTitleFontSize + 4, + fontWeight: FontWeight.w900, + ), + ), + ), + if (subtitle != null) + Padding( + padding: EdgeInsets.fromLTRB(26, 46, 12, 12), + child: Text( + subtitle!, + style: TextStyle( + color: Colors.white, + fontFamily: 'Avenir', + fontSize: appSetting.bodyTextFontSize, + fontWeight: FontWeight.w700, + ), + ), + ), + ], + ), + decoration: BoxDecoration( + color: Colors.white, + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.black.withOpacity(0.6), + Colors.black.withOpacity(0.0), + ], + stops: [0, 0.5], + ), + ), + ); + } +} diff --git a/lib/ui/widgets/image_slider.dart b/lib/ui/widgets/image_slider.dart deleted file mode 100644 index 13b1aae..0000000 --- a/lib/ui/widgets/image_slider.dart +++ /dev/null @@ -1,228 +0,0 @@ -import 'package:carousel_slider/carousel_slider.dart'; -import 'package:flutter/material.dart'; -import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; -import 'package:provider/provider.dart'; - -class ImageSlider extends StatefulWidget { - const ImageSlider({ - Key? key, - this.enlargeCenterPage = true, - this.title, - this.imageNameStyle = ImageNameStyle.title, - this.carouselController, - required this.elementCount, - required this.provideImage, - required this.boxSize, - this.provideText, - this.onTap, - this.imageFit = BoxFit.contain, - }) : assert(title == null || - imageNameStyle != - ImageNameStyle - .title), // if a title is provided the image name cannot be displayed as a title - super(key: key); - final bool enlargeCenterPage; - final String? title; - final ImageNameStyle imageNameStyle; - final CarouselController? carouselController; - final int elementCount; - - /// The size of the box - final Size boxSize; - - /// A function to provide an [ImageProvider] for a given index. - /// The parameter [index] is guaranteed to be 0 <= index < elementCount. - final ImageProvider Function(int index) provideImage; - - /// A function to provide a text for a given index. - /// The parameter [index] is guaranteed to be 0 <= index < elementCount. - /// Only required if the [type] is set to [CarouselSliderIndicator.insideText]. - final String Function(int index)? provideText; - - /// A function which will be called if a image has been tapped by a user. - /// The parameter [index] is the number of the currently displayed image and - /// is guaranteed to be 0 <= index < elementCount. - final void Function(int index)? onTap; - - /// The [BoxFit] of the displayed images in the carousel. - /// If not set, it defaults to [BoxFit.contain]. - final BoxFit imageFit; - - @override - _ImageSliderState createState() => _ImageSliderState(); -} - -class _ImageSliderState extends State { - /// The index of the image which is currently shown. - int position = 0; - - @override - void didChangeDependencies() { - // Run the precache method after the widget is built - _precacheNeighbours(position); - super.didChangeDependencies(); - } - - /// Loads the previous and the next image into the cache. - /// The method is called when the widget is initialized and - /// if the user swipes to change the image. - void _precacheNeighbours(int index) async { - // Precaches the next image in the carousel if there at least two images - if (widget.elementCount >= 2) { - final nextIndex = (index + 1) % widget.elementCount; - final next = widget.provideImage(nextIndex); - if (next is NetworkImage) { - precacheImage(next, context); - } - } - - // Precaches the previous image in the carousel if there at least three images - if (widget.elementCount >= 3) { - final previousIndex = (index - 1) % widget.elementCount; - final previous = widget.provideImage(previousIndex); - if (previous is NetworkImage) { - precacheImage(previous, context); - } - } - } - - @override - Widget build(BuildContext context) { - return CarouselSlider.builder( - carouselController: widget.carouselController, - options: CarouselOptions( - enlargeCenterPage: widget.enlargeCenterPage, - aspectRatio: 1, - // Only enable infinite scrolling when at least 2 artworks are to be shown - enableInfiniteScroll: widget.elementCount > 1, - viewportFraction: 1, - onPageChanged: (index, reason) { - setState(() { - position = index; - }); - _precacheNeighbours(index); - }, - ), - itemCount: widget.elementCount, - itemBuilder: (context, index, realIndex) => _buildImage(index), - ); - } - - /// Builds the correct image widget for the [widget.type]. - Widget _buildImage(int index) { - final Widget? child; - - // Determine the child of the Container with the images based on the indicator type. - /*switch (widget.type) { - case CarouselSliderIndicator.insideText:*/ - child = _ImageOverlay( - size: widget.boxSize, - title: _Title(text: widget.provideText!(position)), - /*pageIndicator: _PageIndicator( - position: position, - elementCount: widget.elementCount, - ),*/ - ); - /*break; - case CarouselSliderIndicator.below: - child = null; - break; - }*/ - - return GestureDetector( - onTap: () { - // An assignment is required for the Dart compiler to be sure that the - // onTap method is not null after the if-check. - final onTap = widget.onTap; - if (onTap != null) onTap(index); - }, - child: Container( - decoration: BoxDecoration( - image: _buildDecorationImage(index), - ), - child: child, - ), - ); - } - - /// Builds a [DecorationImage] which can be used in [Container]s for - /// displaying the image provided by [widget.provideImage] at the [index]. - DecorationImage _buildDecorationImage(int index) { - return DecorationImage( - image: widget.provideImage(index), - fit: widget.imageFit, - ); - } -} - -/// A [StatelessWidget] used to overlay information on an image. -/// The [size] are the dimensions of the image viewport. -/// The [title] is displayed on the upper left corner. -class _ImageOverlay extends StatelessWidget { - const _ImageOverlay({ - Key? key, - required this.size, - required this.title, - }) : super(key: key); - - final Size size; - final Widget title; - - @override - Widget build(BuildContext context) { - return Container( - width: size.width, - height: size.height, - color: Colors.transparent, - child: title); - } -} - -/// A [StatelessWidget] displaying the given [text] formatted as a title. -class _Title extends StatelessWidget { - const _Title({ - Key? key, - required this.text, - }) : super(key: key); - - final String text; - - @override - Widget build(BuildContext context) { - final appSetting = Provider.of(context); - return Container( - child: Padding( - padding: EdgeInsets.fromLTRB(26, 46, 12, 12), - child: Text( - text, - style: TextStyle( - color: Colors.white, - fontFamily: 'Avenir', - fontSize: appSetting.bodyTextFontSize, - fontWeight: FontWeight.w700, - ), - ), - ), - decoration: BoxDecoration( - color: Colors.white, - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.black.withOpacity(0.6), - Colors.black.withOpacity(0.0), - ], - stops: [0, 0.5], - ), - ), - ); - } -} - -enum ImageNameStyle { - none, - - title, - - subtitle -} diff --git a/lib/ui/widgets/new_carousel_slider.dart b/lib/ui/widgets/new_carousel_slider.dart deleted file mode 100644 index e69de29..0000000 -- GitLab From d9540d75d02871f13d4ff155eac0a53f1fc5aa32 Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Fri, 7 Jan 2022 15:47:10 +0100 Subject: [PATCH 4/6] comments added and small bug fix. til now when you slided through the images the title changes while sliding --- lib/ui/widgets/carousel_slider.dart | 53 +++++++++++++++++++---------- lib/ui/widgets/image_overlay.dart | 33 +++++------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/lib/ui/widgets/carousel_slider.dart b/lib/ui/widgets/carousel_slider.dart index ee8617a..c44cf57 100644 --- a/lib/ui/widgets/carousel_slider.dart +++ b/lib/ui/widgets/carousel_slider.dart @@ -5,12 +5,13 @@ import 'package:kunstforum_tu_darmstadt/ui/widgets/image_overlay.dart'; import 'package:provider/provider.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; -/// A enum for choosing if and how titles should be displayed. +/// A enum for choosing if and how image names should be displayed. enum ImageNameStyle { + // the name of the current image is not displayed none, - + // the name of the current image is displayed as a title at the top of the image title, - + // the name of the current image is displayed as a subtitle under a fixed title subtitle } @@ -31,7 +32,6 @@ class CarouselSliderBox extends StatefulWidget { /// A function to provide a text for a given index. /// The parameter [index] is guaranteed to be 0 <= index < elementCount. - /// Only required if the [type] is set to [CarouselSliderIndicator.insideText]. final String Function(int index)? provideText; /// A function which will be called if a image has been tapped by a user. @@ -39,12 +39,20 @@ class CarouselSliderBox extends StatefulWidget { /// is guaranteed to be 0 <= index < elementCount. final void Function(int index)? onTap; - final bool showPageIndicator; - + /// The title of the slider. + /// if a title is provided the imageNameStyle must not be set to ImageNameStyle.title final String? title; + /// The style in which the image names provided by [provideText] should be displayed + /// if it is set to [ImageNameStyle.none], the name of the current image is not displayed + /// if it is set to [ImageNameStyle.title], the name of the current image is displayed as a title at the top of the image + /// if it is set to [ImageNameStyle.subtitle], the name of the current image is displayed as a subtitle under the given fixed [title]. The title must be set in this case + /// If not set, it defaults to [ImageNameStyle.title]. final ImageNameStyle imageNameStyle; + /// Determines if current page should be larger then the side images, + /// creating a feeling of depth in the carousel. + /// If not set, it defaults to false. final bool enlargeCenterPage; CarouselSliderBox({ @@ -55,12 +63,20 @@ class CarouselSliderBox extends StatefulWidget { this.imageFit = BoxFit.contain, this.provideText, this.onTap, - this.showPageIndicator = true, this.title, this.imageNameStyle = ImageNameStyle.title, this.enlargeCenterPage = true, - }) : assert(title == null || imageNameStyle != ImageNameStyle.title), - assert(provideText == null || imageNameStyle != ImageNameStyle.none), + }) : assert(title == null || + imageNameStyle != + ImageNameStyle + .title), // if the image name is displayed as the title, no title must be specified + assert(provideText == null || + imageNameStyle != + ImageNameStyle + .none), // if names for the images are given, these names should also be displayed + assert(imageNameStyle != ImageNameStyle.subtitle || + title != + null), // if the image name is displayed as the subtitle, there has to be a fixed title for the slider super(key: key); @override @@ -154,13 +170,14 @@ class _CarouselSliderBoxState extends State { ), if (widget.elementCount >= 2) Positioned( - right: 20, - bottom: 20, - child: _PageIndicator( - position: position, - elementCount: widget.elementCount, - onTap: (index) => carouselController.animateToPage(index))), - //) + right: 20, + bottom: 20, + child: _PageIndicator( + position: position, + elementCount: widget.elementCount, + onTap: (index) => carouselController.animateToPage(index), + ), + ), ], ); } @@ -186,10 +203,10 @@ class _CarouselSliderBoxState extends State { ? ImageOverlay( size: widget.boxSize, title: widget.imageNameStyle == ImageNameStyle.title - ? widget.provideText!(position) + ? widget.provideText!(index) : null, subtitle: widget.imageNameStyle == ImageNameStyle.subtitle - ? widget.provideText!(position) + ? widget.provideText!(index) : null) : null, ), diff --git a/lib/ui/widgets/image_overlay.dart b/lib/ui/widgets/image_overlay.dart index e2e3307..9687b57 100644 --- a/lib/ui/widgets/image_overlay.dart +++ b/lib/ui/widgets/image_overlay.dart @@ -2,42 +2,26 @@ import 'package:flutter/material.dart'; import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; import 'package:provider/provider.dart'; +/// A [StatelessWidget] displaying the given [title] and [subtitle] if given on a black gradient. +/// class ImageOverlay extends StatelessWidget { const ImageOverlay({Key? key, required this.size, this.title, this.subtitle}) : assert(title != null || subtitle != null), super(key: key); - + + /// The size of the overlay (size of the image to be overlayed) final Size size; + /// The title that should be displayed. final String? title; + /// The subtitle that should be displayed. It will be displayed below the title in a smaller font size final String? subtitle; @override Widget build(BuildContext context) { + final appSetting = Provider.of(context); return Container( width: size.width, height: size.height, - color: Colors.transparent, - child: _Title(title: title, subtitle: subtitle), - ); - } -} - -/// A [StatelessWidget] displaying the given [text] formatted as a title. -class _Title extends StatelessWidget { - const _Title({ - Key? key, - this.title, - this.subtitle, - }) : assert(title != null || subtitle != null), - super(key: key); - - final String? title; - final String? subtitle; - - @override - Widget build(BuildContext context) { - final appSetting = Provider.of(context); - return Container( child: Stack( children: [ if (title != null) @@ -45,6 +29,7 @@ class _Title extends StatelessWidget { padding: EdgeInsets.fromLTRB(20, 20, 12, 12), child: Text( title!, + maxLines: subtitle != null ? 1 : null, style: TextStyle( color: Colors.white, fontFamily: 'Avenir', @@ -82,4 +67,4 @@ class _Title extends StatelessWidget { ), ); } -} +} \ No newline at end of file -- GitLab From 23bd6afcb5c2cc778803a1760735a5b81e2dacf7 Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Fri, 7 Jan 2022 15:57:11 +0100 Subject: [PATCH 5/6] small changes - disabled Landscapemode - comment corrections - ImageOverlay does not need to know its size. It will just expand to the parent widget. --- lib/main.dart | 1 + lib/ui/screens/exhibitions_screen.dart | 9 ++------- lib/ui/widgets/carousel_slider.dart | 5 +++-- lib/ui/widgets/image_overlay.dart | 8 ++------ 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 51e4344..ef7c422 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -25,6 +25,7 @@ bool? showIntroScreen; /// Runs the app by building the widget [KuTUD] void main() async { WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); final prefs = await SharedPreferences.getInstance(); showIntroScreen = prefs.getBool("showIntroScreen") ?? true; // uncomment the next two lines and the imports for release version before merging in master diff --git a/lib/ui/screens/exhibitions_screen.dart b/lib/ui/screens/exhibitions_screen.dart index ff91f6c..25f2f3d 100644 --- a/lib/ui/screens/exhibitions_screen.dart +++ b/lib/ui/screens/exhibitions_screen.dart @@ -10,7 +10,7 @@ import 'package:kunstforum_tu_darmstadt/api/artwork_service.dart'; /// /// A [StatelessWidget] that displays the exhibitions page of the app with a central [BottomNavigationBar] -/// and a [CustomAppBar]. The Screen displays a list of exhibitions fetched from backend in its body as [CarouselSliderBox] +/// and a [CustomAppBar]. The Screen displays the list of all exhibitions fetched from backend /// class ExhibitionsScreen extends StatelessWidget { //*************************************************** @@ -24,16 +24,12 @@ class ExhibitionsScreen extends StatelessWidget { builder: (context, orientation) { return LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { - Size boxSize = Size( - constraints.maxWidth, - orientation == Orientation.portrait - ? constraints.maxHeight / 2 - : constraints.maxHeight); return ListView.builder( scrollDirection: Axis.vertical, itemCount: artworkService.exhibitionList.length, itemBuilder: (BuildContext context, int i) { return Container( + height: constraints.maxHeight / 2, decoration: BoxDecoration( image: DecorationImage( image: NetworkImage(artworkService @@ -42,7 +38,6 @@ class ExhibitionsScreen extends StatelessWidget { ), ), child: ImageOverlay( - size: boxSize, title: artworkService.exhibitionList[i].name), ); }, diff --git a/lib/ui/widgets/carousel_slider.dart b/lib/ui/widgets/carousel_slider.dart index c44cf57..afbdf98 100644 --- a/lib/ui/widgets/carousel_slider.dart +++ b/lib/ui/widgets/carousel_slider.dart @@ -87,7 +87,7 @@ class _CarouselSliderBoxState extends State { /// The index of the image which is currently shown. int position = 0; - /// To controller for the CarouselSlider to swipe to the next page with the [AnimatedSmoothIndicator] + /// Used to control the the CarouselSlider for swiping to the next page with the [AnimatedSmoothIndicator] CarouselController carouselController = CarouselController(); @override @@ -192,6 +192,8 @@ class _CarouselSliderBoxState extends State { if (onTap != null) onTap(index); }, child: Container( + width: widget.boxSize.width, + height: widget.boxSize.height, decoration: BoxDecoration( image: DecorationImage( image: widget.provideImage(index), @@ -201,7 +203,6 @@ class _CarouselSliderBoxState extends State { child: (widget.provideText != null && widget.imageNameStyle != ImageNameStyle.none) ? ImageOverlay( - size: widget.boxSize, title: widget.imageNameStyle == ImageNameStyle.title ? widget.provideText!(index) : null, diff --git a/lib/ui/widgets/image_overlay.dart b/lib/ui/widgets/image_overlay.dart index 9687b57..1c5699c 100644 --- a/lib/ui/widgets/image_overlay.dart +++ b/lib/ui/widgets/image_overlay.dart @@ -5,12 +5,10 @@ import 'package:provider/provider.dart'; /// A [StatelessWidget] displaying the given [title] and [subtitle] if given on a black gradient. /// class ImageOverlay extends StatelessWidget { - const ImageOverlay({Key? key, required this.size, this.title, this.subtitle}) + const ImageOverlay({Key? key, this.title, this.subtitle}) : assert(title != null || subtitle != null), super(key: key); - - /// The size of the overlay (size of the image to be overlayed) - final Size size; + /// The title that should be displayed. final String? title; /// The subtitle that should be displayed. It will be displayed below the title in a smaller font size @@ -20,8 +18,6 @@ class ImageOverlay extends StatelessWidget { Widget build(BuildContext context) { final appSetting = Provider.of(context); return Container( - width: size.width, - height: size.height, child: Stack( children: [ if (title != null) -- GitLab From b70aca10bc173e9c94863f6dd069bab583ca0286 Mon Sep 17 00:00:00 2001 From: Philipp Hempel Date: Fri, 7 Jan 2022 16:09:50 +0100 Subject: [PATCH 6/6] ran flutter format . --- lib/ui/widgets/image_overlay.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/ui/widgets/image_overlay.dart b/lib/ui/widgets/image_overlay.dart index 1c5699c..bc33164 100644 --- a/lib/ui/widgets/image_overlay.dart +++ b/lib/ui/widgets/image_overlay.dart @@ -3,7 +3,7 @@ import 'package:kunstforum_tu_darmstadt/config/app_setting.dart'; import 'package:provider/provider.dart'; /// A [StatelessWidget] displaying the given [title] and [subtitle] if given on a black gradient. -/// +/// class ImageOverlay extends StatelessWidget { const ImageOverlay({Key? key, this.title, this.subtitle}) : assert(title != null || subtitle != null), @@ -11,6 +11,7 @@ class ImageOverlay extends StatelessWidget { /// The title that should be displayed. final String? title; + /// The subtitle that should be displayed. It will be displayed below the title in a smaller font size final String? subtitle; @@ -63,4 +64,4 @@ class ImageOverlay extends StatelessWidget { ), ); } -} \ No newline at end of file +} -- GitLab