mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 15:24:35 +01:00
SFTP support download. listDIr() support rollback.
This commit is contained in:
@@ -4,6 +4,8 @@ PODS:
|
|||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
- flutter_icmp_ping (0.0.1):
|
- flutter_icmp_ping (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- open_file (0.0.1):
|
||||||
|
- Flutter
|
||||||
- path_provider_ios (0.0.1):
|
- path_provider_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- r_upgrade (0.0.1):
|
- r_upgrade (0.0.1):
|
||||||
@@ -15,6 +17,7 @@ DEPENDENCIES:
|
|||||||
- countly_flutter (from `.symlinks/plugins/countly_flutter/ios`)
|
- countly_flutter (from `.symlinks/plugins/countly_flutter/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`)
|
- flutter_icmp_ping (from `.symlinks/plugins/flutter_icmp_ping/ios`)
|
||||||
|
- open_file (from `.symlinks/plugins/open_file/ios`)
|
||||||
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
|
||||||
- r_upgrade (from `.symlinks/plugins/r_upgrade/ios`)
|
- r_upgrade (from `.symlinks/plugins/r_upgrade/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
@@ -26,6 +29,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_icmp_ping:
|
flutter_icmp_ping:
|
||||||
:path: ".symlinks/plugins/flutter_icmp_ping/ios"
|
:path: ".symlinks/plugins/flutter_icmp_ping/ios"
|
||||||
|
open_file:
|
||||||
|
:path: ".symlinks/plugins/open_file/ios"
|
||||||
path_provider_ios:
|
path_provider_ios:
|
||||||
:path: ".symlinks/plugins/path_provider_ios/ios"
|
:path: ".symlinks/plugins/path_provider_ios/ios"
|
||||||
r_upgrade:
|
r_upgrade:
|
||||||
@@ -37,6 +42,7 @@ SPEC CHECKSUMS:
|
|||||||
countly_flutter: 38419412e193a1faa5babeb5d28a63fda260687d
|
countly_flutter: 38419412e193a1faa5babeb5d28a63fda260687d
|
||||||
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
|
||||||
flutter_icmp_ping: 07e508847df7fa9262d050bb0b203de074bbe517
|
flutter_icmp_ping: 07e508847df7fa9262d050bb0b203de074bbe517
|
||||||
|
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
|
||||||
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
|
||||||
r_upgrade: 44d715c61914cce3d01ea225abffe894fd51c114
|
r_upgrade: 44d715c61914cce3d01ea225abffe894fd51c114
|
||||||
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
|
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
|
||||||
|
|||||||
@@ -354,7 +354,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 101;
|
CURRENT_PROJECT_VERSION = 108;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -362,7 +362,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.101;
|
MARKETING_VERSION = 1.0.108;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -484,7 +484,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 101;
|
CURRENT_PROJECT_VERSION = 108;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -492,7 +492,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.101;
|
MARKETING_VERSION = 1.0.108;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
@@ -508,7 +508,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 101;
|
CURRENT_PROJECT_VERSION = 108;
|
||||||
DEVELOPMENT_TEAM = BA88US33G6;
|
DEVELOPMENT_TEAM = BA88US33G6;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
@@ -516,7 +516,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.101;
|
MARKETING_VERSION = 1.0.108;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class BuildData {
|
class BuildData {
|
||||||
static const String name = "ServerBox";
|
static const String name = "ServerBox";
|
||||||
static const int build = 107;
|
static const int build = 108;
|
||||||
static const String engine =
|
static const String engine =
|
||||||
"Flutter 2.10.3 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 7e9793dee1 (8 days ago) • 2022-03-02 11:23:12 -0600\nEngine • revision bd539267b4\nTools • Dart 2.16.1 • DevTools 2.9.2\n";
|
"Flutter 2.10.3 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision 7e9793dee1 (8 days ago) • 2022-03-02 11:23:12 -0600\nEngine • revision bd539267b4\nTools • Dart 2.16.1 • DevTools 2.9.2\n";
|
||||||
static const String buildAt = "2022-03-10 13:25:24.362670";
|
static const String buildAt = "2022-03-10 15:25:32.032568";
|
||||||
static const int modifications = 11;
|
static const int modifications = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ class PingPage extends StatefulWidget {
|
|||||||
class _PingPageState extends State<PingPage>
|
class _PingPageState extends State<PingPage>
|
||||||
with AutomaticKeepAliveClientMixin {
|
with AutomaticKeepAliveClientMixin {
|
||||||
late TextEditingController _textEditingController;
|
late TextEditingController _textEditingController;
|
||||||
String _result = '';
|
|
||||||
Ping? _ping;
|
Ping? _ping;
|
||||||
|
late MediaQueryData _media;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -33,6 +33,7 @@ class _PingPageState extends State<PingPage>
|
|||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
|
_media = MediaQuery.of(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -46,13 +47,12 @@ class _PingPageState extends State<PingPage>
|
|||||||
const SizedBox(height: 13),
|
const SizedBox(height: 13),
|
||||||
buildInput(context, _textEditingController, maxLines: 1),
|
buildInput(context, _textEditingController, maxLines: 1),
|
||||||
_buildControl(),
|
_buildControl(),
|
||||||
RoundRectCard(
|
RoundRectCard(ConstrainedBox(
|
||||||
SizedBox(
|
constraints: BoxConstraints(
|
||||||
width: double.infinity,
|
minWidth: double.infinity,
|
||||||
child: Padding(
|
minHeight: _media.size.height * 0.6,
|
||||||
padding: const EdgeInsets.all(7), child: Text(_result)),
|
|
||||||
),
|
),
|
||||||
),
|
)),
|
||||||
])),
|
])),
|
||||||
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
|
||||||
),
|
),
|
||||||
@@ -60,12 +60,10 @@ class _PingPageState extends State<PingPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void doPing() {
|
void doPing() {
|
||||||
_result = '';
|
|
||||||
_ping = Ping(_textEditingController.text.trim());
|
_ping = Ping(_textEditingController.text.trim());
|
||||||
_ping!.stream.listen((event) {
|
_ping!.stream.listen((event) {
|
||||||
final resp = event.response.toString();
|
final resp = event.response.toString();
|
||||||
if (resp == 'null') return;
|
if (resp == 'null') return;
|
||||||
_result += '$resp\n';
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dartssh2/dartssh2.dart';
|
import 'package:dartssh2/dartssh2.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:toolbox/core/utils.dart';
|
import 'package:toolbox/core/utils.dart';
|
||||||
import 'package:toolbox/data/model/server/server_connection_state.dart';
|
import 'package:toolbox/data/model/server/server_connection_state.dart';
|
||||||
import 'package:toolbox/data/model/server/server_private_info.dart';
|
import 'package:toolbox/data/model/server/server_private_info.dart';
|
||||||
@@ -7,6 +10,7 @@ import 'package:toolbox/data/model/sftp/absolute_path.dart';
|
|||||||
import 'package:toolbox/data/model/sftp/sftp_side_status.dart';
|
import 'package:toolbox/data/model/sftp/sftp_side_status.dart';
|
||||||
import 'package:toolbox/data/provider/server.dart';
|
import 'package:toolbox/data/provider/server.dart';
|
||||||
import 'package:toolbox/locator.dart';
|
import 'package:toolbox/locator.dart';
|
||||||
|
import 'package:toolbox/view/widget/center_loading.dart';
|
||||||
import 'package:toolbox/view/widget/fade_in.dart';
|
import 'package:toolbox/view/widget/fade_in.dart';
|
||||||
import 'package:toolbox/view/widget/two_line_text.dart';
|
import 'package:toolbox/view/widget/two_line_text.dart';
|
||||||
|
|
||||||
@@ -144,6 +148,11 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
title: const Text('Rename'),
|
title: const Text('Rename'),
|
||||||
onTap: () => rename(context, file),
|
onTap: () => rename(context, file),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.download),
|
||||||
|
title: const Text('Download'),
|
||||||
|
onTap: () => download(context, file),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
@@ -153,6 +162,42 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void download(BuildContext context, SftpName name) {
|
||||||
|
showRoundDialog(
|
||||||
|
context, 'Download', Text('Download ${name.filename} to local?'), [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('Cancel')),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
var result = '';
|
||||||
|
try {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
showRoundDialog(context, name.filename, centerSizedLoading, [],
|
||||||
|
barrierDismiss: false);
|
||||||
|
final path = await getApplicationDocumentsDirectory();
|
||||||
|
final localFile = File('${path.path}/${name.filename}');
|
||||||
|
final remotePath = _status.path!.path + '/' + name.filename;
|
||||||
|
final file = await _status.client?.open(remotePath);
|
||||||
|
localFile.writeAsBytes(await file!.readBytes());
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
} catch (e) {
|
||||||
|
result = e.toString();
|
||||||
|
} finally {
|
||||||
|
if (result.isEmpty) {
|
||||||
|
result = 'Donwloaded successfully.';
|
||||||
|
}
|
||||||
|
showRoundDialog(context, 'Result', Text(result), [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('OK'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('Download'))
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
void delete(BuildContext context, SftpName file) {
|
void delete(BuildContext context, SftpName file) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
@@ -274,15 +319,26 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
final sftpc = await client.sftp();
|
final sftpc = await client.sftp();
|
||||||
_status.client = sftpc;
|
_status.client = sftpc;
|
||||||
}
|
}
|
||||||
final fs =
|
try {
|
||||||
await _status.client!.listdir(path ?? (_status.path?.path ?? '/'));
|
final fs =
|
||||||
fs.sort((a, b) => a.filename.compareTo(b.filename));
|
await _status.client!.listdir(path ?? (_status.path?.path ?? '/'));
|
||||||
fs.removeAt(0);
|
fs.sort((a, b) => a.filename.compareTo(b.filename));
|
||||||
if (mounted) {
|
fs.removeAt(0);
|
||||||
setState(() {
|
if (mounted) {
|
||||||
_status.files = fs;
|
setState(() {
|
||||||
_status.isBusy = false;
|
_status.files = fs;
|
||||||
});
|
_status.isBusy = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await showRoundDialog(context, 'Error', Text(e.toString()), [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('OK'))
|
||||||
|
]);
|
||||||
|
if (_status.path!.undo()) {
|
||||||
|
await listDir();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
const centerLoading = Center(child: CircularProgressIndicator());
|
const centerLoading = Center(child: CircularProgressIndicator());
|
||||||
|
|
||||||
|
const centerSizedLoading = SizedBox(
|
||||||
|
width: 77,
|
||||||
|
height: 77,
|
||||||
|
child: Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|||||||
18
pubspec.lock
18
pubspec.lock
@@ -335,6 +335,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.11"
|
version: "0.12.11"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -349,6 +356,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
open_file:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: open_file
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -357,7 +371,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0"
|
version: "1.8.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
@@ -521,7 +535,7 @@ packages:
|
|||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.3"
|
version: "0.4.8"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ dependencies:
|
|||||||
dart_ping_ios: ^1.0.0
|
dart_ping_ios: ^1.0.0
|
||||||
dropdown_button2: ^1.1.1
|
dropdown_button2: ^1.1.1
|
||||||
flutter_advanced_drawer: ^1.3.0
|
flutter_advanced_drawer: ^1.3.0
|
||||||
|
open_file: ^3.2.1
|
||||||
|
path_provider: ^2.0.9
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|||||||
Reference in New Issue
Block a user