import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:file_picker/file_picker.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'main.dart'; import 'sidebar.dart'; import 'shares.dart'; import 'sharedialog.dart'; import 'package:path_provider/path_provider.dart'; import 'package:file_saver/file_saver.dart'; import 'dart:io'; import 'config.dart'; class FileInfo { final int id; final String name; final int size; final DateTime uploadedAt; FileInfo({ required this.id, required this.name, required this.size, required this.uploadedAt, }); factory FileInfo.fromJson(Map json) { return FileInfo( id: json['id'], name: json['original_name'], size: json['size'], uploadedAt: DateTime.parse(json['uploaded_at']), ); } } class MainPage extends StatefulWidget { const MainPage({super.key}); @override State createState() => _MainPageState(); } class _MainPageState extends State { SidebarPage _selectedPage = SidebarPage.myFiles; List _files = []; bool _isLoading = false; String? _error; @override void initState() { super.initState(); _fetchFiles(); } Future _fetchFiles() async { setState(() { _isLoading = true; _error = null; }); try { final prefs = await SharedPreferences.getInstance(); final jwt = prefs.getString('jwt'); if (jwt == null) { setState(() { _error = 'Sessione scaduta, effettua di nuovo il login.'; _isLoading = false; }); return; } final uri = Uri.parse('${Config.apiUrl}/files'); final response = await http.get( uri, headers: {'Authorization': 'Bearer $jwt'}, ); if (response.statusCode == 200) { final List data = jsonDecode(response.body); setState(() { _files = data.map((file) => FileInfo.fromJson(file)).toList(); _isLoading = false; }); } else { setState(() { _error = 'Errore durante il recupero dei file.'; _isLoading = false; }); } } catch (e) { setState(() { _error = 'Errore di rete: ${e.toString()}'; _isLoading = false; }); } } Future _logout() async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('jwt'); if (mounted) { Navigator.of(context).pushAndRemoveUntil( MaterialPageRoute(builder: (_) => const AuthScreen()), (route) => false, ); } } void _onPageSelected(SidebarPage page) { setState(() { _selectedPage = page; }); } Future _uploadFile() async { final result = await FilePicker.platform.pickFiles(); if (result == null || result.files.isEmpty) return; final file = result.files.first; final prefs = await SharedPreferences.getInstance(); final jwt = prefs.getString('jwt'); if (jwt == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Sessione scaduta, effettua di nuovo il login.')), ); return; } final uri = Uri.parse('${Config.apiUrl}/upload'); final request = http.MultipartRequest('POST', uri) ..headers['Authorization'] = 'Bearer $jwt' ..files.add( http.MultipartFile.fromBytes( 'file', file.bytes!, filename: file.name, ), ); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Caricamento di ${file.name} in corso...')), ); final response = await request.send(); if (response.statusCode == 200 || response.statusCode == 201) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('File caricato con successo!')), ); _fetchFiles(); // Refresh the file list } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Errore durante l\'upload.')), ); } } Future _downloadFile(FileInfo file) async { try { final prefs = await SharedPreferences.getInstance(); final jwt = prefs.getString('jwt'); if (jwt == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Sessione scaduta, effettua di nuovo il login.')), ); return; } final uri = Uri.parse('${Config.apiUrl}/files/${file.id}'); ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Download in corso...')), ); final response = await http.get( uri, headers: {'Authorization': 'Bearer $jwt'}, ); if (response.statusCode == 200) { if (Platform.isAndroid || Platform.isIOS) { await FileSaver.instance.saveFile( name: file.name, bytes: response.bodyBytes, ); } else { // Desktop platforms final directory = await getDownloadsDirectory(); if (directory != null) { final filePath = '${directory.path}/${file.name}'; final fileObj = File(filePath); await fileObj.writeAsBytes(response.bodyBytes); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('File salvato in: $filePath')), ); } else { throw Exception('Could not access downloads directory'); } } ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('File ${file.name} scaricato con successo!')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Errore durante il download.')), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Errore di rete: ${e.toString()}')), ); } } Future _deleteFile(FileInfo file) async { try { final prefs = await SharedPreferences.getInstance(); final jwt = prefs.getString('jwt'); if (jwt == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Sessione scaduta, effettua di nuovo il login.')), ); return; } final uri = Uri.parse('${Config.apiUrl}/files/${file.id}'); final response = await http.delete( uri, headers: {'Authorization': 'Bearer $jwt'}, ); if (response.statusCode == 204) { setState(() { _files.removeWhere((f) => f.id == file.id); }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('File ${file.name} eliminato con successo!')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Errore durante l\'eliminazione.')), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Errore di rete: ${e.toString()}')), ); } } void _showShareDialog(FileInfo file) { showDialog( context: context, builder: (context) => ShareDialog( fileId: file.id, fileName: file.name, ), ); } void _showFileOptions(FileInfo file) { showModalBottomSheet( context: context, builder: (context) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.download), title: const Text('Download'), onTap: () { Navigator.pop(context); _downloadFile(file); }, ), ListTile( leading: const Icon(Icons.share), title: const Text('Condividi'), onTap: () { Navigator.pop(context); _showShareDialog(file); }, ), ListTile( leading: Icon(Icons.delete, color: Colors.red[700]), title: Text('Elimina', style: TextStyle(color: Colors.red[700])), onTap: () { Navigator.pop(context); _deleteFile(file); }, ), ], ), ), ); } Widget _buildMyFiles() { if (_isLoading) { return const Center(child: CircularProgressIndicator()); } if (_error != null) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text(_error!, style: TextStyle(color: Colors.red[700])), const SizedBox(height: 16), ElevatedButton( onPressed: _fetchFiles, child: const Text('Riprova'), ), ], ), ); } if (_files.isEmpty) { return const Center( child: Text('Nessun file trovato. Carica il tuo primo file!'), ); } return ListView.separated( padding: const EdgeInsets.all(32), itemCount: _files.length, separatorBuilder: (_, __) => const Divider(), itemBuilder: (context, idx) { final file = _files[idx]; return ListTile( leading: const Icon(Icons.insert_drive_file), title: Text(file.name), subtitle: Text( "Size: ${(file.size / 1024).toStringAsFixed(1)} KB • Uploaded: ${file.uploadedAt.toLocal()}", style: const TextStyle(fontSize: 12), ), trailing: IconButton( icon: const Icon(Icons.more_vert), onPressed: () => _showFileOptions(file), ), ); }, ); } @override Widget build(BuildContext context) { Widget content; if (_selectedPage == SidebarPage.myFiles) { content = Stack( children: [ _buildMyFiles(), Positioned( bottom: 32, right: 32, child: FloatingActionButton.extended( onPressed: _uploadFile, icon: const Icon(Icons.upload_file), label: const Text("Upload"), backgroundColor: Theme.of(context).colorScheme.primary, foregroundColor: Theme.of(context).colorScheme.onPrimary, ), ), ], ); } else if (_selectedPage == SidebarPage.shared) { content = const SharesPage(); } else { content = const Center(child: Text("Settings (coming soon)")); } return Scaffold( body: Row( children: [ Sidebar( selectedPage: _selectedPage, onPageSelected: _onPageSelected, onLogout: _logout, ), Expanded(child: content), ], ), ); } }