dart format
This commit is contained in:
@@ -50,7 +50,11 @@ class _ClipboardBannerState extends State<ClipboardBanner> {
|
||||
final src = _normalised(f.path);
|
||||
if (dst == src || dst.startsWith(src)) return false;
|
||||
}
|
||||
final destination = _joinPath(widget.currentFolder, f.name, isDirectory: f.isDirectory);
|
||||
final destination = _joinPath(
|
||||
widget.currentFolder,
|
||||
f.name,
|
||||
isDirectory: f.isDirectory,
|
||||
);
|
||||
if (destination != f.path) atLeastOneActionable = true;
|
||||
}
|
||||
return atLeastOneActionable;
|
||||
@@ -75,14 +79,24 @@ class _ClipboardBannerState extends State<ClipboardBanner> {
|
||||
try {
|
||||
final webdav = await WebdavApi.webdav;
|
||||
for (final file in cb.files) {
|
||||
final destination = _joinPath(widget.currentFolder, file.name, isDirectory: file.isDirectory);
|
||||
final destination = _joinPath(
|
||||
widget.currentFolder,
|
||||
file.name,
|
||||
isDirectory: file.isDirectory,
|
||||
);
|
||||
if (destination == file.path) continue;
|
||||
try {
|
||||
if (operation == FileClipboardOperation.cut) {
|
||||
await webdav.move(PathUri.parse(file.path), PathUri.parse(destination));
|
||||
await webdav.move(
|
||||
PathUri.parse(file.path),
|
||||
PathUri.parse(destination),
|
||||
);
|
||||
invalidatedSourceFolders.add(_parentCacheKey(file.path));
|
||||
} else {
|
||||
await webdav.copy(PathUri.parse(file.path), PathUri.parse(destination));
|
||||
await webdav.copy(
|
||||
PathUri.parse(file.path),
|
||||
PathUri.parse(destination),
|
||||
);
|
||||
}
|
||||
} on Object catch (e) {
|
||||
errors.add('${file.name}: $e');
|
||||
@@ -111,42 +125,49 @@ class _ClipboardBannerState extends State<ClipboardBanner> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListenableBuilder(
|
||||
listenable: FileClipboard.instance,
|
||||
builder: (context, _) {
|
||||
final cb = FileClipboard.instance;
|
||||
if (cb.isEmpty) return const SizedBox.shrink();
|
||||
final cut = cb.operation == FileClipboardOperation.cut;
|
||||
final count = cb.files.length;
|
||||
final label = count == 1 ? '"${cb.files.first.name}"' : '$count Elemente';
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(cut ? Icons.drive_file_move_outline : Icons.copy_outlined, size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
cut ? '$label verschieben' : '$label kopieren',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _busy || !_canPaste ? null : _paste,
|
||||
child: _busy
|
||||
? const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: const Text('Hier einfügen'),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Verwerfen',
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
onPressed: _busy ? null : cb.clear,
|
||||
),
|
||||
],
|
||||
listenable: FileClipboard.instance,
|
||||
builder: (context, _) {
|
||||
final cb = FileClipboard.instance;
|
||||
if (cb.isEmpty) return const SizedBox.shrink();
|
||||
final cut = cb.operation == FileClipboardOperation.cut;
|
||||
final count = cb.files.length;
|
||||
final label = count == 1 ? '"${cb.files.first.name}"' : '$count Elemente';
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
cut ? Icons.drive_file_move_outline : Icons.copy_outlined,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
cut ? '$label verschieben' : '$label kopieren',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _busy || !_canPaste ? null : _paste,
|
||||
child: _busy
|
||||
? const SizedBox(
|
||||
width: 14,
|
||||
height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
)
|
||||
: const Text('Hier einfügen'),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Verwerfen',
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
onPressed: _busy ? null : cb.clear,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,49 +12,67 @@ void showFileDetailsSheet(BuildContext context, CacheableFile file) {
|
||||
showDetailsBottomSheet(
|
||||
context,
|
||||
header: ListTile(
|
||||
leading: Icon(file.isDirectory ? Icons.folder : Icons.description_outlined, size: 32),
|
||||
title: Text(file.name, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
leading: Icon(
|
||||
file.isDirectory ? Icons.folder : Icons.description_outlined,
|
||||
size: 32,
|
||||
),
|
||||
title: Text(
|
||||
file.name,
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(file.isDirectory ? 'Ordner' : (file.mimeType ?? '–')),
|
||||
),
|
||||
children: (_) => [
|
||||
_DetailRow(label: 'Pfad', value: file.path, copyable: true),
|
||||
if (!file.isDirectory) _DetailRow(label: 'Größe', value: filesize(file.size)),
|
||||
if (!file.isDirectory)
|
||||
_DetailRow(label: 'Größe', value: filesize(file.size)),
|
||||
if (file.modifiedAt != null)
|
||||
_DetailRow(
|
||||
label: 'Geändert',
|
||||
value: '${file.modifiedAt!.formatDateTime()} (${file.modifiedAt!.formatRelative()})',
|
||||
value:
|
||||
'${file.modifiedAt!.formatDateTime()} (${file.modifiedAt!.formatRelative()})',
|
||||
),
|
||||
if (file.createdAt != null)
|
||||
_DetailRow(label: 'Erstellt', value: file.createdAt!.formatDateTime()),
|
||||
if (file.eTag != null) _DetailRow(label: 'ETag', value: file.eTag!, copyable: true),
|
||||
if (file.eTag != null)
|
||||
_DetailRow(label: 'ETag', value: file.eTag!, copyable: true),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
class _DetailRow extends StatelessWidget {
|
||||
const _DetailRow({required this.label, required this.value, this.copyable = false});
|
||||
const _DetailRow({
|
||||
required this.label,
|
||||
required this.value,
|
||||
this.copyable = false,
|
||||
});
|
||||
final String label;
|
||||
final String value;
|
||||
final bool copyable;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 90,
|
||||
child: Text(label, style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 90,
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
Expanded(child: SelectableText(value)),
|
||||
if (copyable)
|
||||
IconButton(
|
||||
tooltip: 'Kopieren',
|
||||
icon: const Icon(Icons.copy, size: 18),
|
||||
onPressed: () => copyToClipboard(context, value),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
Expanded(child: SelectableText(value)),
|
||||
if (copyable)
|
||||
IconButton(
|
||||
tooltip: 'Kopieren',
|
||||
icon: const Icon(Icons.copy, size: 18),
|
||||
onPressed: () => copyToClipboard(context, value),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,11 +138,17 @@ class _FileElementState extends State<FileElement> {
|
||||
|
||||
void _onTap() {
|
||||
if (widget.file.isDirectory) {
|
||||
AppRoutes.openFolder(context, widget.path.toList()..add(widget.file.name));
|
||||
AppRoutes.openFolder(
|
||||
context,
|
||||
widget.path.toList()..add(widget.file.name),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (EndpointData().getEndpointMode() == EndpointMode.stage) {
|
||||
InfoDialog.show(context, 'Virtuelle Dateien im Staging Prozess können nicht heruntergeladen werden!');
|
||||
InfoDialog.show(
|
||||
context,
|
||||
'Virtuelle Dateien im Staging Prozess können nicht heruntergeladen werden!',
|
||||
);
|
||||
return;
|
||||
}
|
||||
final status = _job?.status.value;
|
||||
@@ -178,21 +184,34 @@ class _FileElementState extends State<FileElement> {
|
||||
autofocus: true,
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => Navigator.of(dialogCtx).pop(), child: const Text('Abbrechen')),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(dialogCtx).pop(controller.text.trim()),
|
||||
onPressed: () => Navigator.of(dialogCtx).pop(),
|
||||
child: const Text('Abbrechen'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(dialogCtx).pop(controller.text.trim()),
|
||||
child: const Text('Umbenennen'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (newName == null || newName.isEmpty || newName == widget.file.name) return;
|
||||
if (newName == null || newName.isEmpty || newName == widget.file.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
final parent = _parentPathOf(widget.file.path);
|
||||
final destination = _joinPath(parent, newName, isDirectory: widget.file.isDirectory);
|
||||
final destination = _joinPath(
|
||||
parent,
|
||||
newName,
|
||||
isDirectory: widget.file.isDirectory,
|
||||
);
|
||||
await _runWebdavOp(() async {
|
||||
final webdav = await WebdavApi.webdav;
|
||||
await webdav.move(PathUri.parse(widget.file.path), PathUri.parse(destination));
|
||||
await webdav.move(
|
||||
PathUri.parse(widget.file.path),
|
||||
PathUri.parse(destination),
|
||||
);
|
||||
}, errorTitle: 'Umbenennen fehlgeschlagen');
|
||||
} finally {
|
||||
controller.dispose();
|
||||
@@ -205,10 +224,14 @@ class _FileElementState extends State<FileElement> {
|
||||
} else {
|
||||
FileClipboard.instance.cut([widget.file]);
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text('"${widget.file.name}" zum ${copy ? "Kopieren" : "Verschieben"} bereitgelegt'),
|
||||
duration: const Duration(seconds: 2),
|
||||
));
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'"${widget.file.name}" zum ${copy ? "Kopieren" : "Verschieben"} bereitgelegt',
|
||||
),
|
||||
duration: const Duration(seconds: 2),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _delete() async {
|
||||
@@ -227,7 +250,10 @@ class _FileElementState extends State<FileElement> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _runWebdavOp(Future<void> Function() action, {required String errorTitle}) async {
|
||||
Future<void> _runWebdavOp(
|
||||
Future<void> Function() action, {
|
||||
required String errorTitle,
|
||||
}) async {
|
||||
try {
|
||||
await action();
|
||||
widget.refetch();
|
||||
@@ -287,13 +313,13 @@ class _FileElementState extends State<FileElement> {
|
||||
|
||||
@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: _subtitle(),
|
||||
trailing: Icon(widget.file.isDirectory ? Icons.arrow_right : null),
|
||||
onTap: _onTap,
|
||||
onLongPress: _showActionSheet,
|
||||
);
|
||||
leading: CenteredLeading(
|
||||
Icon(widget.file.isDirectory ? Icons.folder : Icons.description_outlined),
|
||||
),
|
||||
title: Text(widget.file.name, maxLines: 2, overflow: TextOverflow.ellipsis),
|
||||
subtitle: _subtitle(),
|
||||
trailing: Icon(widget.file.isDirectory ? Icons.arrow_right : null),
|
||||
onTap: _onTap,
|
||||
onLongPress: _showActionSheet,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,37 +23,48 @@ class FilesSortActions extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
PopupMenuButton<bool>(
|
||||
icon: Icon(ascending ? Icons.text_rotate_up : Icons.text_rotation_down),
|
||||
icon: Icon(
|
||||
ascending ? Icons.text_rotate_up : Icons.text_rotation_down,
|
||||
),
|
||||
itemBuilder: (context) => [true, false]
|
||||
.map((e) => PopupMenuItem<bool>(
|
||||
value: e,
|
||||
enabled: e != ascending,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(e ? Icons.text_rotate_up : Icons.text_rotation_down,
|
||||
color: theme.colorScheme.onSurface),
|
||||
const SizedBox(width: 15),
|
||||
Text(e ? 'Aufsteigend' : 'Absteigend'),
|
||||
],
|
||||
),
|
||||
))
|
||||
.map(
|
||||
(e) => PopupMenuItem<bool>(
|
||||
value: e,
|
||||
enabled: e != ascending,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
e ? Icons.text_rotate_up : Icons.text_rotation_down,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Text(e ? 'Aufsteigend' : 'Absteigend'),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onSelected: onDirectionChanged,
|
||||
),
|
||||
PopupMenuButton<SortOption>(
|
||||
icon: const Icon(Icons.sort),
|
||||
itemBuilder: (context) => SortOptions.options.keys
|
||||
.map((key) => PopupMenuItem<SortOption>(
|
||||
value: key,
|
||||
enabled: key != currentSort,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(SortOptions.getOption(key).icon, color: theme.colorScheme.onSurface),
|
||||
const SizedBox(width: 15),
|
||||
Text(SortOptions.getOption(key).displayName),
|
||||
],
|
||||
),
|
||||
))
|
||||
.map(
|
||||
(key) => PopupMenuItem<SortOption>(
|
||||
value: key,
|
||||
enabled: key != currentSort,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
SortOptions.getOption(key).icon,
|
||||
color: theme.colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Text(SortOptions.getOption(key).displayName),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onSelected: onSortChanged,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user