diff --git a/lib/widgets/app_pack_container.dart b/lib/widgets/app_pack_container.dart index 175a614..ba11d5e 100644 --- a/lib/widgets/app_pack_container.dart +++ b/lib/widgets/app_pack_container.dart @@ -53,91 +53,25 @@ class AppPackContainer extends HookConsumerWidget { orElse: () => packs.first, ); - // Scroll controller and hint visibility state - final scrollController = useScrollController(); - final showRightHint = useState(true); - final hasScrolledOnce = useState(false); - - // Listen to scroll position to hide hint when near end - useEffect(() { - void listener() { - if (!scrollController.hasClients) return; - final maxScroll = scrollController.position.maxScrollExtent; - final currentScroll = scrollController.offset; - - // Hide hint when scrolled past 20px or near the end - if (currentScroll > 20) { - hasScrolledOnce.value = true; - } - showRightHint.value = - !hasScrolledOnce.value && currentScroll < maxScroll - 20; - } - - // Check initial state after first frame - WidgetsBinding.instance.addPostFrameCallback((_) { - if (scrollController.hasClients) { - final maxScroll = scrollController.position.maxScrollExtent; - // Hide hint if content doesn't overflow - showRightHint.value = maxScroll > 20; - } - }); - - scrollController.addListener(listener); - return () => scrollController.removeListener(listener); - }, [scrollController]); - return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 48, - child: Stack( - children: [ - SingleChildScrollView( - controller: scrollController, - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.only(left: 12, right: 52), - child: Row( - children: packs - .map( - (pack) => _PackPill( - pack: pack, - isSelected: selectedId.value == pack.id, - onTap: () => selectedId.value = pack.id, - ), - ) - .toList(), - ), - ), - // Right fade gradient with animated chevron - if (showRightHint.value) - Positioned( - right: 0, - top: 0, - bottom: 0, - width: 56, - child: IgnorePointer( - child: Container( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.centerLeft, - end: Alignment.centerRight, - colors: [ - Colors.transparent, - AppColors.darkBackground, - AppColors.darkBackground, - ], - stops: [0.0, 0.5, 1.0], - ), - ), - child: const Align( - alignment: Alignment(0.6, -0.1), - child: _AnimatedScrollHint(), - ), + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Row( + children: packs + .map( + (pack) => _PackPill( + pack: pack, + isSelected: selectedId.value == pack.id, + onTap: () => selectedId.value = pack.id, ), - ), - ), - ], + ) + .toList(), + ), ), ), const SizedBox(height: 16), @@ -205,81 +139,6 @@ class _SkeletonPill extends StatelessWidget { } } -/// Animated chevron hint for horizontal scroll discovery -class _AnimatedScrollHint extends StatefulWidget { - const _AnimatedScrollHint(); - - @override - State<_AnimatedScrollHint> createState() => _AnimatedScrollHintState(); -} - -class _AnimatedScrollHintState extends State<_AnimatedScrollHint> - with SingleTickerProviderStateMixin { - late AnimationController _controller; - late Animation _offsetAnimation; - late Animation _opacityAnimation; - - @override - void initState() { - super.initState(); - _controller = AnimationController( - duration: const Duration(milliseconds: 900), - vsync: this, - )..repeat(reverse: true); - - _offsetAnimation = Tween( - begin: 0, - end: 6, - ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); - - _opacityAnimation = Tween( - begin: 0.7, - end: 1.0, - ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut)); - } - - @override - void dispose() { - _controller.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return AnimatedBuilder( - animation: _controller, - builder: (context, child) => Transform.translate( - offset: Offset(_offsetAnimation.value, 0), - child: Opacity( - opacity: _opacityAnimation.value, - // Stack icons with slight offsets to create bold effect - child: SizedBox( - width: 20, - height: 20, - child: Stack( - children: [ - Positioned( - left: 0.5, - child: Icon( - Icons.arrow_forward_ios_rounded, - color: Colors.white.withValues(alpha: 0.7), - size: 20, - ), - ), - const Icon( - Icons.arrow_forward_ios_rounded, - color: Colors.white, - size: 20, - ), - ], - ), - ), - ), - ), - ); - } -} - /// Individual pack pill - watches its own author reactively class _PackPill extends ConsumerWidget { const _PackPill({