From 799b7d8403c504bd66ff0cc13eee497d8ce1e8bc Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Fri, 9 Jan 2026 21:12:09 +0100 Subject: [PATCH 1/9] Implemented new nav bar with selected animation --- lib/core/custom_theme.dart | 2 + .../main_menu/custom_navigation_bar.dart | 89 ++++++++++--------- lib/presentation/widgets/navbar_item.dart | 69 ++++++++++++-- pubspec.yaml | 2 +- 4 files changed, 110 insertions(+), 52 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index a6c6376..3f15ad9 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -11,6 +11,8 @@ class CustomTheme { static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); static const Color textColor = Colors.white; + static Color navBarItemSelectedColor = primaryColor.withValues(green: 0.4); + static Color navBarItemUnselectedColor = Colors.white.withValues(alpha: 0.6); // ==================== Border Radius ==================== static const double standardBorderRadius = 12.0; diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index a8b18c8..15f15b6 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -1,3 +1,5 @@ +import 'dart:ui'; + import 'package:flutter/material.dart'; import 'package:game_tracker/core/custom_theme.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; @@ -70,50 +72,49 @@ class _CustomNavigationBarState extends State backgroundColor: CustomTheme.backgroundColor, body: tabs[currentIndex], extendBody: true, - bottomNavigationBar: SafeArea( - minimum: const EdgeInsets.only(bottom: 30), - child: Container( - margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24), - color: CustomTheme.primaryColor, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(24), - child: SizedBox( - height: 60, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - NavbarItem( - index: 0, - isSelected: currentIndex == 0, - icon: Icons.home_rounded, - label: loc.home, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 1, - isSelected: currentIndex == 1, - icon: Icons.gamepad_rounded, - label: loc.matches, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 2, - isSelected: currentIndex == 2, - icon: Icons.group_rounded, - label: loc.groups, - onTabTapped: onTabTapped, - ), - NavbarItem( - index: 3, - isSelected: currentIndex == 3, - icon: Icons.bar_chart_rounded, - label: loc.statistics, - onTabTapped: onTabTapped, - ), - ], + bottomNavigationBar: ClipRRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Container( + decoration: BoxDecoration( + color: CustomTheme.boxColor.withValues(alpha: 0.8), + ), + child: SafeArea( + child: SizedBox( + height: 70, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + NavbarItem( + index: 0, + isSelected: currentIndex == 0, + icon: Icons.home_rounded, + label: loc.home, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 1, + isSelected: currentIndex == 1, + icon: Icons.gamepad_rounded, + label: loc.matches, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 2, + isSelected: currentIndex == 2, + icon: Icons.group_rounded, + label: loc.groups, + onTabTapped: onTabTapped, + ), + NavbarItem( + index: 3, + isSelected: currentIndex == 3, + icon: Icons.bar_chart_rounded, + label: loc.statistics, + onTabTapped: onTabTapped, + ), + ], + ), ), ), ), diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 13a8d4d..6e2e24e 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:game_tracker/core/custom_theme.dart'; /// A navigation bar item widget that represents a single tab in a navigation bar. /// - [index]: The index of the tab. @@ -35,7 +36,45 @@ class NavbarItem extends StatefulWidget { State createState() => _NavbarItemState(); } -class _NavbarItemState extends State { +class _NavbarItemState extends State + with SingleTickerProviderStateMixin { + /// Animation controller for the scale animation + late AnimationController _animationController; + + /// Scale animation for the icon when selected + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + + _scaleAnimation = Tween(begin: 1.0, end: 1.2).animate( + CurvedAnimation( + parent: _animationController, + curve: Curves.easeInOutBack, + ), + ); + + if (widget.isSelected) { + _animationController.forward(); + } + } + + // Retrigger animation on selection change + @override + void didUpdateWidget(NavbarItem oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.isSelected && !oldWidget.isSelected) { + _animationController.forward(); + } else if (!widget.isSelected && oldWidget.isSelected) { + _animationController.reverse(); + } + } + @override Widget build(BuildContext context) { return Expanded( @@ -48,19 +87,29 @@ class _NavbarItemState extends State { mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - widget.icon, - color: widget.isSelected ? Colors.white : Colors.black, + ScaleTransition( + scale: widget.isSelected + ? _scaleAnimation + : const AlwaysStoppedAnimation(1.0), + child: Icon( + widget.icon, + color: widget.isSelected + ? CustomTheme.navBarItemSelectedColor + : CustomTheme.navBarItemUnselectedColor, + size: 26, + ), ), const SizedBox(height: 4), Text( widget.label, style: TextStyle( - color: widget.isSelected ? Colors.white : Colors.black, - fontSize: 12, + color: widget.isSelected + ? CustomTheme.navBarItemSelectedColor + : CustomTheme.navBarItemUnselectedColor, + fontSize: widget.isSelected ? 12 : 11, fontWeight: widget.isSelected ? FontWeight.bold - : FontWeight.normal, + : FontWeight.w500, ), ), ], @@ -69,4 +118,10 @@ class _NavbarItemState extends State { ), ); } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } } diff --git a/pubspec.yaml b/pubspec.yaml index e79ca17..74df2a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+21 +version: 0.0.1+69 environment: sdk: ^3.8.1 From 8ca4e3210e2b2e15263dbe33ff5bd7890fdb958e Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 11:28:21 +0100 Subject: [PATCH 2/9] remove button in match view for testing --- lib/presentation/views/main_menu/match_view/match_view.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index ecfa9ca..9da007b 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -105,7 +105,8 @@ class _MatchViewState extends State { ), Positioned( bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( + child: SizedBox.shrink() + /* CustomWidthButton( text: loc.create_match, sizeRelativeToWidth: 0.90, onPressed: () async { @@ -118,6 +119,7 @@ class _MatchViewState extends State { ); }, ), + */ ), ], ), From ab20bd764b67e015e73b3957c6229e11c4bcecd3 Mon Sep 17 00:00:00 2001 From: Mathis Kirchner Date: Sun, 11 Jan 2026 11:30:00 +0100 Subject: [PATCH 3/9] implement draft blur navbar --- .../main_menu/custom_navigation_bar.dart | 61 ++++++++++++++++--- 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index 9c5c846..d3b7007 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -73,14 +73,59 @@ class _CustomNavigationBarState extends State backgroundColor: CustomTheme.backgroundColor, body: tabs[currentIndex], extendBody: true, - bottomNavigationBar: ClipRRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: Container( - decoration: BoxDecoration( - color: CustomTheme.boxColor.withValues(alpha: 0.8), + bottomNavigationBar: SizedBox( + height: 70 + MediaQuery.of(context).padding.bottom, + child: Stack( + children: [ + // Dynamisch generierte Blur-Layer für ultra-smooth Übergang + ...List.generate(35, (index) { + // Verwende kubische Kurve für noch natürlicheren, weicheren Übergang + final progress = index / 34.0; // 0.0 bis 1.0 + final cubic = progress * progress * progress; // Kubische Kurve + final blurStrength = 0.5 + (cubic * 50.0); // Sehr sanft von 0.5 bis 50.5 + + // Höhe geht jetzt komplett von 100% bis 0% (ganz nach unten) + // Mit extra Dichte am unteren Ende für weicheren Übergang + final heightFactor = index < 25 + ? 1.0 - (progress * 0.7) // Erste 25 Layer: 100% bis 30% + : 0.3 - ((index - 25) / 34.0); // Letzte 10 Layer: 30% bis 0% (dichter) + + return Positioned( + left: 0, + right: 0, + bottom: 0, + height: (70 + MediaQuery.of(context).padding.bottom) * heightFactor.clamp(0.05, 1.0), + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: blurStrength, + sigmaY: blurStrength, + ), + child: Container( + color: Colors.transparent, + ), + ), + ), + ); + }), + // Gradient-Overlay + Positioned.fill( + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment.bottomCenter, + end: Alignment.topCenter, + colors: [ + CustomTheme.boxColor.withValues(alpha: 1), + CustomTheme.boxColor.withValues(alpha: 0.0), + ], + stops: const [0.4, 1], + ), + ), + ), ), - child: SafeArea( + // Navbar-Inhalt + SafeArea( child: SizedBox( height: 70, child: Row( @@ -118,7 +163,7 @@ class _CustomNavigationBarState extends State ), ), ), - ), + ], ), ), ); From 0fb6208345772524613625bf7b1cdde9eba60256 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:23:34 +0100 Subject: [PATCH 4/9] Created new buttons for the main menu --- .../widgets/buttons/main_menu_button.dart | 98 +++++++++++++++++++ pubspec.yaml | 3 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 lib/presentation/widgets/buttons/main_menu_button.dart diff --git a/lib/presentation/widgets/buttons/main_menu_button.dart b/lib/presentation/widgets/buttons/main_menu_button.dart new file mode 100644 index 0000000..9e6ed80 --- /dev/null +++ b/lib/presentation/widgets/buttons/main_menu_button.dart @@ -0,0 +1,98 @@ +import 'package:flutter/material.dart'; + +/// A button for the main menu with an optional icon and a press animation. +/// - [text]: The text of the button. +/// - [icon]: The icon of the button. +/// - [onPressed]: The callback to be invoked when the button is pressed. +class MainMenuButton extends StatefulWidget { + const MainMenuButton({ + super.key, + required this.text, + this.icon, + required this.onPressed, + }); + + /// The text of the button. + final String text; + + /// The icon of the button. + final IconData? icon; + + /// The callback to be invoked when the button is pressed. + final void Function() onPressed; + + @override + State createState() => _MainMenuButtonState(); +} + +class _MainMenuButtonState extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + + _animationController = AnimationController( + duration: const Duration(milliseconds: 100), + vsync: this, + ); + + _scaleAnimation = Tween(begin: 1.0, end: 0.95).animate( + CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), + ); + } + + @override + Widget build(BuildContext context) { + return ScaleTransition( + scale: _scaleAnimation, + child: GestureDetector( + onTapDown: (_) { + _animationController.forward(); + }, + onTapUp: (_) async { + await _animationController.reverse(); + if (mounted) { + widget.onPressed(); + } + }, + onTapCancel: () { + _animationController.reverse(); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(30), + ), + padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 15), + child: Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (widget.icon != null) ...[ + Icon(widget.icon, size: 28, color: Colors.black), + const SizedBox(width: 7), + ], + Text( + widget.text, + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ], + ), + ), + ), + ); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 1b033f2..a7a2df7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+149 +version: 0.0.1+153 environment: sdk: ^3.8.1 @@ -23,6 +23,7 @@ dependencies: flutter_localizations: sdk: flutter package_info_plus: ^9.0.0 + fluttericon: ^2.0.0 dev_dependencies: flutter_test: From cde40ef2935baea1379a39345bff14cd1720dff7 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:23:43 +0100 Subject: [PATCH 5/9] Updated buttons in main menu --- .../views/main_menu/group_view/groups_view.dart | 8 ++++---- .../views/main_menu/match_view/match_view.dart | 13 ++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/groups_view.dart b/lib/presentation/views/main_menu/group_view/groups_view.dart index 239aa23..ec5fc44 100644 --- a/lib/presentation/views/main_menu/group_view/groups_view.dart +++ b/lib/presentation/views/main_menu/group_view/groups_view.dart @@ -8,7 +8,7 @@ import 'package:game_tracker/data/dto/player.dart'; import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; @@ -79,10 +79,10 @@ class _GroupsViewState extends State { ), ), Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: CustomWidthButton( + bottom: MediaQuery.paddingOf(context).bottom + 20, + child: MainMenuButton( text: loc.create_group, - sizeRelativeToWidth: 0.90, + icon: Icons.group_add, onPressed: () async { await Navigator.push( context, diff --git a/lib/presentation/views/main_menu/match_view/match_view.dart b/lib/presentation/views/main_menu/match_view/match_view.dart index 9da007b..7705d18 100644 --- a/lib/presentation/views/main_menu/match_view/match_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_view.dart @@ -1,6 +1,7 @@ import 'dart:core' hide Match; import 'package:flutter/material.dart'; +import 'package:fluttericon/rpg_awesome_icons.dart'; import 'package:game_tracker/core/adaptive_page_route.dart'; import 'package:game_tracker/core/constants.dart'; import 'package:game_tracker/core/custom_theme.dart'; @@ -12,7 +13,7 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart'; import 'package:game_tracker/presentation/widgets/app_skeleton.dart'; -import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart'; +import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart'; import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart'; import 'package:game_tracker/presentation/widgets/top_centered_message.dart'; import 'package:provider/provider.dart'; @@ -104,11 +105,10 @@ class _MatchViewState extends State { ), ), Positioned( - bottom: MediaQuery.paddingOf(context).bottom, - child: SizedBox.shrink() - /* CustomWidthButton( - text: loc.create_match, - sizeRelativeToWidth: 0.90, + bottom: MediaQuery.paddingOf(context).bottom + 20, + child: MainMenuButton( + text: 'Spiel erstellen', + icon: RpgAwesome.clovers_card, onPressed: () async { Navigator.push( context, @@ -119,7 +119,6 @@ class _MatchViewState extends State { ); }, ), - */ ), ], ), From 8bf2b9e3ddf1b8fab6cc61970040004b6e6c3971 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:31:30 +0100 Subject: [PATCH 6/9] Updated navbar item color & size --- lib/core/custom_theme.dart | 4 ++-- lib/presentation/widgets/navbar_item.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/core/custom_theme.dart b/lib/core/custom_theme.dart index 3f15ad9..cfe9b5a 100644 --- a/lib/core/custom_theme.dart +++ b/lib/core/custom_theme.dart @@ -11,8 +11,8 @@ class CustomTheme { static Color onBoxColor = const Color(0xFF181818); static Color boxBorder = const Color(0xFF272727); static const Color textColor = Colors.white; - static Color navBarItemSelectedColor = primaryColor.withValues(green: 0.4); - static Color navBarItemUnselectedColor = Colors.white.withValues(alpha: 0.6); + static Color navBarItemSelectedColor = primaryColor.withGreen(100); + static Color navBarItemUnselectedColor = Colors.grey.shade400; // ==================== Border Radius ==================== static const double standardBorderRadius = 12.0; diff --git a/lib/presentation/widgets/navbar_item.dart b/lib/presentation/widgets/navbar_item.dart index 6e2e24e..abf7acc 100644 --- a/lib/presentation/widgets/navbar_item.dart +++ b/lib/presentation/widgets/navbar_item.dart @@ -96,7 +96,7 @@ class _NavbarItemState extends State color: widget.isSelected ? CustomTheme.navBarItemSelectedColor : CustomTheme.navBarItemUnselectedColor, - size: 26, + size: 32, ), ), const SizedBox(height: 4), diff --git a/pubspec.yaml b/pubspec.yaml index a7a2df7..7978e22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+153 +version: 0.0.1+159 environment: sdk: ^3.8.1 From 679f4c94d978357a68df1be40798e068631ae4a8 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:33:20 +0100 Subject: [PATCH 7/9] Updated button size --- lib/presentation/widgets/buttons/main_menu_button.dart | 6 +++--- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/presentation/widgets/buttons/main_menu_button.dart b/lib/presentation/widgets/buttons/main_menu_button.dart index 9e6ed80..d29566c 100644 --- a/lib/presentation/widgets/buttons/main_menu_button.dart +++ b/lib/presentation/widgets/buttons/main_menu_button.dart @@ -66,19 +66,19 @@ class _MainMenuButtonState extends State color: Colors.white, borderRadius: BorderRadius.circular(30), ), - padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 15), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14), child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ if (widget.icon != null) ...[ - Icon(widget.icon, size: 28, color: Colors.black), + Icon(widget.icon, size: 26, color: Colors.black), const SizedBox(width: 7), ], Text( widget.text, style: const TextStyle( - fontSize: 20, + fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black, ), diff --git a/pubspec.yaml b/pubspec.yaml index 7978e22..6ff77df 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+159 +version: 0.0.1+160 environment: sdk: ^3.8.1 From 9344f8212ca351cbc39b18e0a506a4c2326d8bae Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 17:55:52 +0100 Subject: [PATCH 8/9] Updated version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 6ff77df..e57c3bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.1+160 +version: 0.0.5+161 environment: sdk: ^3.8.1 From fa7740101b9f87eeae15bb3cb2e0e1f9184f7d69 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Mon, 12 Jan 2026 19:34:35 +0100 Subject: [PATCH 9/9] Small changes on navbar --- .../main_menu/custom_navigation_bar.dart | 39 +++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/presentation/views/main_menu/custom_navigation_bar.dart b/lib/presentation/views/main_menu/custom_navigation_bar.dart index d3b7007..4ff61f6 100644 --- a/lib/presentation/views/main_menu/custom_navigation_bar.dart +++ b/lib/presentation/views/main_menu/custom_navigation_bar.dart @@ -77,38 +77,41 @@ class _CustomNavigationBarState extends State height: 70 + MediaQuery.of(context).padding.bottom, child: Stack( children: [ - // Dynamisch generierte Blur-Layer für ultra-smooth Übergang - ...List.generate(35, (index) { - // Verwende kubische Kurve für noch natürlicheren, weicheren Übergang - final progress = index / 34.0; // 0.0 bis 1.0 - final cubic = progress * progress * progress; // Kubische Kurve - final blurStrength = 0.5 + (cubic * 50.0); // Sehr sanft von 0.5 bis 50.5 + // Dynamically generated blur layers for ultra-smooth transition + ...List.generate(34, (index) { + // Use cubic curve for an even more natural, smoother transition + final progress = index / 34.0; // 0.0 to 1.0 + final cubic = progress * progress * progress; // cubic curve + final blurStrength = + 0.5 + (cubic * 50.0); // Very smooth from 0.5 to 50.5 - // Höhe geht jetzt komplett von 100% bis 0% (ganz nach unten) - // Mit extra Dichte am unteren Ende für weicheren Übergang + // Height goes completely from 100% to 0% (all the way down) + // With extra density at the bottom for softer transition final heightFactor = index < 25 - ? 1.0 - (progress * 0.7) // Erste 25 Layer: 100% bis 30% - : 0.3 - ((index - 25) / 34.0); // Letzte 10 Layer: 30% bis 0% (dichter) + // First 25 layers: 100% to 30% + ? 1.0 - (progress * 0.7) + // Last 10 layers: 30% to 0% (denser) + : 0.3 - ((index - 25) / 34.0); return Positioned( left: 0, right: 0, bottom: 0, - height: (70 + MediaQuery.of(context).padding.bottom) * heightFactor.clamp(0.05, 1.0), + height: + (70 + MediaQuery.of(context).padding.bottom) * + heightFactor.clamp(0.05, 1.0), child: ClipRect( child: BackdropFilter( filter: ImageFilter.blur( sigmaX: blurStrength, sigmaY: blurStrength, ), - child: Container( - color: Colors.transparent, - ), + child: Container(color: Colors.transparent), ), ), ); }), - // Gradient-Overlay + // Gradient overlay Positioned.fill( child: Container( decoration: BoxDecoration( @@ -117,14 +120,16 @@ class _CustomNavigationBarState extends State end: Alignment.topCenter, colors: [ CustomTheme.boxColor.withValues(alpha: 1), + CustomTheme.boxColor.withValues(alpha: 0.5), + CustomTheme.boxColor.withValues(alpha: 0.2), CustomTheme.boxColor.withValues(alpha: 0.0), ], - stops: const [0.4, 1], + stops: const [0.0, 0.4, 0.8, 1], ), ), ), ), - // Navbar-Inhalt + // Navbar content SafeArea( child: SizedBox( height: 70, diff --git a/pubspec.yaml b/pubspec.yaml index e57c3bc..8844c81 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: game_tracker description: "Game Tracking App for Card Games" publish_to: 'none' -version: 0.0.5+161 +version: 0.0.5+166 environment: sdk: ^3.8.1