import 'dart:io'; import 'package:better_open_file/better_open_file.dart'; import 'package:filesize/filesize.dart'; import 'package:flowder/flowder.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import '../../../widget/infoDialog.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:path_provider/path_provider.dart'; import '../../../api/marianumcloud/webdav/queries/listFiles/cacheableFile.dart'; import '../../../api/marianumcloud/webdav/webdavApi.dart'; import '../../../model/endpointData.dart'; import '../../../widget/centeredLeading.dart'; import '../../../widget/confirmDialog.dart'; import '../../../widget/fileViewer.dart'; import '../../../widget/unimplementedDialog.dart'; import 'files.dart'; class FileElement extends StatefulWidget { final CacheableFile file; final List path; final void Function() refetch; const FileElement(this.file, this.path, this.refetch, {super.key}); static Future download(BuildContext context, String remotePath, String name, Function(double) onProgress, Function(OpenResult) onDone) async { var paths = await getTemporaryDirectory(); var encodedPath = Uri.encodeComponent(remotePath); encodedPath = encodedPath.replaceAll('%2F', '/'); var local = paths.path + Platform.pathSeparator + name; var options = DownloaderUtils( progressCallback: (current, total) { final progress = (current / total) * 100; onProgress(progress); }, file: File(local), progress: ProgressImplementation(), deleteOnCancel: true, onDone: () { //Future result = OpenFile.open(local); // TODO legacy - refactor: remove onDone parameter Navigator.of(context).push(MaterialPageRoute(builder: (context) => FileViewer(path: local))); onDone(OpenResult(message: 'File viewer opened', type: ResultType.done)); // result.then((value) => { // onDone(value) // }); }, ); return await Flowder.download( '${await WebdavApi.webdavConnectString}$encodedPath', options, ); } @override State createState() => _FileElementState(); } class _FileElementState extends State { double percent = 0; Future? downloadCore; Widget getSubtitle() { if(widget.file.currentlyDownloading) { return Row( children: [ Container( margin: const EdgeInsets.only(right: 10), child: const Text('Download:'), ), Expanded( child: LinearProgressIndicator(value: percent/100), ), Container( margin: const EdgeInsets.only(left: 10), child: Text('${percent.round()}%'), ), ], ); } return widget.file.isDirectory ? Text('geändert ${Jiffy.parseFromDateTime(widget.file.modifiedAt ?? DateTime.now()).fromNow()}') : Text('${filesize(widget.file.size)}, ${Jiffy.parseFromDateTime(widget.file.modifiedAt ?? DateTime.now()).fromNow()}'); } @override Widget build(BuildContext context) => ListTile( leading: CenteredLeading( Icon(widget.file.isDirectory ? Icons.folder : Icons.description_outlined) ), title: Text(widget.file.name, maxLines: 2, overflow: TextOverflow.ellipsis), subtitle: getSubtitle(), trailing: Icon(widget.file.isDirectory ? Icons.arrow_right : null), onTap: () { if(widget.file.isDirectory) { Navigator.of(context).push(MaterialPageRoute( builder: (context) => Files(path: widget.path.toList()..add(widget.file.name)), )); } else { if(EndpointData().getEndpointMode() == EndpointMode.stage) { InfoDialog.show(context, 'Virtuelle Dateien im Staging Prozess können nicht heruntergeladen werden!'); return; } if(widget.file.currentlyDownloading) { showDialog( context: context, builder: (context) => ConfirmDialog( title: 'Download abbrechen?', content: 'Möchtest du den Download abbrechen?', cancelButton: 'Nein', confirmButton: 'Ja, Abbrechen', onConfirm: () { downloadCore?.then((value) { if(!value.isCancelled) value.cancel(); }); setState(() { widget.file.currentlyDownloading = false; percent = 0; downloadCore = null; }); }, ), ); return; } setState(() { widget.file.currentlyDownloading = true; }); downloadCore = FileElement.download(context, widget.file.path, widget.file.name, (progress) { setState(() => percent = progress); }, (result) { if(result.type != ResultType.done) { showDialog(context: context, builder: (context) => AlertDialog( title: const Text('Download'), content: Text(result.message), )); } setState(() { widget.file.currentlyDownloading = false; percent = 0; }); }); } }, onLongPress: () { showDialog(context: context, builder: (context) => SimpleDialog( children: [ ListTile( leading: const Icon(Icons.delete_outline), title: const Text('Löschen'), onTap: () { Navigator.of(context).pop(); showDialog(context: context, builder: (context) => ConfirmDialog( title: 'Element löschen?', content: 'Das Element wird unwiederruflich gelöscht.', onConfirm: () { WebdavApi.webdav .then((value) => value.delete(PathUri.parse(widget.file.path))) .then((value) => widget.refetch()); } )); }, ), Visibility( visible: !kReleaseMode, child: ListTile( leading: const Icon(Icons.share_outlined), title: const Text('Teilen'), onTap: () { Navigator.of(context).pop(); UnimplementedDialog.show(context); }, ), ), ], )); }, ); }