import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter_animate/flutter_animate.dart'; import '../../../models/idea.dart'; import '../../../providers/ideas_provider.dart'; import '../../../core/constants/app_constants.dart'; import '../../../core/theme/app_theme.dart'; import '../../../widgets/funnel_status_badge.dart'; class IdeaFunnelKanban extends ConsumerWidget { final List ideas; const IdeaFunnelKanban({super.key, required this.ideas}); @override Widget build(BuildContext context, WidgetRef ref) { final notifier = ref.read(ideasProvider.notifier); return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: AppConstants.funnelStates.map((status) { final columnIdeas = ideas.where((i) => i.funnelStatus == status).toList(); final color = AppConstants.funnelColors[status]!; final label = AppConstants.funnelLabels[status]!; return Container( width: 280, margin: const EdgeInsets.all(8), child: Column( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 10), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: const BorderRadius.vertical(top: Radius.circular(12)), ), child: Row( children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: color, shape: BoxShape.circle, ), ), const SizedBox(width: 8), Text(label, style: TextStyle( fontWeight: FontWeight.w600, color: color)), const Spacer(), Text( '${columnIdeas.length}', style: TextStyle(color: color, fontSize: 12), ), ], ), ), Expanded( child: Container( decoration: BoxDecoration( color: VoIdeaColors.surface, border: Border.all(color: color.withOpacity(0.2)), borderRadius: const BorderRadius.vertical(bottom: Radius.circular(12)), ), child: columnIdeas.isEmpty ? Center( child: Text('Нет идей', style: TextStyle( color: VoIdeaColors.muted, fontSize: 12)), ) : ListView.builder( padding: const EdgeInsets.all(8), itemCount: columnIdeas.length, itemBuilder: (_, i) { final idea = columnIdeas[i]; return Card( margin: const EdgeInsets.only(bottom: 8), child: InkWell( borderRadius: BorderRadius.circular(8), onTap: () => context.push('/ideas/${idea.id}'), onLongPress: () => _showKanbanContextMenu(context, ref, idea), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( idea.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( fontWeight: FontWeight.w500, fontSize: 13), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ _iconText( Icons.thumb_up_outlined, idea.upvotes.toString()), const SizedBox(width: 8), _iconText( Icons.comment_outlined, idea.commentCount .toString()), ], ), Row( mainAxisSize: MainAxisSize.min, children: [ if (i > 0 || AppConstants.funnelStates .indexOf(status) > 0) InkWell( onTap: () => notifier .updateFunnel( idea.id, AppConstants .funnelStates[ AppConstants .funnelStates .indexOf( status) - 1]), child: const Icon( Icons.chevron_left, size: 20), ), InkWell( onTap: () => notifier .updateFunnel( idea.id, AppConstants .funnelStates[ AppConstants .funnelStates .indexOf( status) + 1]), child: const Icon( Icons.chevron_right, size: 20), ), ], ), ], ), ], ), ), ), ).animate().fadeIn( duration: 200.ms, delay: (i * 30).ms); }, ), ), ), ], ), ); }).toList(), ), ); } Widget _iconText(IconData icon, String text) { return Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 12, color: VoIdeaColors.muted), const SizedBox(width: 2), Text(text, style: const TextStyle(fontSize: 11, color: VoIdeaColors.muted)), ], ); } void _showKanbanContextMenu(BuildContext context, WidgetRef ref, Idea idea) { final notifier = ref.read(ideasProvider.notifier); final funnelIdx = AppConstants.funnelStates.indexOf(idea.funnelStatus ?? ''); final canMoveLeft = funnelIdx > 0; final canMoveRight = funnelIdx < AppConstants.funnelStates.length - 1; showModalBottomSheet( context: context, builder: (ctx) => SafeArea( child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(idea.title, style: Theme.of(context) .textTheme .titleMedium ?.copyWith(fontWeight: FontWeight.w600)), const SizedBox(height: 16), ListTile( leading: const Icon(Icons.slideshow, color: VoIdeaColors.primary), title: const Text('Создать презентацию'), onTap: () { Navigator.pop(ctx); context.push('/ideas/${idea.id}'); }, ), if (canMoveLeft) ListTile( leading: const Icon(Icons.arrow_back, color: VoIdeaColors.warning), title: Text( 'Переместить в "${AppConstants.funnelLabels[AppConstants.funnelStates[funnelIdx - 1]]}"'), onTap: () { Navigator.pop(ctx); notifier.updateFunnel(idea.id, AppConstants.funnelStates[funnelIdx - 1]); }, ), if (canMoveRight) ListTile( leading: const Icon(Icons.arrow_forward, color: VoIdeaColors.success), title: Text( 'Переместить в "${AppConstants.funnelLabels[AppConstants.funnelStates[funnelIdx + 1]]}"'), onTap: () { Navigator.pop(ctx); notifier.updateFunnel(idea.id, AppConstants.funnelStates[funnelIdx + 1]); }, ), ], ), ), ), ); } }