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 '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 '../../../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 { Directory paths = await getTemporaryDirectory(); var encodedPath = Uri.encodeComponent(remotePath); encodedPath = encodedPath.replaceAll("%2F", "/"); String local = paths.path + Platform.pathSeparator + name; DownloaderUtils 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) { return 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) { return Files(widget.path.toList()..add(widget.file.name)); }, )); } else { 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) { return AlertDialog( title: const Text("Download"), content: Text(result.message), ); }); } setState(() { widget.file.currentlyDownloading = false; percent = 0; }); }); } }, onLongPress: () { showDialog(context: context, builder: (context) { return 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); }, ), ), ], ); }); }, ); } }