import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:firebase_auth/firebase_auth.dart'; import '../providers/mind_maps_provider.dart'; import '../models/mindmap_model.dart'; import '../core/admin_access_service.dart'; import 'mind_map_viewer_screen.dart'; import 'mind_map_editor_screen.dart'; import 'mind_map_interactive_screen.dart'; class MindMapScreen extends ConsumerWidget { const MindMapScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final mindMapsAsync = ref.watch(mindMapsProvider); final isAdmin = ref.watch(isAdminProvider); final currentUserEmail = FirebaseAuth.instance.currentUser?.email ?? ''; return Scaffold( appBar: AppBar( title: const Text('Mind Maps'), actions: [ if (isAdmin) IconButton( icon: const Icon(Icons.admin_panel_settings), onPressed: () => _showAdminOptions(context), tooltip: 'Админ панель', ), ], ), body: mindMapsAsync.when( data: (mindMaps) => _buildContent(context, mindMaps, isAdmin, currentUserEmail, ref), loading: () => const Center(child: CircularProgressIndicator()), error: (error, stack) => Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error_outline, size: 48, color: Colors.red), const SizedBox(height: 16), Text('Ошибка: $error'), const SizedBox(height: 16), ElevatedButton( onPressed: () => ref.invalidate(mindMapsProvider), child: const Text('Повторить'), ), ], ), ), ), floatingActionButton: FloatingActionButton.extended( onPressed: () => _showCreateOptions(context, ref), icon: const Icon(Icons.add), label: const Text('Создать'), ), ); } Widget _buildContent( BuildContext context, List mindMaps, bool isAdmin, String currentUserEmail, WidgetRef ref, ) { // Разделяем на основные и личные final mainMaps = mindMaps.where((m) => m.isMain).toList(); final personalMaps = mindMaps.where((m) => !m.isMain).toList(); if (mindMaps.isEmpty) { return _buildEmptyState(context, ref); } return ListView( padding: const EdgeInsets.all(16), children: [ // Основные карты if (mainMaps.isNotEmpty) ...[ _buildSectionHeader('Основные', Icons.star, Colors.amber), ...mainMaps.map((map) => _buildMindMapCard(context, map, isAdmin, currentUserEmail, ref)), const SizedBox(height: 16), ], // Личные карты if (personalMaps.isNotEmpty) ...[ _buildSectionHeader('Личные', Icons.person, Colors.blue), ...personalMaps.map((map) => _buildMindMapCard(context, map, isAdmin, currentUserEmail, ref)), ], ], ); } Widget _buildSectionHeader(String title, IconData icon, Color color) { return Padding( padding: const EdgeInsets.only(bottom: 12), child: Row( children: [ Icon(icon, color: color, size: 24), const SizedBox(width: 8), Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), ], ), ); } Widget _buildMindMapCard( BuildContext context, MindMapModel mindMap, bool isAdmin, String currentUserEmail, WidgetRef ref, ) { final isOwner = mindMap.ownerEmail == currentUserEmail; final canDelete = isAdmin || isOwner; final canEdit = isAdmin || isOwner; return Card( margin: const EdgeInsets.only(bottom: 12), child: ListTile( leading: CircleAvatar( backgroundColor: mindMap.isMain ? Colors.amber : Colors.blue, child: Icon( mindMap.isMain ? Icons.star : Icons.account_tree, color: Colors.white, ), ), title: Text( mindMap.title, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (mindMap.description.isNotEmpty) Text(mindMap.description, maxLines: 1, overflow: TextOverflow.ellipsis), const SizedBox(height: 4), Text('Владелец: ${mindMap.ownerEmail}'), Text( '${mindMap.nodeCount} узлов • ${_formatDate(mindMap.createdAt)}'), ], ), trailing: PopupMenuButton( onSelected: (value) => _handleAction(context, value, mindMap, ref), itemBuilder: (context) => [ PopupMenuItem( value: 'view', child: Row( children: [ const Icon(Icons.visibility, size: 20), const SizedBox(width: 12), const Text('Открыть'), ], ), ), if (canEdit) PopupMenuItem( value: 'edit', child: Row( children: [ const Icon(Icons.edit, size: 20), const SizedBox(width: 12), const Text('Редактировать'), ], ), ), if (canDelete) PopupMenuItem( value: 'delete', child: Row( children: [ const Icon(Icons.delete, color: Colors.red, size: 20), const SizedBox(width: 12), const Text('Удалить', style: TextStyle(color: Colors.red)), ], ), ), ], ), onTap: () => _openMindMap(context, mindMap), ), ); } Widget _buildEmptyState(BuildContext context, WidgetRef ref) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.account_tree, size: 100, color: Colors.grey[400]), const SizedBox(height: 24), Text( 'Нет mind карт', style: TextStyle(fontSize: 20, color: Colors.grey[600]), ), const SizedBox(height: 8), Text( 'Создайте первую карту вручную или с помощью AI', textAlign: TextAlign.center, style: TextStyle(color: Colors.grey[500]), ), const SizedBox(height: 32), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton.icon( onPressed: () => _showCreateManualDialog(context, ref), icon: const Icon(Icons.add), label: const Text('Вручную'), ), const SizedBox(width: 16), FilledButton.icon( onPressed: () => _showCreateAIDialog(context, ref), icon: const Icon(Icons.auto_awesome), label: const Text('AI Генерация'), ), ], ), ], ), ); } void _showCreateOptions(BuildContext context, WidgetRef ref) { showModalBottomSheet( context: context, builder: (context) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.add, color: Colors.blue), title: const Text('Создать вручную'), subtitle: const Text('Пустая mind map'), onTap: () { Navigator.pop(context); _showCreateManualDialog(context, ref); }, ), ListTile( leading: const Icon(Icons.auto_awesome, color: Colors.purple), title: const Text('AI Генерация'), subtitle: const Text('С помощью DeepSeek'), onTap: () { Navigator.pop(context); _showCreateAIDialog(context, ref); }, ), ], ), ), ); } void _showCreateManualDialog(BuildContext context, WidgetRef ref) { Navigator.push( context, MaterialPageRoute( builder: (context) => const MindMapEditorScreen(), ), ); } void _showCreateAIDialog(BuildContext context, WidgetRef ref) { Navigator.push( context, MaterialPageRoute( builder: (context) => const MindMapEditorScreen(), ), ); } void _handleAction( BuildContext context, String action, MindMapModel mindMap, WidgetRef ref, ) { switch (action) { case 'view': _openMindMap(context, mindMap); break; case 'edit': _editMindMap(context, mindMap, ref); break; case 'delete': _confirmDelete(context, mindMap, ref); break; } } void _openMindMap(BuildContext context, MindMapModel mindMap) { Navigator.push( context, MaterialPageRoute( builder: (context) => MindMapInteractiveScreen(mindMap: mindMap), ), ); } void _editMindMap(BuildContext context, MindMapModel mindMap, WidgetRef ref) { Navigator.push( context, MaterialPageRoute( builder: (context) => MindMapEditorScreen(mindMap: mindMap), ), ); } void _confirmDelete( BuildContext context, MindMapModel mindMap, WidgetRef ref) { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Удалить mind map?'), content: Text( '"${mindMap.title}" будет удалена навсегда. Это действие нельзя отменить.'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Отмена'), ), TextButton( onPressed: () async { try { await ref .read(mindMapsNotifierProvider.notifier) .deleteMindMap(mindMap.id, mindMap.ownerEmail); if (context.mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('✅ Mind map удалена'), backgroundColor: Colors.green, ), ); } } catch (e) { if (context.mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('❌ Ошибка: $e'), backgroundColor: Colors.red, ), ); } } }, style: TextButton.styleFrom(foregroundColor: Colors.red), child: const Text('Удалить'), ), ], ), ); } void _showAdminOptions(BuildContext context) { // TODO: Открыть админ панель ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Админ панель в разработке')), ); } String _formatDate(DateTime date) { return '${date.day.toString().padLeft(2, '0')}.' '${date.month.toString().padLeft(2, '0')}.' '${date.year}'; } }