From 0740c4b82d5f0b150bc9a5b04df725f0822a4e90 Mon Sep 17 00:00:00 2001 From: RafayAhmad7548 Date: Sun, 27 Jul 2025 09:56:46 +0500 Subject: [PATCH] basic file exploration and bugfixes --- lib/add_server_modal.dart | 6 ++-- lib/sftp_connection_list.dart | 19 +++++++++-- lib/sftp_explorer.dart | 62 +++++++++++++++++++++++++++++++++++ pubspec.lock | 40 ++++++++++++++++++++++ pubspec.yaml | 1 + 5 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 lib/sftp_explorer.dart diff --git a/lib/add_server_modal.dart b/lib/add_server_modal.dart index 5f26104..d2aa848 100644 --- a/lib/add_server_modal.dart +++ b/lib/add_server_modal.dart @@ -39,7 +39,10 @@ class _AddServerModalState extends State { _connection.isEncryptionEnabled = widget.initialState?.isEncryptionEnabled; _connection.isDefault = widget.initialState?.isDefault; _privateKeyFileController.text = widget.initialState?.privateKey ?? ''; + _connection.privateKey = widget.initialState?.privateKey; _passwordController.text = widget.initialState?.password ?? ''; + _fileSelected = true; + _isPrivateKeyValid = true; } } @@ -135,7 +138,6 @@ class _AddServerModalState extends State { } } catch (e) { - print('bonga'); setState(() { _fileSelected = true; _showPrivateKey = true; @@ -168,7 +170,7 @@ class _AddServerModalState extends State { if (_privateKeyFileController.text.isEmpty && _passwordController.text.isEmpty) { return 'At least provide one of these'; } - if (!_isPrivateKeyValid) { + if (_privateKeyFileController.text.isNotEmpty && !_isPrivateKeyValid) { return 'Invalid private key file'; } return null; diff --git a/lib/sftp_connection_list.dart b/lib/sftp_connection_list.dart index ab78e5b..c8b068d 100644 --- a/lib/sftp_connection_list.dart +++ b/lib/sftp_connection_list.dart @@ -1,9 +1,11 @@ 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'; class SftpConnectionList extends StatefulWidget { const SftpConnectionList({ @@ -75,8 +77,21 @@ class _SftpConnectionListState extends State { color: Theme.of(context).colorScheme.onSecondary, borderRadius: BorderRadius.circular(10), child: InkWell( - onTap: () { - // TODO: connect to connection here + onTap: () async { + final conn = _connections[index]; + final client = SSHClient( + await SSHSocket.connect(conn.host!, conn.port!), + username: conn.username!, + onPasswordRequest: () => conn.password, + identities: [ + if (conn.privateKey != null) + ...SSHKeyPair.fromPem(conn.privateKey!) + ] + ); + final sftpClient = await client.sftp(); + if (context.mounted) { + Navigator.push(context, MaterialPageRoute(builder: (context) => SftpExplorer(sftpClient: sftpClient,))); + } }, borderRadius: BorderRadius.circular(10), child: Padding( diff --git a/lib/sftp_explorer.dart b/lib/sftp_explorer.dart new file mode 100644 index 0000000..8560c6a --- /dev/null +++ b/lib/sftp_explorer.dart @@ -0,0 +1,62 @@ +import 'package:dartssh2/dartssh2.dart'; +import 'package:flutter/material.dart'; + +class SftpExplorer extends StatefulWidget { + const SftpExplorer({super.key, required this.sftpClient, this.path = '/'}); + + final SftpClient sftpClient; + final String path; + + @override + State createState() => _SftpExplorerState(); +} + +class _SftpExplorerState extends State { + + bool _isLoading = true; + late List _dirContents; + + + @override + void initState() { + super.initState(); + _listDir(); + } + + void _listDir() async { + _dirContents = await widget.sftpClient.listdir(widget.path); + setState(() { + _isLoading = false; + }); + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Explorer'), + ), + 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), + onTap: () { + if (dirEntry.attr.isDirectory) { + Navigator.push(context, MaterialPageRoute( + builder: (context) => SftpExplorer( + sftpClient: widget.sftpClient, + path: '${widget.path}${dirEntry.filename}/', + ) + )); + } + }, + ); + }, + ) + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index e7b2f4d..3a123a5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + asn1lib: + dependency: transitive + description: + name: asn1lib + sha256: "9a8f69025044eb466b9b60ef3bc3ac99b4dc6c158ae9c56d25eeccf5bc56d024" + url: "https://pub.dev" + source: hosted + version: "1.6.5" async: dependency: transitive description: @@ -41,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" cross_file: dependency: transitive description: @@ -49,6 +65,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.4+2" + dartssh2: + dependency: "direct main" + description: + name: dartssh2 + sha256: bb242396c1d90f05c261b5eb8338cc67167e803c0948b0207029339cc568a66c + url: "https://pub.dev" + source: hosted + version: "2.13.0" fake_async: dependency: transitive description: @@ -336,6 +360,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pinenacl: + dependency: transitive + description: + name: pinenacl + sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf" + url: "https://pub.dev" + source: hosted + version: "0.6.0" platform: dependency: transitive description: @@ -352,6 +384,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" + url: "https://pub.dev" + source: hosted + version: "3.9.1" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 853979e..f976e12 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: sdk: flutter file_selector: ^1.0.3 flutter_secure_storage: ^9.2.4 + dartssh2: ^2.13.0 dev_dependencies: flutter_test: