diff --git a/lib/widgets/add_server_modal.dart b/lib/add_server_modal.dart similarity index 100% rename from lib/widgets/add_server_modal.dart rename to lib/add_server_modal.dart diff --git a/lib/sftp_connection_list.dart b/lib/sftp_connection_list.dart index 0116fa4..c8b068d 100644 --- a/lib/sftp_connection_list.dart +++ b/lib/sftp_connection_list.dart @@ -3,9 +3,9 @@ import 'dart:convert'; import 'package:dartssh2/dartssh2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:fluxcloud/add_server_modal.dart'; import 'package:fluxcloud/connection.dart'; import 'package:fluxcloud/sftp_explorer.dart'; -import 'package:fluxcloud/widgets/add_server_modal.dart'; class SftpConnectionList extends StatefulWidget { const SftpConnectionList({ diff --git a/lib/sftp_explorer.dart b/lib/sftp_explorer.dart index daaa1a3..8560c6a 100644 --- a/lib/sftp_explorer.dart +++ b/lib/sftp_explorer.dart @@ -1,5 +1,4 @@ import 'package:dartssh2/dartssh2.dart'; -import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; class SftpExplorer extends StatefulWidget { @@ -16,10 +15,7 @@ class _SftpExplorerState extends State { bool _isLoading = true; late List _dirContents; - - SftpFileWriter? _loader; - String _loadingFileName = ''; - double _progress = 0; + @override void initState() { @@ -27,10 +23,11 @@ class _SftpExplorerState extends State { _listDir(); } - Future _listDir() async { - setState(() => _isLoading = true); + void _listDir() async { _dirContents = await widget.sftpClient.listdir(widget.path); - setState(() => _isLoading = false); + setState(() { + _isLoading = false; + }); } @@ -40,8 +37,6 @@ class _SftpExplorerState extends State { appBar: AppBar( title: Text('Explorer'), ), - bottomNavigationBar: _buildLoadingWidget(context), - floatingActionButton: _buildFABs(context), body: _isLoading ? Center(child: CircularProgressIndicator()) : ListView.builder( itemCount: _dirContents.length, itemBuilder: (context, index) { @@ -49,71 +44,6 @@ class _SftpExplorerState extends State { 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: () {}, - 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.sftpClient.listdir(path); - for (SftpName entry in dirContents) { - final fullPath = '$path${entry.filename}'; - if (entry.attr.isDirectory) { - await removeRecursively('$fullPath/'); - await widget.sftpClient.rmdir('$fullPath/'); - } - else { - await widget.sftpClient.remove(fullPath); - } - } - await widget.sftpClient.rmdir(path); - } - await removeRecursively('${widget.path}${dirEntry.filename}/'); - } - else { - await widget.sftpClient.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( @@ -129,135 +59,4 @@ class _SftpExplorerState extends State { ) ); } - - Widget _buildFABs(BuildContext context) { - return Row( - mainAxisSize: MainAxisSize.min, - spacing: 10, - children: [ - FloatingActionButton( - heroTag: 'create-new-folder', - onPressed: () { - final nameController = TextEditingController(); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: Text('Create new folder'), - content: TextField( - controller: nameController, - decoration: InputDecoration( - labelText: 'Enter folder name' - ), - ), - actions: [ - TextButton(onPressed: () => Navigator.pop(context), child: Text('Cancel')), - TextButton( - onPressed: () async { - try { - await widget.sftpClient.mkdir('${widget.path}${nameController.text}'); - _listDir(); - } - on SftpStatusError catch (e) { - if (context.mounted) { - if (e.code == 4) { - ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, 'Folder Already Exists')); - } - else { - ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, 'Error: ${e.message}')); - } - } - } - if (context.mounted) { - Navigator.pop(context); - } - }, - child: Text('Ok') - ), - ], - ) - ); - }, - child: Icon(Icons.create_new_folder), - ), - FloatingActionButton( - heroTag: 'upload-file', - onPressed: () async { - final List files = await openFiles(); - for (XFile file in files) { - try { - final remoteFile = await widget.sftpClient.open('${widget.path}${file.name}', mode: SftpFileOpenMode.create | SftpFileOpenMode.write | SftpFileOpenMode.exclusive); - final fileSize = await file.length(); - final uploader = remoteFile.write( - file.openRead().cast(), - onProgress: (progress) => setState(() => _progress = progress/fileSize) - ); - setState(() { - _loader = uploader; - _loadingFileName = file.name; - }); - await uploader.done; - setState(() => _loader = null); - _listDir(); - } - on SftpStatusError catch (e) { - if (context.mounted) { - if (e.code == 4) { - ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, 'File Already Exists')); - } - else { - ScaffoldMessenger.of(context).showSnackBar(_buildErrorSnackBar(context, 'Error: ${e.message}')); - } - } - } - } - }, - child: Icon(Icons.upload), - ), - ], - ); - } - - SnackBar _buildErrorSnackBar(BuildContext context, String error) { - return SnackBar( - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, - behavior: SnackBarBehavior.floating, - content: Row( - spacing: 10, - children: [ - Icon(Icons.error, color: Colors.red,), - Text(error, style: TextStyle(color: Theme.of(context).colorScheme.onSecondaryContainer),), - ], - ) - ); - } - - Widget _buildLoadingWidget(BuildContext context) { - return _loader != null ? Container( - color: Theme.of(context).colorScheme.secondaryContainer, - child: Padding( - padding: const EdgeInsets.all(10), - child: Column( - spacing: 10, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - spacing: 10, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Uploading file: $_loadingFileName', style: TextStyle(fontSize: 16),), - TextButton( - onPressed: () { - _loader!.abort(); - widget.sftpClient.remove('${widget.path}$_loadingFileName'); - }, - child: Text('Cancel') - ), - ], - ), - LinearProgressIndicator(value: _progress,) - ], - ), - ), - ) : SizedBox(); - } } diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index 4903bee..3741b8b 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -27,7 +27,7 @@ static void my_application_activate(GApplication* application) { // in case the window manager does more exotic layout, e.g. tiling. // If running on Wayland assume the header bar will work (may need changing // if future cases occur). - gboolean use_header_bar = FALSE; + gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) {