import 'package:didvan/config/design_config.dart'; import 'package:didvan/models/story_model.dart'; import 'package:didvan/routes/routes.dart'; import 'package:flutter/material.dart'; import 'package:didvan/config/theme_data.dart'; class StorySection extends StatelessWidget { final List stories; const StorySection({super.key, required this.stories}); @override Widget build(BuildContext context) { return SizedBox( height: 118.0, child: ListView.builder( padding: const EdgeInsets.symmetric(horizontal: 8.0), scrollDirection: Axis.horizontal, // In RTL, reversing a horizontal list places item zero on the left. reverse: true, itemCount: stories.length, physics: const BouncingScrollPhysics(), itemBuilder: (BuildContext context, int index) { final userStories = stories[index]; return Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), child: _StoryCircle( userStories: userStories, onTap: () { Navigator.of(context).pushNamed( Routes.storyViewer, arguments: { 'stories': stories, 'tappedIndex': index, }, ); }, ), ); }, ), ); } } class _StoryCircle extends StatefulWidget { final UserStories userStories; final VoidCallback onTap; const _StoryCircle({required this.userStories, required this.onTap}); @override State<_StoryCircle> createState() => _StoryCircleState(); } class _StoryCircleState extends State<_StoryCircle> { late ValueNotifier _allViewed; @override void initState() { super.initState(); _attach(widget.userStories); } @override void didUpdateWidget(covariant _StoryCircle oldWidget) { super.didUpdateWidget(oldWidget); if (!identical(oldWidget.userStories, widget.userStories)) { _detach(oldWidget.userStories); _attach(widget.userStories); } } void _attach(UserStories us) { _allViewed = ValueNotifier(us.stories.every((s) => s.isViewed.value)); for (final s in us.stories) { s.isViewed.addListener(_recalcViewed); } } void _detach(UserStories us) { for (final s in us.stories) { s.isViewed.removeListener(_recalcViewed); } _allViewed.dispose(); } void _recalcViewed() { if (!mounted) return; _allViewed.value = widget.userStories.stories.every((s) => s.isViewed.value); } @override void dispose() { _detach(widget.userStories); super.dispose(); } @override Widget build(BuildContext context) { return InkWell( onTap: widget.onTap, borderRadius: BorderRadius.circular(50), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ValueListenableBuilder( valueListenable: _allViewed, builder: (context, isViewed, child) { return Hero( tag: 'story-${widget.userStories.user.name}', child: Container( width: 88.0, height: 88.0, decoration: BoxDecoration( shape: BoxShape.circle, gradient: isViewed ? LinearGradient( colors: [ Theme.of(context).colorScheme.cardBorder, Theme.of(context).colorScheme.cardBorder, ], ) : LinearGradient( colors: [ Theme.of(context).colorScheme.primary, Theme.of(context) .colorScheme .primary .withValues(alpha: 0.7), ], begin: Alignment.topRight, end: Alignment.bottomLeft, ), ), child: Padding( padding: const EdgeInsets.all(4.0), child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, shape: BoxShape.circle, ), child: Padding( padding: const EdgeInsets.all(4.0), child: CircleAvatar( backgroundColor: Theme.of(context).colorScheme.splash, child: ClipOval( child: Image.asset( widget.userStories.user.profileImageUrl, color: DesignConfig.isDark ? Colors.grey : null, fit: BoxFit.cover, width: 50.0, height: 50.0, errorBuilder: (context, error, stackTrace) { return Icon(Icons.person, color: Theme.of(context) .colorScheme .caption, size: 40.0); }, ), ), ), ), ), ), ), ); }, ), const SizedBox(height: 6.0), SizedBox( width: 80, child: Text( widget.userStories.user.name, style: const TextStyle(fontSize: 12.0, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, maxLines: 1, ), ), ], ), ); } }