From e2099b0566ca6c59c16d1ef927b97b002850c732 Mon Sep 17 00:00:00 2001 From: Jacob Moura Date: Tue, 20 Feb 2024 13:42:05 -0300 Subject: [PATCH] feat: Added List Game View --- lib/app/(public)/home/grid_page.dart | 1 + lib/app/(public)/home/list_page.dart | 9 ++ lib/app/core/widgets/animated_tile.dart | 148 +++++++++++++++--------- lib/app/core/widgets/command_bar.dart | 8 +- 4 files changed, 108 insertions(+), 58 deletions(-) diff --git a/lib/app/(public)/home/grid_page.dart b/lib/app/(public)/home/grid_page.dart index 8392a4d..07eac38 100644 --- a/lib/app/(public)/home/grid_page.dart +++ b/lib/app/(public)/home/grid_page.dart @@ -241,6 +241,7 @@ class _HomePageState extends State with HomeMixin { onSettings: openSettings, onFavorite: favorite, onPlay: openGame, + onGameView: gameView, ), ), ], diff --git a/lib/app/(public)/home/list_page.dart b/lib/app/(public)/home/list_page.dart index 1cc1371..d2766f9 100644 --- a/lib/app/(public)/home/list_page.dart +++ b/lib/app/(public)/home/list_page.dart @@ -229,6 +229,9 @@ class _ListPageState extends State with HomeMixin { controller: scrollController, index: index, child: AnimatedTile( + index: index, + gamesLength: games.length, + transitionAnimation: widget.transitionAnimation, colorScheme: colorScheme, selected: selected, text: game.name, @@ -236,6 +239,11 @@ class _ListPageState extends State with HomeMixin { getPlatformFromGame(game).category.name, onTap: () { handlerSelect(index); + openGame(); + }, + onLongPressed: () { + handlerSelect(index); + gameMenu(); }, ), ); @@ -268,6 +276,7 @@ class _ListPageState extends State with HomeMixin { onSettings: openSettings, onFavorite: favorite, onPlay: openGame, + onGameView: gameView, ), ), ], diff --git a/lib/app/core/widgets/animated_tile.dart b/lib/app/core/widgets/animated_tile.dart index 49ffe49..13cb6be 100644 --- a/lib/app/core/widgets/animated_tile.dart +++ b/lib/app/core/widgets/animated_tile.dart @@ -1,19 +1,29 @@ +import 'dart:ui'; + import 'package:flutter/material.dart'; class AnimatedTile extends StatefulWidget { final String text; final String subtext; + final int index; + final int gamesLength; + final Animation transitionAnimation; final bool selected; final ColorScheme colorScheme; final void Function()? onTap; + final void Function()? onLongPressed; const AnimatedTile({ super.key, required this.text, required this.subtext, required this.colorScheme, + required this.transitionAnimation, + required this.index, + required this.gamesLength, this.selected = false, this.onTap, + this.onLongPressed, }); @override @@ -24,6 +34,8 @@ class _AnimatedTileState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; + late final Animation _tileSlideAnimation; + @override void initState() { super.initState(); @@ -34,9 +46,27 @@ class _AnimatedTileState extends State _controller.value = widget.selected ? 1 : 0; - _controller.addListener(() { - setState(() {}); - }); + Listenable.merge([ + _controller, + widget.transitionAnimation, + ]).addListener(_listener); + + final start = widget.index / widget.gamesLength; + final duration = 1 / widget.gamesLength; + + final curved = CurvedAnimation( + parent: widget.transitionAnimation, + curve: const Interval(0.5, 1.0), + ); + + _tileSlideAnimation = Tween(begin: 1.0, end: 0.0).animate(CurvedAnimation( + parent: curved, + curve: Interval(start, start + duration, curve: Curves.easeOut), + )); + } + + void _listener() { + setState(() {}); } @override @@ -56,6 +86,7 @@ class _AnimatedTileState extends State @override void dispose() { + widget.transitionAnimation.removeListener(_listener); _controller.dispose(); super.dispose(); } @@ -84,62 +115,69 @@ class _AnimatedTileState extends State ), ); - return Padding( - padding: const EdgeInsets.only(left: 12.0, right: 4.0), - child: Card( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0), - ), - color: widget.selected - ? widget.colorScheme.surface - : theme.colorScheme.surface, - child: InkWell( - borderRadius: BorderRadius.circular(12.0), - onTap: widget.onTap, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Transform.translate( - offset: textTranslate.value, - child: Text( - widget.text, - maxLines: 1, - style: theme.textTheme.titleMedium?.copyWith( - overflow: TextOverflow.ellipsis, - color: widget.selected - ? widget.colorScheme.primary - : theme.colorScheme.onSurface, + return Transform.translate( + offset: Offset(_tileSlideAnimation.value * -200, 0), + child: Opacity( + opacity: lerpDouble(1.0, 0.0, _tileSlideAnimation.value)!, + child: Padding( + padding: const EdgeInsets.only(left: 12.0, right: 4.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12.0), + ), + color: widget.selected + ? widget.colorScheme.surface + : theme.colorScheme.surface, + child: InkWell( + borderRadius: BorderRadius.circular(12.0), + onTap: widget.onTap, + onLongPress: widget.onLongPressed, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Transform.translate( + offset: textTranslate.value, + child: Text( + widget.text, + maxLines: 1, + style: theme.textTheme.titleMedium?.copyWith( + overflow: TextOverflow.ellipsis, + color: widget.selected + ? widget.colorScheme.primary + : theme.colorScheme.onSurface, + ), + ), ), - ), - ), - Opacity( - opacity: subtextOpacity.value, - child: Text( - widget.subtext, - maxLines: 1, - style: theme.textTheme.bodySmall?.copyWith( - overflow: TextOverflow.ellipsis, - color: widget.selected - ? widget.colorScheme.primary - : theme.colorScheme.onSurface, + Opacity( + opacity: subtextOpacity.value, + child: Text( + widget.subtext, + maxLines: 1, + style: theme.textTheme.bodySmall?.copyWith( + overflow: TextOverflow.ellipsis, + color: widget.selected + ? widget.colorScheme.primary + : theme.colorScheme.onSurface, + ), + ), ), - ), + ], ), - ], - ), - ), - Icon( - Icons.arrow_forward_ios, - color: widget.selected - ? widget.colorScheme.primary - : theme.colorScheme.onSurface, + ), + Icon( + Icons.arrow_forward_ios, + color: widget.selected + ? widget.colorScheme.primary + : theme.colorScheme.onSurface, + ), + ], ), - ], + ), ), ), ), diff --git a/lib/app/core/widgets/command_bar.dart b/lib/app/core/widgets/command_bar.dart index 5026fbd..5fda2ac 100644 --- a/lib/app/core/widgets/command_bar.dart +++ b/lib/app/core/widgets/command_bar.dart @@ -15,6 +15,7 @@ class NavigationCommand extends StatelessWidget { final VoidCallback? onPlay; final VoidCallback? onFavorite; final VoidCallback? onSettings; + final VoidCallback? onGameView; final ColorScheme colorScheme; final bool isSyncing; @@ -22,6 +23,7 @@ class NavigationCommand extends StatelessWidget { super.key, this.onApps, this.onFavorite, + this.onGameView, this.onSettings, this.onPlay, this.isSyncing = false, @@ -55,10 +57,10 @@ class NavigationCommand extends StatelessWidget { background: colorScheme.onBackground, textColor: colorScheme.background, ), - const Gap(17), IconButton( - onPressed: () {}, - icon: const Icon(Icons.laptop_windows_outlined)), + onPressed: onGameView, + icon: const Icon(Icons.space_dashboard_rounded), + ), const Spacer(), if (isSyncing) Row(