import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import '../models/project.dart'; import '../services/storage_service.dart'; import 'project_screen.dart'; import '../widgets/project_dialog.dart'; import '../widgets/about_dialog.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { final StorageService _storageService = StorageService(); List _projects = []; bool _isLoading = true; @override void initState() { super.initState(); _loadProjects(); // Show web warning after build if (kIsWeb) { WidgetsBinding.instance.addPostFrameCallback((_) { _showWebWarning(); }); } } Future _loadProjects() async { setState(() => _isLoading = true); final projects = await _storageService.loadProjects(); setState(() { _projects = projects; _isLoading = false; }); } Future _saveProjects() async { await _storageService.saveProjects(_projects); } void _addProject(Project project) { setState(() { _projects.add(project); }); _saveProjects(); } void _updateProject(Project updatedProject) { setState(() { final index = _projects.indexWhere((p) => p.id == updatedProject.id); if (index != -1) { _projects[index] = updatedProject; } }); _saveProjects(); } void _deleteProject(String projectId) { setState(() { _projects.removeWhere((p) => p.id == projectId); }); _saveProjects(); } void _showProjectDialog({Project? project}) { showDialog( context: context, builder: (context) => ProjectDialog( project: project, onSave: (newProject) { if (project == null) { _addProject(newProject); } else { _updateProject(newProject); } }, ), ); } void _showAboutDialog() { showDialog( context: context, builder: (context) => const AppAboutDialog(), ); } Future _showStorageInfo() async { final filePath = await _storageService.getProjectsFilePath(); if (!mounted) return; showDialog( context: context, builder: (context) => AlertDialog( title: const Row( children: [ Icon(Icons.folder_open), SizedBox(width: 8), Text('Storage Location'), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Your projects are saved in:', style: TextStyle(fontWeight: FontWeight.bold), ), const SizedBox(height: 8), SelectableText( filePath, style: const TextStyle( fontFamily: 'monospace', fontSize: 12, ), ), const SizedBox(height: 16), const Text( 'You can share this file with other users or back it up for safekeeping.', style: TextStyle(fontSize: 12), ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Close'), ), ], ), ); } void _showWebWarning() { showDialog( context: context, barrierDismissible: true, builder: (context) => AlertDialog( title: const Row( children: [ Icon(Icons.warning, color: Colors.orange), SizedBox(width: 8), Text('Web Platform Limitation'), ], ), content: const Text( 'You are running this app in a web browser.\n\n' '⚠️ UDP networking is NOT supported in web browsers due to security restrictions.\n\n' '✅ For full functionality, please run this app on:\n' ' • Windows (flutter run -d windows)\n' ' • macOS (flutter run -d macos)\n' ' • Linux (flutter run -d linux)\n' ' • Android or iOS devices\n\n' 'The app will work for creating and managing projects, but UDP packets cannot be sent from a browser.', ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('I Understand'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('UnityUDP'), actions: [ if (kIsWeb) Padding( padding: const EdgeInsets.only(right: 8), child: IconButton( icon: const Icon(Icons.warning_amber, color: Colors.orange), onPressed: _showWebWarning, tooltip: 'Web Platform Limitations', ), ), if (!kIsWeb) IconButton( icon: const Icon(Icons.folder), onPressed: _showStorageInfo, tooltip: 'Storage Location', ), IconButton( icon: const Icon(Icons.info_outline), onPressed: _showAboutDialog, tooltip: 'About', ), ], ), body: _isLoading ? const Center(child: CircularProgressIndicator()) : _projects.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.folder_open, size: 64, color: Theme.of(context).colorScheme.primary.withAlpha(128), ), const SizedBox(height: 16), Text( 'No projects yet', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), Text( 'Create your first project to get started', style: Theme.of(context).textTheme.bodyMedium, ), ], ), ) : ListView.builder( padding: const EdgeInsets.all(16), itemCount: _projects.length, itemBuilder: (context, index) { final project = _projects[index]; return Card( margin: const EdgeInsets.only(bottom: 12), child: InkWell( borderRadius: BorderRadius.circular(12), onTap: () async { final updatedProject = await Navigator.push( context, MaterialPageRoute( builder: (context) => ProjectScreen(project: project), ), ); if (updatedProject != null) { _updateProject(updatedProject); } }, child: Padding( padding: const EdgeInsets.all(16), child: Row( children: [ Container( width: 48, height: 48, decoration: BoxDecoration( color: Theme.of(context) .colorScheme .primaryContainer, borderRadius: BorderRadius.circular(8), ), child: Icon( Icons.folder, color: Theme.of(context) .colorScheme .onPrimaryContainer, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( project.name, style: Theme.of(context) .textTheme .titleMedium ?.copyWith( fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( '${project.ipAddress}:${project.port} • ${project.packages.length} package(s)', style: Theme.of(context).textTheme.bodySmall, ), ], ), ), PopupMenuButton( itemBuilder: (context) => [ const PopupMenuItem( value: 'edit', child: Row( children: [ Icon(Icons.edit), SizedBox(width: 8), Text('Edit'), ], ), ), const PopupMenuItem( value: 'delete', child: Row( children: [ Icon(Icons.delete, color: Colors.red), SizedBox(width: 8), Text('Delete', style: TextStyle(color: Colors.red)), ], ), ), ], onSelected: (value) { if (value == 'edit') { _showProjectDialog(project: project); } else if (value == 'delete') { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Delete Project'), content: Text( 'Are you sure you want to delete "${project.name}"?'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Cancel'), ), TextButton( onPressed: () { _deleteProject(project.id); Navigator.pop(context); }, style: TextButton.styleFrom( foregroundColor: Colors.red, ), child: const Text('Delete'), ), ], ), ); } }, ), ], ), ), ), ); }, ), floatingActionButton: FloatingActionButton.extended( onPressed: () => _showProjectDialog(), icon: const Icon(Icons.add), label: const Text('New Project'), ), ); } }