From 06a548500c82691ac94899278c4c0cc10ee83767 Mon Sep 17 00:00:00 2001 From: braniii Date: Thu, 1 May 2025 12:21:27 +0200 Subject: [PATCH 1/6] Fix deprecated vall withOpacity. --- app/lib/core/theme.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/lib/core/theme.dart b/app/lib/core/theme.dart index 32890605..6ef59b7d 100644 --- a/app/lib/core/theme.dart +++ b/app/lib/core/theme.dart @@ -128,7 +128,9 @@ class TraleTheme { /// get elevated shade of clr Color colorOfElevation(double elevation, Color clr) => Color.alphaBlend( - getFontColor(clr).withOpacity(overlayOpacity(elevation)), clr, + getFontColor(clr).withValues( + alpha: overlayOpacity(elevation) + ), clr, ); /// 24 elevation shade of bg Color get bgShade1 => bgElevated(24); From 8365854f34dda2956432c9b29082b5f29019b584 Mon Sep 17 00:00:00 2001 From: braniii Date: Thu, 1 May 2025 12:22:05 +0200 Subject: [PATCH 2/6] Remove dropdown shadow of cards. --- app/lib/core/theme.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/lib/core/theme.dart b/app/lib/core/theme.dart index 6ef59b7d..d5796d1d 100644 --- a/app/lib/core/theme.dart +++ b/app/lib/core/theme.dart @@ -198,6 +198,10 @@ class TraleTheme { year2023: false, ); + const CardThemeData cardTheme = CardThemeData( + shadowColor: Colors.transparent, + ); + const ProgressIndicatorThemeData progressIndicatorTheme = ProgressIndicatorThemeData(year2023: false); @@ -209,6 +213,7 @@ class TraleTheme { ).copyWith( listTileTheme: listTileThemeData, sliderTheme: sliderTheme, + cardTheme: cardTheme, progressIndicatorTheme: progressIndicatorTheme, pageTransitionsTheme: const PageTransitionsTheme( builders: { From 1299f1c5c504fe015de938be1a2d0aa2076728ca Mon Sep 17 00:00:00 2001 From: braniii Date: Sat, 3 May 2025 23:26:33 +0200 Subject: [PATCH 3/6] Fix applying correct coloring of appbar on pages: about, faq and settings. --- app/lib/pages/about.dart | 17 ++++++----------- app/lib/pages/faq.dart | 17 ++++++----------- app/lib/pages/settings.dart | 17 ++++++----------- 3 files changed, 18 insertions(+), 33 deletions(-) diff --git a/app/lib/pages/about.dart b/app/lib/pages/about.dart index d9284f37..a007175e 100644 --- a/app/lib/pages/about.dart +++ b/app/lib/pages/about.dart @@ -366,17 +366,12 @@ class _About extends State { ); } - return Container( - color: Theme.of(context).colorScheme.surface, - child: SafeArea( - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool _) { - return [appBar()]; - }, - body: aboutList(), - ), - ), + return Scaffold( + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, bool _) { + return [appBar()]; + }, + body: aboutList(), ), ); } diff --git a/app/lib/pages/faq.dart b/app/lib/pages/faq.dart index be1f777b..702db735 100644 --- a/app/lib/pages/faq.dart +++ b/app/lib/pages/faq.dart @@ -188,17 +188,12 @@ class _FAQ extends State { ); } - return Container( - color: Theme.of(context).colorScheme.surface, - child: SafeArea( - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool _) { - return [appBar()]; - }, - body: faqList(), - ), - ), + return Scaffold( + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, bool _) { + return [appBar()]; + }, + body: faqList(), ), ); } diff --git a/app/lib/pages/settings.dart b/app/lib/pages/settings.dart index e0077691..e2f8540c 100644 --- a/app/lib/pages/settings.dart +++ b/app/lib/pages/settings.dart @@ -900,17 +900,12 @@ class _Settings extends State { ); } - return Container( - color: Theme.of(context).colorScheme.surface, - child: SafeArea( - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (BuildContext context, bool _) { - return [appBar()]; - }, - body: settingsList(), - ), - ), + return Scaffold( + body: NestedScrollView( + headerSliverBuilder: (BuildContext context, bool _) { + return [appBar()]; + }, + body: settingsList(), ), ); } From 72d468737bbf1f8996ea9256040f09fdfecf733d Mon Sep 17 00:00:00 2001 From: braniii Date: Sat, 3 May 2025 23:27:17 +0200 Subject: [PATCH 4/6] Fix nested scroll views on stats and measurement screens. --- app/lib/pages/measurementScreen.dart | 9 ++++----- app/lib/pages/overview.dart | 6 +++--- app/lib/pages/statScreen.dart | 14 +++++--------- app/lib/widget/customSliverAppBar.dart | 4 ++++ app/lib/widget/weightList.dart | 10 +++------- 5 files changed, 19 insertions(+), 24 deletions(-) diff --git a/app/lib/pages/measurementScreen.dart b/app/lib/pages/measurementScreen.dart index 8aa81e88..c5c0e0ea 100644 --- a/app/lib/pages/measurementScreen.dart +++ b/app/lib/pages/measurementScreen.dart @@ -52,11 +52,10 @@ class _MeasurementScreen extends State { } return StreamBuilder>( - stream: database.streamController.stream, - builder: ( - BuildContext context, AsyncSnapshot> snapshot, - ) => measurementScreenWrapper(context, snapshot) + stream: database.streamController.stream, + builder: ( + BuildContext context, AsyncSnapshot> snapshot, + ) => measurementScreenWrapper(context, snapshot), ); - } } diff --git a/app/lib/pages/overview.dart b/app/lib/pages/overview.dart index aa96b2ce..81ee90d2 100644 --- a/app/lib/pages/overview.dart +++ b/app/lib/pages/overview.dart @@ -121,10 +121,10 @@ class _OverviewScreen extends State { stream: database.streamController.stream, builder: ( BuildContext context, AsyncSnapshot> snapshot, - ) => SafeArea( + ) => SafeArea( key: key, - child: overviewScreenWrapper(context, snapshot) - ) + child: overviewScreenWrapper(context, snapshot), + ) ); } } diff --git a/app/lib/pages/statScreen.dart b/app/lib/pages/statScreen.dart index babc9226..a0e3f954 100644 --- a/app/lib/pages/statScreen.dart +++ b/app/lib/pages/statScreen.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:trale/core/measurement.dart'; import 'package:trale/core/measurementDatabase.dart'; -import 'package:trale/core/measurementStats.dart'; import 'package:trale/widget/emptyChart.dart'; import 'package:trale/widget/statsWidgetsList.dart'; @@ -21,14 +20,12 @@ class _StatsScreen extends State { @override Widget build(BuildContext context) { final MeasurementDatabase database = MeasurementDatabase(); - final MeasurementStats stats = MeasurementStats(); - Widget statsScreen(BuildContext context, AsyncSnapshot> snapshot) { return CustomScrollView( - controller: scrollController, + physics: const NeverScrollableScrollPhysics(), cacheExtent: MediaQuery.of(context).size.height, slivers: const [ SliverToBoxAdapter( @@ -47,12 +44,11 @@ class _StatsScreen extends State { : defaultEmptyChart(context:context); } - return StreamBuilder>( - stream: database.streamController.stream, - builder: ( - BuildContext context, AsyncSnapshot> snapshot, - ) => statsScreenWrapper(context, snapshot) + stream: database.streamController.stream, + builder: ( + BuildContext context, AsyncSnapshot> snapshot, + ) => statsScreenWrapper(context, snapshot), ); } diff --git a/app/lib/widget/customSliverAppBar.dart b/app/lib/widget/customSliverAppBar.dart index 5eb9586f..07acef88 100644 --- a/app/lib/widget/customSliverAppBar.dart +++ b/app/lib/widget/customSliverAppBar.dart @@ -15,6 +15,7 @@ class CustomSliverAppBar extends StatefulWidget { this.actions, this.backgroundColor, this.expandedHeight, + this.collapsedHeight, this.flexibleSpace, }); @@ -40,6 +41,8 @@ class CustomSliverAppBar extends StatefulWidget { final Color? backgroundColor; /// expanded height final double? expandedHeight; + /// collapsed height + final double? collapsedHeight; /// flexible space final Widget? flexibleSpace; @@ -63,6 +66,7 @@ class _CustomSliverAppBarState extends State { backgroundColor: widget.backgroundColor, automaticallyImplyLeading: widget.automaticallyImplyLeading, expandedHeight: widget.expandedHeight, + collapsedHeight: widget.collapsedHeight, flexibleSpace: widget.flexibleSpace, snap: widget.snap, floating: widget.floating, diff --git a/app/lib/widget/weightList.dart b/app/lib/widget/weightList.dart index 65905d09..50e60554 100644 --- a/app/lib/widget/weightList.dart +++ b/app/lib/widget/weightList.dart @@ -180,7 +180,7 @@ class _TotalWeightList extends State{ }; return CustomScrollView( - controller: widget.scrollController, + physics: const NeverScrollableScrollPhysics(), cacheExtent: 2 * MediaQuery.of(context).size.height, slivers: [ ...[ @@ -202,7 +202,7 @@ class _TotalWeightList extends State{ ), SliverToBoxAdapter( child: SizedBox( - height: 2 * TraleTheme.of(context)!.padding, + height: TraleTheme.of(context)!.padding, ), ), ], @@ -218,11 +218,7 @@ Widget getYearWidget({required BuildContext context, required String year, int? delayInMilliseconds}) { return Padding( - padding: EdgeInsets.only( - bottom: TraleTheme.of(context)!.padding, - left: TraleTheme.of(context)!.padding, - right: TraleTheme.of(context)!.padding, - ), + padding: EdgeInsets.all(TraleTheme.of(context)!.padding), child: StatCard( backgroundColor: Theme.of(context).colorScheme.primaryContainer, delayInMilliseconds: delayInMilliseconds, From f70bf218ee8745252c5d0995b5fa03498042232a Mon Sep 17 00:00:00 2001 From: braniii Date: Sun, 4 May 2025 00:47:08 +0200 Subject: [PATCH 5/6] Use m3 Carousel for theme selection. --- app/lib/pages/settings.dart | 208 +++++++++++++++++------------------- 1 file changed, 99 insertions(+), 109 deletions(-) diff --git a/app/lib/pages/settings.dart b/app/lib/pages/settings.dart index e2f8540c..e4f921f8 100644 --- a/app/lib/pages/settings.dart +++ b/app/lib/pages/settings.dart @@ -536,123 +536,113 @@ class ThemeSelection extends StatelessWidget { (traleNotifier.themeMode == ThemeMode.system && Theme.of(context).brightness == Brightness.dark); - return ListView.builder( - physics: const ClampingScrollPhysics(), - shrinkWrap: true, - scrollDirection: Axis.horizontal, - itemCount: TraleCustomTheme.values.length, - itemBuilder: (BuildContext context, int index) { + Widget themePreview(BuildContext context, TraleCustomTheme ctheme) { + return Expanded( + child: Container( + decoration: BoxDecoration( + borderRadius: + TraleTheme.of(context)!.borderShape.borderRadius, + border: Border.all( + color: Theme.of(context).colorScheme.onSurface, + ), + color: ( + isDark + ? traleNotifier.isAmoled + ? ctheme.dark(context).amoled + : ctheme.dark(context) + : ctheme.light(context) + ).themeData.colorScheme.surface, + ), + //width: 0.3 * MediaQuery.of(context).size.width, + margin: EdgeInsets.all(0.5 * TraleTheme.of(context)!.padding), + child: Container( + margin: EdgeInsets.all( + 0.04 * MediaQuery.of(context).size.width), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + AutoSizeText( + ctheme.name, + style: ( + isDark ? ctheme.dark(context): ctheme.light(context) + ).themeData.textTheme.labelSmall, + maxLines: 1, + ), + Divider( + height: 5, + color: ( + isDark ? ctheme.dark(context) : ctheme.light(context) + ).themeData.colorScheme.onSurface, + ), + AutoSizeText( + 'wwwwwwwwww', + style: ( + isDark ? ctheme.dark(context): ctheme.light(context) + ).themeData.textTheme.labelSmall, + maxLines: 2, + ), + const Spacer(), + Container( + decoration: BoxDecoration( + borderRadius: TraleTheme.of(context)! + .borderShape + .borderRadius, + color: ( + isDark ? ctheme.dark(context): ctheme.light(context) + ).themeData.colorScheme.primary, + ), + height: 0.05 * MediaQuery.of(context).size.width, + ), + ], + ), + ), + ), + ); + } + + return CarouselView.weighted( + scrollDirection: Axis.horizontal, + flexWeights: const [1, 3, 3, 3, 1], + padding: EdgeInsets.zero, + itemSnapping: true, + backgroundColor: Colors.transparent, + onTap: (int index) { + final TraleCustomTheme ctheme = TraleCustomTheme.values[index]; + traleNotifier.theme = TraleCustomTheme.values[index]; + }, + children: List.generate( + TraleCustomTheme.values.length, + (int index) { final TraleCustomTheme ctheme = TraleCustomTheme.values[index]; if (!traleNotifier.systemColorsAvailable && ctheme == TraleCustomTheme.system) { return const SizedBox.shrink(); } - return GestureDetector( - onTap: () { - traleNotifier.theme = TraleCustomTheme.values[index]; - }, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: Container( - decoration: BoxDecoration( - borderRadius: - TraleTheme.of(context)!.borderShape.borderRadius, - border: Border.all( - color: Theme.of(context).colorScheme.onSurface, - ), - color: (isDark - ? traleNotifier.isAmoled - ? ctheme.dark(context).amoled - : ctheme.dark(context) - : ctheme.light(context)) - .themeData - .colorScheme - .surface, - ), - width: 0.2 * MediaQuery.of(context).size.width, - margin: EdgeInsets.all(TraleTheme.of(context)!.padding), - child: Container( - margin: EdgeInsets.all( - 0.04 * MediaQuery.of(context).size.width), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AutoSizeText( - ctheme.name, - style: isDark - ? ctheme - .dark(context) - .themeData - .textTheme - .labelSmall - : ctheme - .light(context) - .themeData - .textTheme - .labelSmall, - maxLines: 1, - ), - Divider( - height: 5, - color: (isDark - ? ctheme.dark(context) - : ctheme.light(context)) - .themeData - .colorScheme - .onSurface, - ), - AutoSizeText( - 'wwwwwwwwww', - style: isDark - ? ctheme - .dark(context) - .themeData - .textTheme - .labelSmall - : ctheme - .light(context) - .themeData - .textTheme - .labelSmall, - maxLines: 2, - ), - const Spacer(), - Container( - decoration: BoxDecoration( - borderRadius: TraleTheme.of(context)! - .borderShape - .borderRadius, - color: (isDark - ? ctheme.dark(context) - : ctheme.light(context)) - .themeData - .colorScheme - .primary, - ), - height: 0.05 * MediaQuery.of(context).size.width, - ), - ], - ), - ), + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + themePreview(context, ctheme), + SizedBox( + height: 40, + child: FittedBox( + child: Radio( + value: TraleCustomTheme.values[index], + groupValue: traleNotifier.theme, + onChanged: (TraleCustomTheme? theme) { + if (theme != null) { + traleNotifier.theme = theme; + } + }, ), ), - Radio( - value: TraleCustomTheme.values[index], - groupValue: traleNotifier.theme, - onChanged: (TraleCustomTheme? theme) { - if (theme != null) { - traleNotifier.theme = theme; - } - }, - ), - ], - ), + ), + ], ); - }); + }, + ), + ); } } From 37995b54cee2347a79c4dc2427932a48eb6ee460 Mon Sep 17 00:00:00 2001 From: braniii Date: Sun, 4 May 2025 15:32:21 +0200 Subject: [PATCH 6/6] Scroll initially to selected theme idx. ToDo: refactor stateful part into ThemeSelection. --- app/lib/pages/onBoarding.dart | 2 +- app/lib/pages/settings.dart | 63 ++++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/app/lib/pages/onBoarding.dart b/app/lib/pages/onBoarding.dart index 21cbf2ab..0689a84e 100644 --- a/app/lib/pages/onBoarding.dart +++ b/app/lib/pages/onBoarding.dart @@ -91,7 +91,7 @@ class _OnBoardingPageState extends State { image: SizedBox( width: MediaQuery.of(context).size.width, height: 0.5 * MediaQuery.of(context).size.width, - child: const ThemeSelection(), + child: ThemeSelection(controller: CarouselController()), ), decoration: pageDecoration.copyWith( imagePadding: EdgeInsets.symmetric( diff --git a/app/lib/pages/settings.dart b/app/lib/pages/settings.dart index e4f921f8..6d838a0d 100644 --- a/app/lib/pages/settings.dart +++ b/app/lib/pages/settings.dart @@ -526,7 +526,8 @@ class InterpolationSetting extends StatelessWidget { /// ListTile for changing interpolation settings class ThemeSelection extends StatelessWidget { /// constructor - const ThemeSelection({super.key}); + final CarouselController controller; + const ThemeSelection({super.key, required this.controller}); @override Widget build(BuildContext context) { @@ -601,24 +602,26 @@ class ThemeSelection extends StatelessWidget { ); } + final List cthemes = TraleCustomTheme.values.toList(); + if (!traleNotifier.systemColorsAvailable) { + cthemes.remove(TraleCustomTheme.system); + } + return CarouselView.weighted( + controller: controller, scrollDirection: Axis.horizontal, flexWeights: const [1, 3, 3, 3, 1], padding: EdgeInsets.zero, itemSnapping: true, backgroundColor: Colors.transparent, onTap: (int index) { - final TraleCustomTheme ctheme = TraleCustomTheme.values[index]; - traleNotifier.theme = TraleCustomTheme.values[index]; + final TraleCustomTheme ctheme = cthemes[index]; + traleNotifier.theme = ctheme; }, children: List.generate( - TraleCustomTheme.values.length, + cthemes.length, (int index) { - final TraleCustomTheme ctheme = TraleCustomTheme.values[index]; - if (!traleNotifier.systemColorsAvailable && - ctheme == TraleCustomTheme.system) { - return const SizedBox.shrink(); - } + final TraleCustomTheme ctheme = cthemes[index]; return Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, @@ -628,13 +631,9 @@ class ThemeSelection extends StatelessWidget { height: 40, child: FittedBox( child: Radio( - value: TraleCustomTheme.values[index], + value: cthemes[index], groupValue: traleNotifier.theme, - onChanged: (TraleCustomTheme? theme) { - if (theme != null) { - traleNotifier.theme = theme; - } - }, + onChanged: (TraleCustomTheme? theme) {}, ), ), ), @@ -778,8 +777,40 @@ class Settings extends StatefulWidget { } class _Settings extends State { + late final CarouselController _carouselController; + bool loadedFirst = true; + + @override + void initState() { + super.initState(); + //_carouselController = CarouselController(initialItem: 0); + } + + @override + void dispose() { + _carouselController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { + if (loadedFirst) { + loadedFirst = false; + final List cthemes = TraleCustomTheme.values.toList(); + if (!Provider.of(context).systemColorsAvailable) { + cthemes.remove(TraleCustomTheme.system); + } + final int idx = cthemes.indexWhere( + (TraleCustomTheme theme) => + theme == Provider.of(context).theme, + ); + + // last two cannot be selected, so cap idx + _carouselController = CarouselController( + initialItem: idx < cthemes.length - 3 ? idx : cthemes.length - 3, + ); + } + final EdgeInsets padding = EdgeInsets.symmetric( horizontal: TraleTheme.of(context)!.padding, ); @@ -797,7 +828,7 @@ class _Settings extends State { ColoredContainer( height: 0.7 * MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width, - child: const ThemeSelection(), + child: ThemeSelection(controller: _carouselController), ), const DarkModeListTile(), const AmoledListTile(),