import 'package:didvan/config/theme_data.dart'; import 'package:didvan/models/ai/ai_chat_args.dart'; import 'package:didvan/models/ai/bots_model.dart'; import 'package:didvan/views/ai/ai_chat_page.dart'; import 'package:didvan/views/ai/ai_chat_state.dart'; import 'package:didvan/views/widgets/didvan/text.dart'; import 'package:didvan/views/widgets/hoshan_home_app_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:didvan/views/ai/history_ai_chat_state.dart'; import 'package:didvan/views/ai/ai_state.dart'; class AiSectionPage extends StatefulWidget { const AiSectionPage({super.key}); @override State createState() => _AiSectionPageState(); } class _AiSectionGridItem { final String title; final String description; final String iconPath; final void Function(BuildContext context) onTap; _AiSectionGridItem({ required this.title, required this.description, required this.iconPath, required this.onTap, }); } class _AiSectionPageState extends State with TickerProviderStateMixin { late final List<_AiSectionGridItem> _gridItems; late AnimationController _fadeController; late AnimationController _slideController; late Animation _fadeAnimation; late Animation _slideAnimation; @override void initState() { super.initState(); _fadeController = AnimationController( duration: const Duration(milliseconds: 800), vsync: this, ); _fadeAnimation = CurvedAnimation( parent: _fadeController, curve: Curves.easeIn, ); _slideController = AnimationController( duration: const Duration(milliseconds: 1000), vsync: this, ); _slideAnimation = Tween( begin: const Offset(0, 0.3), end: Offset.zero, ).animate(CurvedAnimation( parent: _slideController, curve: Curves.easeOutCubic, )); _fadeController.forward(); _slideController.forward(); WidgetsBinding.instance.addPostFrameCallback((_) { final historyAiChatState = context.read(); if (historyAiChatState.bots.isEmpty) { historyAiChatState.getBots(); } final aiState = context.read(); final aiChatState = context.read(); aiState.onClearChatCallback = () async { await aiChatState.clearChat(); }; aiState.endChat(); if (aiState.tools == null) { aiState.getTools(); } }); _gridItems = [ _AiSectionGridItem( title: 'ساخت عکس', description: 'ایجاد تصاویر خلاقانه با هوش مصنوعی', iconPath: 'lib/assets/icons/create image.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); if (aiState.tools != null && aiState.tools!.isNotEmpty) { try { final tool = aiState.tools![0]; if (tool.bots != null && tool.bots!.isNotEmpty) { aiState.startChat(AiChatArgs(bot: tool.bots!.first)); } } catch (e) { debugPrint('خطا در یافتن ابزار تصویرساز: $e'); } } }, ), _AiSectionGridItem( title: 'ترجمه', description: 'ترجمه متون به زبان‌های مختلف', iconPath: 'lib/assets/icons/translate.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); if (aiState.tools != null && aiState.tools!.length > 2) { try { final tool = aiState.tools![2]; if (tool.bots != null && tool.bots!.isNotEmpty) { aiState.startChat(AiChatArgs(bot: tool.bots!.first)); } } catch (e) { debugPrint('خطا در یافتن ابزار ترجمه: $e'); } } }, ), _AiSectionGridItem( title: 'خلاصه‌ساز', description: 'خلاصه‌سازی متن با هوش مصنوعی', iconPath: 'lib/assets/icons/summary.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); final aisummeryBot = BotsModel( id: 100, name: 'Aisummery', responseType: 'text', attachmentType: ['pdf', 'image', 'audio'], attachment: 1, ); aiState.startChat(AiChatArgs(bot: aisummeryBot)); }, ), _AiSectionGridItem( title: 'متن به صوت', description: 'تبدیل متن به فایل صوتی', iconPath: 'lib/assets/icons/text to voice.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); final textToSpeechBot = BotsModel( id: 101, name: 'aiaudio', responseType: 'audio', attachmentType: [], attachment: 0, ); aiState.startChat(AiChatArgs(bot: textToSpeechBot)); }, ), _AiSectionGridItem( title: 'تحلیل و ترسیم نمودار', description: 'ساخت نمودار با تحلیل هوشمند', iconPath: 'lib/assets/icons/chart-analysis.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); final chartAnalysisBot = BotsModel( id: 27, name: 'chart-analysis', responseType: 'text', attachmentType: ['image', 'pdf'], attachment: 1, ); aiState.startChat(AiChatArgs(bot: chartAnalysisBot)); }, ), _AiSectionGridItem( title: 'ساخت ویدیو', description: 'تولید ویدیو با هوش مصنوعی', iconPath: 'lib/assets/icons/video creator.svg', onTap: (context) { final aiState = context.read(); aiState.endChat(); final aiVideoBot = BotsModel( id: 102, name: 'aivideo', responseType: 'video', attachmentType: [], attachment: 0, ); aiState.startChat(AiChatArgs(bot: aiVideoBot)); }, ), ]; } @override void dispose() { _fadeController.dispose(); _slideController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final aiState = context.watch(); return Column( children: [ if (!aiState.isChatting) const HoshanHomeAppBar(), Expanded( child: aiState.isChatting ? AiChatPage(args: aiState.currentChatArgs!) : SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ FadeTransition( opacity: _fadeAnimation, child: Padding( padding: const EdgeInsets.all(20), child: Row( children: [ SvgPicture.asset('lib/assets/icons/clarity_tools-line.svg'), const SizedBox(width: 8,), DidvanText( 'جعبه ابزار استراتژیک هوشان', style: Theme.of(context).textTheme.titleMedium, color: Theme.of(context).colorScheme.title, ), ], ), ), ), SlideTransition( position: _slideAnimation, child: FadeTransition( opacity: _fadeAnimation, child: SizedBox( height: MediaQuery.of(context).size.height - 100, child: _buildAiGrid(context, aiState), ), ), ), ], ), ), ), ], ); } Widget _buildAiGrid(BuildContext context, AiState aiState) { if (aiState.tools == null) { if (aiState.loading) { return const Center(child: CircularProgressIndicator()); } return const Center( child: DidvanText('لیست ابزارها هنوز بارگذاری نشده یا خالی است.')); } return ListView.builder( scrollDirection: Axis.horizontal, reverse: true, padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 16.0), itemCount: (_gridItems.length / 2).ceil(), itemBuilder: (context, columnIndex) { return Padding( padding: EdgeInsets.only( left: columnIndex == (_gridItems.length / 2).ceil() - 1 ? 0 : 4.0, right: 16.0, ), child: SizedBox( width: 180, height: 340, child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ if (columnIndex * 2 < _gridItems.length) TweenAnimationBuilder( duration: Duration(milliseconds: 600 + (columnIndex * 100)), tween: Tween(begin: 0.0, end: 1.0), curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, child: Transform.translate( offset: Offset(50 * (1 - value), 0), child: child, ), ); }, child: SizedBox( width: 180, height: 160, child: _buildGridItemCard(context, _gridItems[columnIndex * 2]), ), ), if (columnIndex * 2 + 1 < _gridItems.length) Padding( padding: const EdgeInsets.only(top: 16.0), child: TweenAnimationBuilder( duration: Duration(milliseconds: 700 + (columnIndex * 100)), tween: Tween(begin: 0.0, end: 1.0), curve: Curves.easeOut, builder: (context, value, child) { return Opacity( opacity: value, child: Transform.translate( offset: Offset(50 * (1 - value), 0), child: child, ), ); }, child: SizedBox( width: 180, height: 160, child: _buildGridItemCard(context, _gridItems[columnIndex * 2 + 1]), ), ), ), ], ), ), ); }, ); } Widget _buildGridItemCard(BuildContext context, _AiSectionGridItem item) { return _AnimatedGridCard(item: item); } } class _AnimatedGridCard extends StatefulWidget { final _AiSectionGridItem item; const _AnimatedGridCard({required this.item}); @override State<_AnimatedGridCard> createState() => _AnimatedGridCardState(); } class _AnimatedGridCardState extends State<_AnimatedGridCard> { bool _isHovered = false; @override Widget build(BuildContext context) { return TweenAnimationBuilder( duration: const Duration(milliseconds: 400), tween: Tween(begin: 0.0, end: 1.0), curve: Curves.easeOutBack, builder: (context, value, child) { return Transform.scale( scale: value, child: child, ); }, child: MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), child: InkWell( onTap: () => widget.item.onTap(context), borderRadius: BorderRadius.circular(25), child: AnimatedContainer( duration: const Duration(milliseconds: 300), transform: Matrix4.identity() ..translate(0.0, _isHovered ? -8.0 : 0.0), decoration: BoxDecoration( color: const Color.fromARGB(255, 245, 245, 245), borderRadius: BorderRadius.circular(20), border: Border.all( color: _isHovered ? const Color.fromARGB(255, 0, 126, 167) : const Color.fromARGB(255, 184, 184, 184), width: _isHovered ? 2 : 1, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(_isHovered ? 0.15 : 0.05), blurRadius: _isHovered ? 20 : 10, offset: Offset(0, _isHovered ? 8 : 4), ), ], ), padding: const EdgeInsets.all(12.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ TweenAnimationBuilder( duration: const Duration(milliseconds: 600), tween: Tween(begin: 0.0, end: 1.0), curve: Curves.elasticOut, builder: (context, value, child) { return Transform.rotate( angle: (1 - value) * 0.5, child: Opacity( opacity: value, child: child, ), ); }, child: AnimatedScale( duration: const Duration(milliseconds: 200), scale: _isHovered ? 1.1 : 1.0, child: SvgPicture.asset( widget.item.iconPath, width: 48, height: 48, ), ), ), const SizedBox(height: 8), DidvanText( widget.item.title, style: Theme.of(context).textTheme.titleSmall, color: const Color.fromARGB(255, 0, 126, 167), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Expanded( child: DidvanText( widget.item.description, style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Theme.of(context).colorScheme.caption, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ), ], ), ), ), ), ); } }