diff --git a/lib/sftp_explorer.dart b/lib/sftp_explorer.dart index 441958f..7d8504d 100644 --- a/lib/sftp_explorer.dart +++ b/lib/sftp_explorer.dart @@ -7,10 +7,9 @@ import 'package:flutter/material.dart'; import 'package:fluxcloud/sftp_worker.dart'; class SftpExplorer extends StatefulWidget { - const SftpExplorer({super.key, required this.sftpWorker, this.path = '/'}); + const SftpExplorer({super.key, required this.sftpWorker}); final SftpWorker sftpWorker; - final String path; @override State createState() => _SftpExplorerState(); @@ -18,6 +17,8 @@ class SftpExplorer extends StatefulWidget { class _SftpExplorerState extends State { + String path = '/'; + bool _isLoading = true; late List _dirContents; @@ -32,7 +33,7 @@ class _SftpExplorerState extends State { Future _listDir() async { setState(() => _isLoading = true); try { - _dirContents = await widget.sftpWorker.listdir(widget.path); + _dirContents = await widget.sftpWorker.listdir(path); } catch (e) { if (mounted) { @@ -46,12 +47,25 @@ class _SftpExplorerState extends State { @override Widget build(BuildContext context) { return Scaffold( - // TODO: make appbar same for all directories appBar: AppBar( toolbarHeight: 75, title: Text('Explorer'), elevation: 2, actionsPadding: EdgeInsets.only(right: 20), + leading: IconButton( + onPressed: () { + if (path == '/') { + // TODO: figure this out + // Navigator.pop(context); + } + else { + path = path.substring(0, path.length - 1); + path = path.substring(0, path.lastIndexOf('/')+1); + _listDir(); + } + }, + icon: Icon(Icons.arrow_back) + ), actions: [ if (_progress != null) Stack( @@ -64,7 +78,7 @@ class _SftpExplorerState extends State { ), IconButton( onPressed: () { - + }, icon: Icon(Icons.upload) ), @@ -73,127 +87,143 @@ class _SftpExplorerState extends State { ], ), floatingActionButton: _buildFABs(context), - body: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder( - itemCount: _dirContents.length, - itemBuilder: (context, index) { - final dirEntry = _dirContents[index]; - return ListTile( - leading: Icon(dirEntry.attr.isDirectory ? Icons.folder : Icons.description), - title: Text(dirEntry.filename), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - onPressed: () { - - }, - icon: Icon(Icons.drive_file_move) - ), - IconButton( - onPressed: () { - - }, - icon: Icon(Icons.copy) - ), - IconButton( - onPressed: () { - final newNameController = TextEditingController(text: dirEntry.filename); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Rename'), - content: TextField( - controller: newNameController, - autofocus: true, - decoration: InputDecoration( - labelText: 'Enter new name' - ), - ), - actions: [ - TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancel')), - TextButton( - onPressed: () async { - // try { - // await widget.sftpWorker.rename('${widget.path}${dirEntry.filename}', '${widget.path}${newNameController.text}'); - // _listDir(); - // } - // on SftpStatusError catch (e) { - // if (context.mounted) { - // ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, e.message)); - // } - // } - // if (context.mounted) { - // Navigator.pop(context); - // } - // - }, - child: Text('Rename') - ), - - ], - ) - ); - }, - icon: Icon(Icons.drive_file_rename_outline) - ), - IconButton( - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Delete Permanently?'), - content: Text(dirEntry.attr.isDirectory ? 'The contents of this folder will be deleted as well\nThis action cannot be undone' : 'This action cannot be undone'), - actions: [ - TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancel')), - TextButton( - onPressed: () async { - // if (dirEntry.attr.isDirectory) { - // Future removeRecursively (String path) async { - // final dirContents = await widget.sftpWorker.listdir(path); - // for (SftpName entry in dirContents) { - // final fullPath = '$path${entry.filename}'; - // if (entry.attr.isDirectory) { - // await removeRecursively('$fullPath/'); - // await widget.sftpWorker.rmdir('$fullPath/'); - // } - // else { - // await widget.sftpWorker.remove(fullPath); - // } - // } - // await widget.sftpWorker.rmdir(path); - // } - // await removeRecursively('${widget.path}${dirEntry.filename}/'); - // } - // else { - // await widget.sftpWorker.remove('${widget.path}${dirEntry.filename}'); - // } - // _listDir(); - // if (context.mounted) { - // Navigator.pop(context); - // } - }, - child: Text('Yes') - ), - ], - ) - ); - }, - icon: Icon(Icons.delete) - ), - ], - ), - onTap: () { - if (dirEntry.attr.isDirectory) { - Navigator.push(context, MaterialPageRoute( - builder: (context) => SftpExplorer( - sftpWorker: widget.sftpWorker, - path: '${widget.path}${dirEntry.filename}/', - ) - )); - } - }, + body: AnimatedSwitcher( + duration: Duration(milliseconds: 300), + transitionBuilder: (child, animation) { + final curved = CurvedAnimation( + parent: animation, + curve: Curves.fastOutSlowIn ); - }, + return FadeTransition( + opacity: curved, + child: ScaleTransition( + scale: Tween( + begin: 0.92, + end: 1 + ).animate(curved), + child: child, + ), + ); + }, + child: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder( + key: ValueKey(path), + itemCount: _dirContents.length, + itemBuilder: (context, index) { + final dirEntry = _dirContents[index]; + return ListTile( + leading: Icon(dirEntry.attr.isDirectory ? Icons.folder : Icons.description), + title: Text(dirEntry.filename), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + onPressed: () { + + }, + icon: Icon(Icons.drive_file_move) + ), + IconButton( + onPressed: () { + + }, + icon: Icon(Icons.copy) + ), + IconButton( + onPressed: () { + final newNameController = TextEditingController(text: dirEntry.filename); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Rename'), + content: TextField( + controller: newNameController, + autofocus: true, + decoration: InputDecoration( + labelText: 'Enter new name' + ), + ), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancel')), + TextButton( + onPressed: () async { + // try { + // await widget.sftpWorker.rename('${path}${dirEntry.filename}', '${widget.path}${newNameController.text}'); + // _listDir(); + // } + // on SftpStatusError catch (e) { + // if (context.mounted) { + // ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, e.message)); + // } + // } + // if (context.mounted) { + // Navigator.pop(context); + // } + // + }, + child: Text('Rename') + ), + + ], + ) + ); + }, + icon: Icon(Icons.drive_file_rename_outline) + ), + IconButton( + onPressed: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text('Delete Permanently?'), + content: Text(dirEntry.attr.isDirectory ? 'The contents of this folder will be deleted as well\nThis action cannot be undone' : 'This action cannot be undone'), + actions: [ + TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancel')), + TextButton( + onPressed: () async { + // if (dirEntry.attr.isDirectory) { + // Future removeRecursively (String path) async { + // final dirContents = await widget.sftpWorker.listdir(path); + // for (SftpName entry in dirContents) { + // final fullPath = '$path${entry.filename}'; + // if (entry.attr.isDirectory) { + // await removeRecursively('$fullPath/'); + // await widget.sftpWorker.rmdir('$fullPath/'); + // } + // else { + // await widget.sftpWorker.remove(fullPath); + // } + // } + // await widget.sftpWorker.rmdir(path); + // } + // await removeRecursively('${path}${dirEntry.filename}/'); + // } + // else { + // await widget.sftpWorker.remove('${path}${dirEntry.filename}'); + // } + // _listDir(); + // if (context.mounted) { + // Navigator.pop(context); + // } + }, + child: Text('Yes') + ), + ], + ) + ); + }, + icon: Icon(Icons.delete) + ), + ], + ), + onTap: () { + if (dirEntry.attr.isDirectory) { + path = '$path${dirEntry.filename}/'; + _listDir(); + } + }, + ); + }, + ) ) ); } @@ -222,7 +252,7 @@ class _SftpExplorerState extends State { TextButton( onPressed: () async { try { - await widget.sftpWorker.mkdir('${widget.path}${nameController.text}'); + await widget.sftpWorker.mkdir('${path}${nameController.text}'); _listDir(); } catch (e) { @@ -255,7 +285,7 @@ class _SftpExplorerState extends State { filePaths = files.map((file) => file.path).toList(); } try { - await for (final progress in widget.sftpWorker.uploadFiles(widget.path, filePaths)) { + await for (final progress in widget.sftpWorker.uploadFiles(path, filePaths)) { setState(() => _progress = progress); } }