From b664bcacda19ab81deaf813561d8ac5ba4aade86 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sat, 2 May 2026 16:02:49 +0200 Subject: [PATCH] Created seperate game tile and simplified title description list tile --- lib/presentation/widgets/tiles/game_tile.dart | 151 ++++++++++++++++++ .../tiles/title_description_list_tile.dart | 77 ++------- 2 files changed, 168 insertions(+), 60 deletions(-) create mode 100644 lib/presentation/widgets/tiles/game_tile.dart diff --git a/lib/presentation/widgets/tiles/game_tile.dart b/lib/presentation/widgets/tiles/game_tile.dart new file mode 100644 index 0000000..1d494b9 --- /dev/null +++ b/lib/presentation/widgets/tiles/game_tile.dart @@ -0,0 +1,151 @@ +import 'package:flutter/material.dart'; +import 'package:tallee/core/common.dart'; +import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; + +class GameTile extends StatelessWidget { + /// A list tile widget that displays a title and description, with optional highlighting and badge. + /// - [title]: The title text displayed on the tile. + /// - [description]: The description text displayed below the title. + /// - [onTap]: The callback invoked when the tile is tapped. + /// - [onLongPress]: The callback invoked when the tile is tapped. + /// - [isHighlighted]: A boolean to determine if the tile should be highlighted. + /// - [badgeText]: Optional text to display in a badge on the right side of the title. + /// - [badgeColor]: Optional color for the badge background. + const GameTile({ + super.key, + required this.title, + required this.description, + this.onTap, + this.onLongPress, + this.isHighlighted = false, + this.badgeText, + this.badgeColor, + }); + + /// The title text displayed on the tile. + final String title; + + /// The description text displayed below the title. + final String description; + + /// The callback invoked when the tile is tapped. + final VoidCallback? onTap; + + /// The callback invoked when the tile is long-pressed. + final VoidCallback? onLongPress; + + /// A boolean to determine if the tile should be highlighted. + final bool isHighlighted; + + /// Optional text to display in a badge on the right side of the title. + final String? badgeText; + + /// Optional color for the badge background. + final Color? badgeColor; + + @override + Widget build(BuildContext context) { + final badgeTextColor = badgeColor != null + ? (badgeColor!.computeLuminance() > 0.5 ? Colors.black : Colors.white) + : Colors.white; + + final gameColor = badgeColor ?? getColorFromGameColor(GameColor.orange); + + return GestureDetector( + onTap: onTap, + onLongPress: onLongPress, + child: AnimatedContainer( + margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), + decoration: !isHighlighted + ? CustomTheme.standardBoxDecoration + : CustomTheme.highlightedBoxDecoration.copyWith( + border: Border.all( + color: gameColor.withValues(alpha: 0.9), + width: 2, + ), + ), + duration: const Duration(milliseconds: 200), + child: Stack( + children: [ + // Gradient overlay + Positioned.fill( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + gameColor.withValues(alpha: 0.08), + gameColor.withValues(alpha: 0.02), + Colors.transparent, + ], + stops: const [0.0, 0.5, 1.0], + ), + ), + ), + ), + + // Content + Padding( + padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + // Title + Text( + title, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + + // Badge + if (badgeText != null) ...[ + const SizedBox(height: 5), + Container( + constraints: const BoxConstraints(maxWidth: 250), + padding: const EdgeInsets.symmetric( + vertical: 2, + horizontal: 6, + ), + decoration: BoxDecoration( + color: gameColor, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + badgeText!, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: TextStyle( + color: badgeTextColor, + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + + // Description + if (description.isNotEmpty) ...[ + const SizedBox(height: 10), + Text(description, style: const TextStyle(fontSize: 14)), + const SizedBox(height: 2.5), + ], + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/tiles/title_description_list_tile.dart b/lib/presentation/widgets/tiles/title_description_list_tile.dart index 95163f2..bf45c1e 100644 --- a/lib/presentation/widgets/tiles/title_description_list_tile.dart +++ b/lib/presentation/widgets/tiles/title_description_list_tile.dart @@ -2,23 +2,17 @@ import 'package:flutter/material.dart'; import 'package:tallee/core/custom_theme.dart'; class TitleDescriptionListTile extends StatelessWidget { - /// A list tile widget that displays a title and description, with optional highlighting and badge. + /// A list tile widget that displays a title and description /// - [title]: The title text displayed on the tile. /// - [description]: The description text displayed below the title. /// - [onTap]: The callback invoked when the tile is tapped. - /// - [onLongPress]: The callback invoked when the tile is tapped. /// - [isHighlighted]: A boolean to determine if the tile should be highlighted. - /// - [badgeText]: Optional text to display in a badge on the right side of the title. - /// - [badgeColor]: Optional color for the badge background. const TitleDescriptionListTile({ super.key, required this.title, required this.description, this.onTap, - this.onLongPress, this.isHighlighted = false, - this.badgeText, - this.badgeColor, }); /// The title text displayed on the tile. @@ -30,23 +24,13 @@ class TitleDescriptionListTile extends StatelessWidget { /// The callback invoked when the tile is tapped. final VoidCallback? onTap; - /// The callback invoked when the tile is long-pressed. - final VoidCallback? onLongPress; - /// A boolean to determine if the tile should be highlighted. final bool isHighlighted; - /// Optional text to display in a badge on the right side of the title. - final String? badgeText; - - /// Optional color for the badge background. - final Color? badgeColor; - @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, - onLongPress: onLongPress, child: AnimatedContainer( margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10), padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 12), @@ -57,53 +41,26 @@ class TitleDescriptionListTile extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox( - width: 230, - child: Text( - title, - overflow: TextOverflow.ellipsis, - maxLines: 1, - softWrap: false, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), + // Title + SizedBox( + width: 230, + child: Text( + title, + overflow: TextOverflow.ellipsis, + maxLines: 1, + softWrap: false, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, ), - if (badgeText != null) ...[ - const Spacer(), - Container( - constraints: const BoxConstraints(maxWidth: 115), - padding: const EdgeInsets.symmetric( - vertical: 2, - horizontal: 6, - ), - decoration: BoxDecoration( - color: badgeColor ?? CustomTheme.primaryColor, - borderRadius: BorderRadius.circular(4), - ), - child: Text( - badgeText!, - overflow: TextOverflow.ellipsis, - maxLines: 1, - softWrap: false, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ], + ), ), + + // Description if (description.isNotEmpty) ...[ - const SizedBox(height: 5), + const SizedBox(height: 10), Text(description, style: const TextStyle(fontSize: 14)), const SizedBox(height: 2.5), ],