Added inline file download progressbar, handle OpenFile directly and handle errors
This commit is contained in:
parent
58bbfc6329
commit
d21dc26a18
@ -14,7 +14,11 @@ class CacheableFile {
|
|||||||
DateTime? createdAt;
|
DateTime? createdAt;
|
||||||
DateTime? modifiedAt;
|
DateTime? modifiedAt;
|
||||||
|
|
||||||
CacheableFile(this.path, this.isDirectory, this.name, {this.mimeType, this.size, this.eTag, this.createdAt, this.modifiedAt});
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
bool currentlyDownloading = false;
|
||||||
|
|
||||||
|
|
||||||
|
CacheableFile({required this.path, required this.isDirectory, required this.name, this.mimeType, this.size, this.eTag, this.createdAt, this.modifiedAt});
|
||||||
|
|
||||||
CacheableFile.fromDavFile(WebDavFile file) {
|
CacheableFile.fromDavFile(WebDavFile file) {
|
||||||
path = file.path;
|
path = file.path;
|
||||||
|
@ -8,9 +8,9 @@ part of 'cacheableFile.dart';
|
|||||||
|
|
||||||
CacheableFile _$CacheableFileFromJson(Map<String, dynamic> json) =>
|
CacheableFile _$CacheableFileFromJson(Map<String, dynamic> json) =>
|
||||||
CacheableFile(
|
CacheableFile(
|
||||||
json['path'] as String,
|
path: json['path'] as String,
|
||||||
json['isDirectory'] as bool,
|
isDirectory: json['isDirectory'] as bool,
|
||||||
json['name'] as String,
|
name: json['name'] as String,
|
||||||
mimeType: json['mimeType'] as String?,
|
mimeType: json['mimeType'] as String?,
|
||||||
size: json['size'] as int?,
|
size: json['size'] as int?,
|
||||||
eTag: json['eTag'] as String?,
|
eTag: json['eTag'] as String?,
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
import 'dart:developer';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:better_open_file/better_open_file.dart';
|
|
||||||
import 'package:flowder/flowder.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:marianum_mobile/api/marianumcloud/webdav/webdavApi.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
|
||||||
|
|
||||||
class FileDownload extends StatefulWidget {
|
|
||||||
String source;
|
|
||||||
String name;
|
|
||||||
FileDownload(this.source, this.name, {Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<FileDownload> createState() => _FileDownloadState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FileDownloadState extends State<FileDownload> {
|
|
||||||
late DownloaderCore core;
|
|
||||||
|
|
||||||
void download(String remotePath, String name) async {
|
|
||||||
Directory paths = await getApplicationDocumentsDirectory();
|
|
||||||
|
|
||||||
String local = paths.path + Platform.pathSeparator + name;
|
|
||||||
|
|
||||||
DownloaderUtils options = DownloaderUtils(
|
|
||||||
progressCallback: (current, total) {
|
|
||||||
final progress = (current / total) * 100;
|
|
||||||
setState(() => {
|
|
||||||
percent = progress,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
file: File(local),
|
|
||||||
progress: ProgressImplementation(),
|
|
||||||
deleteOnCancel: true,
|
|
||||||
onDone: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
showDialog(context: context, builder: (context) {
|
|
||||||
return AlertDialog(
|
|
||||||
icon: const Icon(Icons.link),
|
|
||||||
title: const Text("Dateipfad"),
|
|
||||||
content: Text(local),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: Text("Öffnen mit"),
|
|
||||||
onPressed: () {
|
|
||||||
OpenFile.open(local).then((value) => () {
|
|
||||||
log("Result: ${value.toString()}");
|
|
||||||
});
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
log(local);
|
|
||||||
|
|
||||||
core = await Flowder.download(
|
|
||||||
"${await WebdavApi.webdavConnectString}$remotePath",
|
|
||||||
options,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
double percent = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
log("Downloading file: Source(${widget.source}), Name(${widget.name})");
|
|
||||||
download(widget.source, widget.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text("Download"),
|
|
||||||
content: ListTile(
|
|
||||||
leading: const Icon(Icons.download),
|
|
||||||
title: LinearProgressIndicator(value: percent/100),
|
|
||||||
trailing: Text("${percent.round()}%"),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
child: const Text("Abbrechen"),
|
|
||||||
onPressed: () => () {
|
|
||||||
if(!core.isCancelled) core.cancel();
|
|
||||||
Navigator.of(context, rootNavigator: true).pop();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
136
lib/screen/pages/files/fileElement.dart
Normal file
136
lib/screen/pages/files/fileElement.dart
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
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/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:jiffy/jiffy.dart';
|
||||||
|
import 'package:marianum_mobile/api/marianumcloud/webdav/queries/listFiles/cacheableFile.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../../../api/marianumcloud/webdav/webdavApi.dart';
|
||||||
|
import '../../../data/files/filesProps.dart';
|
||||||
|
|
||||||
|
class FileElement extends StatefulWidget {
|
||||||
|
CacheableFile file;
|
||||||
|
Function updateAppBar;
|
||||||
|
FileElement(this.file, this.updateAppBar, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FileElement> createState() => _FileElementState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FileElementState extends State<FileElement> {
|
||||||
|
late DownloaderCore core;
|
||||||
|
double percent = 0;
|
||||||
|
|
||||||
|
void download(String remotePath, String name) async {
|
||||||
|
|
||||||
|
Directory paths = await getApplicationDocumentsDirectory();
|
||||||
|
|
||||||
|
String local = paths.path + Platform.pathSeparator + name;
|
||||||
|
|
||||||
|
DownloaderUtils options = DownloaderUtils(
|
||||||
|
progressCallback: (current, total) {
|
||||||
|
final progress = (current / total) * 100;
|
||||||
|
setState(() => {
|
||||||
|
percent = progress,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
file: File(local),
|
||||||
|
progress: ProgressImplementation(),
|
||||||
|
deleteOnCancel: true,
|
||||||
|
onDone: () {
|
||||||
|
Future<OpenResult> result = OpenFile.open(local);
|
||||||
|
|
||||||
|
result.then((value) => {
|
||||||
|
if(value.type != ResultType.done) {
|
||||||
|
showDialog(context: context, builder: (context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text("Download"),
|
||||||
|
content: Text(value.message),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
widget.file.currentlyDownloading = false;
|
||||||
|
percent = 0;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
log(local);
|
||||||
|
|
||||||
|
core = await Flowder.download(
|
||||||
|
"${await WebdavApi.webdavConnectString}$remotePath",
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(widget.file.modifiedAt).fromNow()}") : Text("${filesize(widget.file.size)}, ${Jiffy(widget.file.modifiedAt).fromNow()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: Icon(widget.file.isDirectory ? Icons.folder : Icons.file_open_outlined),
|
||||||
|
title: Text(widget.file.name),
|
||||||
|
subtitle: getSubtitle(),
|
||||||
|
trailing: Icon(widget.file.isDirectory ? Icons.arrow_right : Icons.open_in_browser),
|
||||||
|
onTap: () {
|
||||||
|
FilesProps props = Provider.of<FilesProps>(context, listen: false);
|
||||||
|
widget.updateAppBar(props);
|
||||||
|
if(widget.file.isDirectory) {
|
||||||
|
props.enterFolder(widget.file.name);
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
widget.file.currentlyDownloading = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
download(widget.file.path, widget.file.name);
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
showModalBottomSheet<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return ListView(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.delete),
|
||||||
|
title: Text("'${widget.file.name}' Löschen"),
|
||||||
|
),
|
||||||
|
const ListTile(
|
||||||
|
leading: Icon(Icons.share),
|
||||||
|
title: Text("Teilen"),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,11 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:filesize/filesize.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:jiffy/jiffy.dart';
|
|
||||||
import 'package:marianum_mobile/api/marianumcloud/webdav/queries/listFiles/cacheableFile.dart';
|
import 'package:marianum_mobile/api/marianumcloud/webdav/queries/listFiles/cacheableFile.dart';
|
||||||
import 'package:marianum_mobile/screen/pages/files/fileDownload.dart';
|
|
||||||
import 'package:marianum_mobile/widget/errorView.dart';
|
import 'package:marianum_mobile/widget/errorView.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../../../data/files/filesProps.dart';
|
import '../../../data/files/filesProps.dart';
|
||||||
|
import 'fileElement.dart';
|
||||||
|
|
||||||
class Files extends StatefulWidget {
|
class Files extends StatefulWidget {
|
||||||
Function appBar;
|
Function appBar;
|
||||||
@ -57,45 +54,7 @@ class _FilesState extends State<Files> {
|
|||||||
itemCount: value.listFilesResponse.files.length,
|
itemCount: value.listFilesResponse.files.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
CacheableFile file = value.listFilesResponse.files.skip(index).first;
|
CacheableFile file = value.listFilesResponse.files.skip(index).first;
|
||||||
return ListTile(
|
return FileElement(file, updateAppBar);
|
||||||
leading: Icon(file.isDirectory ? Icons.folder : Icons.file_open_outlined),
|
|
||||||
title: Text(file.name),
|
|
||||||
subtitle: file.isDirectory ? Text("geändert ${Jiffy(file.modifiedAt).fromNow()}") : Text("${filesize(file.size)}, ${Jiffy(file.modifiedAt).fromNow()}"),
|
|
||||||
trailing: Icon(file.isDirectory ? Icons.arrow_right : Icons.open_in_new),
|
|
||||||
onTap: () {
|
|
||||||
FilesProps props = Provider.of<FilesProps>(context, listen: false);
|
|
||||||
updateAppBar(props);
|
|
||||||
if(file.isDirectory) {
|
|
||||||
props.enterFolder(file.name);
|
|
||||||
} else {
|
|
||||||
//TODO implement file download / view
|
|
||||||
log(file.path);
|
|
||||||
|
|
||||||
showDialog(context: context, builder: (context) {
|
|
||||||
return FileDownload(file.path, file.name);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onLongPress: () {
|
|
||||||
showModalBottomSheet<void>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return ListView(
|
|
||||||
children: [
|
|
||||||
ListTile(
|
|
||||||
leading: const Icon(Icons.delete),
|
|
||||||
title: Text("'${file.name}' Löschen"),
|
|
||||||
),
|
|
||||||
const ListTile(
|
|
||||||
leading: Icon(Icons.share),
|
|
||||||
title: Text("Teilen"),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user