litecloud/lightcloud_app/lib/mainpage.dart

396 lines
11 KiB
Dart

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<String, dynamic> 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<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
SidebarPage _selectedPage = SidebarPage.myFiles;
List<FileInfo> _files = [];
bool _isLoading = false;
String? _error;
@override
void initState() {
super.initState();
_fetchFiles();
}
Future<void> _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<dynamic> 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<void> _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<void> _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<void> _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<void> _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),
],
),
);
}
}