import 'dart:io'; import 'package:flutter/material.dart'; import 'package:loader_overlay/loader_overlay.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import 'package:provider/provider.dart'; import '../../../api/marianumcloud/webdav/queries/listFiles/cacheableFile.dart'; import '../../../api/marianumcloud/webdav/queries/listFiles/listFilesCache.dart'; import '../../../api/marianumcloud/webdav/queries/listFiles/listFilesResponse.dart'; import '../../../api/marianumcloud/webdav/webdavApi.dart'; import '../../../model/files/filesProps.dart'; import '../../../storage/base/settingsProvider.dart'; import '../../../widget/loadingSpinner.dart'; import '../../../widget/placeholderView.dart'; import '../../../widget/filePick.dart'; import 'fileElement.dart'; import 'filesUploadDialog.dart'; class Files extends StatefulWidget { final List path; const Files(this.path, {super.key}); @override State createState() => _FilesState(); } class BetterSortOption { String displayName; int Function(CacheableFile, CacheableFile) compare; IconData icon; BetterSortOption({required this.displayName, required this.icon, required this.compare}); } enum SortOption { name, date, size } class SortOptions { static Map options = { SortOption.name: BetterSortOption( displayName: 'Name', icon: Icons.sort_by_alpha_outlined, compare: (CacheableFile a, CacheableFile b) => a.name.compareTo(b.name) ), SortOption.date: BetterSortOption( displayName: 'Datum', icon: Icons.history_outlined, compare: (CacheableFile a, CacheableFile b) => a.modifiedAt!.compareTo(b.modifiedAt!) ), SortOption.size: BetterSortOption( displayName: 'Größe', icon: Icons.sd_card_outlined, compare: (CacheableFile a, CacheableFile b) { if(a.isDirectory || b.isDirectory) return a.isDirectory ? 1 : 0; if(a.size == null) return 0; if(b.size == null) return 1; return a.size!.compareTo(b.size!); } ) }; static BetterSortOption getOption(SortOption option) { return options[option]!; } } class _FilesState extends State { FilesProps props = FilesProps(); ListFilesResponse? data; late SettingsProvider settings = Provider.of(context, listen: false); SortOption currentSort = SortOption.name; bool currentSortDirection = true; @override void initState() { super.initState(); currentSort = settings.val().fileSettings.sortBy; currentSortDirection = settings.val().fileSettings.ascending; _query(); } void _query() { ListFilesCache( path: widget.path.isEmpty ? '/' : widget.path.join('/'), onUpdate: (ListFilesResponse d) { d.files.removeWhere((element) => element.name.isEmpty || element.name == widget.path.lastOrNull()); setState(() { data = d; }); } ); } void mediaUpload(List? paths) async { if(paths == null) return; pushScreen( context, withNavBar: false, screen: FilesUploadDialog(filePaths: paths, remotePath: widget.path.join('/'), onUploadFinished: (uploadedFilePaths) => _query()), ); return; } @override Widget build(BuildContext context) { var files = data?.sortBy( sortOption: currentSort, foldersToTop: Provider.of(context).val().fileSettings.sortFoldersToTop, reversed: currentSortDirection ) ?? List.empty(); return Scaffold( appBar: AppBar( title: Text(widget.path.isNotEmpty ? widget.path.last : 'Dateien'), actions: [ // IconButton( // icon: const Icon(Icons.search), // onPressed: () => { // // TODO implement search // }, // ), PopupMenuButton( icon: Icon(currentSortDirection ? Icons.text_rotate_up : Icons.text_rotation_down), itemBuilder: (context) => [true, false].map((e) => PopupMenuItem( value: e, enabled: e != currentSortDirection, child: Row( children: [ Icon(e ? Icons.text_rotate_up : Icons.text_rotation_down, color: Theme.of(context).colorScheme.onSurface), const SizedBox(width: 15), Text(e ? 'Aufsteigend' : 'Absteigend') ], ) )).toList(), onSelected: (e) { setState(() { currentSortDirection = e; settings.val(write: true).fileSettings.ascending = e; }); }, ), PopupMenuButton( icon: const Icon(Icons.sort), itemBuilder: (context) => SortOptions.options.keys.map((key) => PopupMenuItem( value: key, enabled: key != currentSort, child: Row( children: [ Icon(SortOptions.getOption(key).icon, color: Theme.of(context).colorScheme.onSurface), const SizedBox(width: 15), Text(SortOptions.getOption(key).displayName), ], ) )).toList(), onSelected: (e) { setState(() { currentSort = e; settings.val(write: true).fileSettings.sortBy = e; }); }, ), ], ), floatingActionButton: FloatingActionButton( heroTag: 'uploadFile', backgroundColor: Theme.of(context).primaryColor, onPressed: () { showDialog(context: context, builder: (context) => SimpleDialog( children: [ ListTile( leading: const Icon(Icons.create_new_folder_outlined), title: const Text('Ordner erstellen'), onTap: () { Navigator.of(context).pop(); showDialog(context: context, builder: (context) { var inputController = TextEditingController(); return AlertDialog( title: const Text('Neuer Ordner'), content: TextField( controller: inputController, decoration: const InputDecoration( labelText: 'Name', ), ), actions: [ TextButton(onPressed: () { Navigator.of(context).pop(); }, child: const Text('Abbrechen')), TextButton(onPressed: () { WebdavApi.webdav.then((webdav) { webdav.mkcol(PathUri.parse("${widget.path.join("/")}/${inputController.text}")).then((value) => _query()); }); Navigator.of(context).pop(); }, child: const Text('Ordner erstellen')), ], ); }); }, ), ListTile( leading: const Icon(Icons.upload_file), title: const Text('Aus Dateien hochladen'), onTap: () { FilePick.documentPick().then(mediaUpload); Navigator.of(context).pop(); }, ), Visibility( visible: !Platform.isIOS, child: ListTile( leading: const Icon(Icons.add_a_photo_outlined), title: const Text('Aus Gallerie hochladen'), onTap: () { FilePick.galleryPick().then((value) { if(value != null) mediaUpload([value.path]); }); Navigator.of(context).pop(); }, ), ), ], )); }, child: const Icon(Icons.add), ), body: data == null ? const LoadingSpinner() : data!.files.isEmpty ? const PlaceholderView(icon: Icons.folder_off_rounded, text: 'Der Ordner ist leer') : LoaderOverlay( child: RefreshIndicator( onRefresh: () { _query(); return Future.delayed(const Duration(seconds: 3)); }, child: ListView.builder( padding: EdgeInsets.zero, itemCount: files.length, itemBuilder: (context, index) { var file = files.toList()[index]; return FileElement(file, widget.path, _query); }, ), ) ) ); } }