optimization: desktop UI (#747)
This commit is contained in:
@@ -9,9 +9,10 @@ import 'package:server_box/data/provider/server.dart';
|
||||
import 'package:server_box/data/provider/sftp.dart';
|
||||
import 'package:server_box/data/res/misc.dart';
|
||||
|
||||
import 'package:server_box/core/route.dart';
|
||||
import 'package:server_box/data/model/app/path_with_prefix.dart';
|
||||
import 'package:server_box/view/page/editor.dart';
|
||||
import 'package:server_box/view/page/storage/sftp.dart';
|
||||
import 'package:server_box/view/page/storage/sftp_mission.dart';
|
||||
|
||||
final class LocalFilePageArgs {
|
||||
final bool? isPickFile;
|
||||
@@ -29,15 +30,14 @@ class LocalFilePage extends StatefulWidget {
|
||||
|
||||
static const route = AppRoute<String, LocalFilePageArgs>(
|
||||
page: LocalFilePage.new,
|
||||
path: '/local_file',
|
||||
path: '/files/local',
|
||||
);
|
||||
|
||||
@override
|
||||
State<LocalFilePage> createState() => _LocalFilePageState();
|
||||
}
|
||||
|
||||
class _LocalFilePageState extends State<LocalFilePage>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
class _LocalFilePageState extends State<LocalFilePage> with AutomaticKeepAliveClientMixin {
|
||||
late final _path = LocalPath(widget.args?.initDir ?? Paths.file);
|
||||
final _sortType = _SortType.name.vn;
|
||||
bool get isPickFile => widget.args?.isPickFile ?? false;
|
||||
@@ -125,13 +125,9 @@ class _LocalFilePageState extends State<LocalFilePage>
|
||||
|
||||
return CardX(
|
||||
child: ListTile(
|
||||
leading: isDir
|
||||
? const Icon(Icons.folder_open)
|
||||
: const Icon(Icons.insert_drive_file),
|
||||
leading: isDir ? const Icon(Icons.folder_open) : const Icon(Icons.insert_drive_file),
|
||||
title: Text(fileName),
|
||||
subtitle: isDir
|
||||
? null
|
||||
: Text(stat.size.bytes2Str, style: UIs.textGrey),
|
||||
subtitle: isDir ? null : Text(stat.size.bytes2Str, style: UIs.textGrey),
|
||||
trailing: Text(
|
||||
stat.modified.ymdhms(),
|
||||
style: UIs.textGrey,
|
||||
@@ -262,10 +258,11 @@ class _LocalFilePageState extends State<LocalFilePage>
|
||||
);
|
||||
if (spi == null) return;
|
||||
|
||||
final remotePath = await AppRoutes.sftp(
|
||||
final args = SftpPageArgs(
|
||||
spi: spi,
|
||||
isSelect: true,
|
||||
).go<String>(context);
|
||||
);
|
||||
final remotePath = await SftpPage.route.go(context, args);
|
||||
if (remotePath == null) {
|
||||
return;
|
||||
}
|
||||
@@ -346,7 +343,7 @@ class _LocalFilePageState extends State<LocalFilePage>
|
||||
Widget _buildMissionBtn() {
|
||||
return IconButton(
|
||||
icon: const Icon(Icons.downloading),
|
||||
onPressed: () => AppRoutes.sftpMission().go(context),
|
||||
onPressed: () => SftpMissionPage.route.go(context),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -383,8 +380,7 @@ enum _SortType {
|
||||
files.sort((a, b) => a.statSync().size.compareTo(b.statSync().size));
|
||||
break;
|
||||
case _SortType.time:
|
||||
files.sort(
|
||||
(a, b) => a.statSync().modified.compareTo(b.statSync().modified));
|
||||
files.sort((a, b) => a.statSync().modified.compareTo(b.statSync().modified));
|
||||
break;
|
||||
}
|
||||
return files;
|
||||
|
||||
@@ -6,7 +6,6 @@ import 'package:fl_lib/fl_lib.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:server_box/core/extension/context/locale.dart';
|
||||
import 'package:server_box/core/extension/sftpfile.dart';
|
||||
import 'package:server_box/core/route.dart';
|
||||
import 'package:server_box/core/utils/comparator.dart';
|
||||
import 'package:server_box/data/model/server/server_private_info.dart';
|
||||
import 'package:server_box/data/model/sftp/browser_status.dart';
|
||||
@@ -15,32 +14,48 @@ import 'package:server_box/data/provider/sftp.dart';
|
||||
import 'package:server_box/data/res/misc.dart';
|
||||
import 'package:server_box/data/res/store.dart';
|
||||
import 'package:server_box/view/page/editor.dart';
|
||||
import 'package:server_box/view/page/ssh/page.dart';
|
||||
import 'package:server_box/view/page/storage/local.dart';
|
||||
import 'package:server_box/view/page/storage/sftp_mission.dart';
|
||||
import 'package:server_box/view/widget/omit_start_text.dart';
|
||||
import 'package:server_box/view/widget/two_line_text.dart';
|
||||
import 'package:server_box/view/widget/unix_perm.dart';
|
||||
|
||||
import 'package:icons_plus/icons_plus.dart';
|
||||
|
||||
class SftpPage extends StatefulWidget {
|
||||
|
||||
final class SftpPageArgs {
|
||||
final Spi spi;
|
||||
final String? initPath;
|
||||
final bool isSelect;
|
||||
final String? initPath;
|
||||
|
||||
const SftpPageArgs({
|
||||
required this.spi,
|
||||
this.isSelect = false,
|
||||
this.initPath,
|
||||
});
|
||||
}
|
||||
|
||||
class SftpPage extends StatefulWidget {
|
||||
final SftpPageArgs args;
|
||||
|
||||
const SftpPage({
|
||||
super.key,
|
||||
required this.spi,
|
||||
required this.isSelect,
|
||||
this.initPath,
|
||||
required this.args,
|
||||
});
|
||||
|
||||
@override
|
||||
State<SftpPage> createState() => _SftpPageState();
|
||||
|
||||
static const route = AppRouteArg<String, SftpPageArgs>(
|
||||
page: SftpPage.new,
|
||||
path: '/sftp',
|
||||
);
|
||||
}
|
||||
|
||||
class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||
late final _status = SftpBrowserStatus(_client);
|
||||
late final _client = widget.spi.server!.value.client!;
|
||||
late final _client = widget.args.spi.server!.value.client!;
|
||||
final _sortOption = _SortOption().vn;
|
||||
|
||||
@override
|
||||
@@ -54,7 +69,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||
final children = [
|
||||
Btn.icon(
|
||||
icon: const Icon(Icons.downloading),
|
||||
onTap: () => AppRoutes.sftpMission().go(context),
|
||||
onTap: () => SftpMissionPage.route.go(context),
|
||||
),
|
||||
_buildSortMenu(),
|
||||
_buildSearchBtn(),
|
||||
@@ -63,7 +78,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||
|
||||
return Scaffold(
|
||||
appBar: CustomAppBar(
|
||||
title: TwoLineText(up: 'SFTP', down: widget.spi.name),
|
||||
title: TwoLineText(up: 'SFTP', down: widget.args.spi.name),
|
||||
actions: children,
|
||||
),
|
||||
body: _buildFileView(),
|
||||
@@ -75,13 +90,13 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||
FutureOr<void> afterFirstLayout(BuildContext context) {
|
||||
var initPath = '/';
|
||||
if (Stores.setting.sftpOpenLastPath.fetch()) {
|
||||
final history = Stores.history.sftpLastPath.fetch(widget.spi.id);
|
||||
final history = Stores.history.sftpLastPath.fetch(widget.args.spi.id);
|
||||
if (history != null) {
|
||||
initPath = history;
|
||||
}
|
||||
}
|
||||
|
||||
_status.path.path = widget.initPath ?? initPath;
|
||||
_status.path.path = widget.args.initPath ?? initPath;
|
||||
_listDir();
|
||||
}
|
||||
}
|
||||
@@ -93,9 +108,7 @@ extension _UI on _SftpPageState {
|
||||
(_SortType.size, l10n.size),
|
||||
(_SortType.time, l10n.time),
|
||||
];
|
||||
return ValBuilder(
|
||||
listenable: _sortOption,
|
||||
builder: (value) {
|
||||
return _sortOption.listenVal((value) {
|
||||
return PopupMenuButton<_SortType>(
|
||||
icon: const Icon(Icons.sort),
|
||||
itemBuilder: (context) {
|
||||
@@ -130,7 +143,7 @@ extension _UI on _SftpPageState {
|
||||
}
|
||||
|
||||
Widget _buildBottom() {
|
||||
final children = widget.isSelect
|
||||
final children = widget.args.isSelect
|
||||
? [
|
||||
IconButton(
|
||||
onPressed: () => context.pop(_status.path.path),
|
||||
@@ -168,7 +181,7 @@ extension _UI on _SftpPageState {
|
||||
return RefreshIndicator(
|
||||
onRefresh: _listDir,
|
||||
child: FadeIn(
|
||||
key: Key(widget.spi.name + _status.path.path),
|
||||
key: Key(widget.args.spi.name + _status.path.path),
|
||||
child: ValBuilder(
|
||||
listenable: _sortOption,
|
||||
builder: (sortOption) {
|
||||
@@ -305,7 +318,8 @@ extension _Actions on _SftpPageState {
|
||||
if (editor.isNotEmpty) {
|
||||
// Use single quote to avoid escape
|
||||
final cmd = "$editor '${_getRemotePath(name)}'";
|
||||
await AppRoutes.ssh(spi: widget.spi, initCmd: cmd).go(context);
|
||||
final args = SshPageArgs(spi: widget.args.spi, initCmd: cmd);
|
||||
await SSHPage.route.go(context, args);
|
||||
await _listDir();
|
||||
return;
|
||||
}
|
||||
@@ -324,7 +338,7 @@ extension _Actions on _SftpPageState {
|
||||
final localPath = _getLocalPath(remotePath);
|
||||
final completer = Completer();
|
||||
final req = SftpReq(
|
||||
widget.spi,
|
||||
widget.args.spi,
|
||||
remotePath,
|
||||
localPath,
|
||||
SftpReqType.download,
|
||||
@@ -368,7 +382,7 @@ extension _Actions on _SftpPageState {
|
||||
|
||||
SftpProvider.add(
|
||||
SftpReq(
|
||||
widget.spi,
|
||||
widget.args.spi,
|
||||
remotePath,
|
||||
_getLocalPath(remotePath),
|
||||
SftpReqType.download,
|
||||
@@ -604,7 +618,8 @@ extension _Actions on _SftpPageState {
|
||||
);
|
||||
if (confirm != true) return;
|
||||
|
||||
await AppRoutes.ssh(spi: widget.spi, initCmd: cmd).go(context);
|
||||
final args = SshPageArgs(spi: widget.args.spi, initCmd: cmd);
|
||||
await SSHPage.route.go(context, args);
|
||||
_listDir();
|
||||
}
|
||||
|
||||
@@ -616,7 +631,7 @@ extension _Actions on _SftpPageState {
|
||||
|
||||
/// Local file dir + server id + remote path
|
||||
String _getLocalPath(String remotePath) {
|
||||
return Paths.file.joinPath(widget.spi.id).joinPath(remotePath);
|
||||
return Paths.file.joinPath(widget.args.spi.id).joinPath(remotePath);
|
||||
}
|
||||
|
||||
/// Only return true if the path is changed
|
||||
@@ -653,7 +668,7 @@ extension _Actions on _SftpPageState {
|
||||
|
||||
// Only update history when success
|
||||
if (Stores.setting.sftpOpenLastPath.fetch()) {
|
||||
Stores.history.sftpLastPath.put(widget.spi.id, listPath);
|
||||
Stores.history.sftpLastPath.put(widget.args.spi.id, listPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -735,7 +750,7 @@ extension _Actions on _SftpPageState {
|
||||
final remotePath = '$remoteDir/$fileName';
|
||||
Loggers.app.info('SFTP upload local: $path, remote: $remotePath');
|
||||
SftpProvider.add(
|
||||
SftpReq(widget.spi, remotePath, path, SftpReqType.upload),
|
||||
SftpReq(widget.args.spi, remotePath, path, SftpReqType.upload),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.upload_file),
|
||||
@@ -817,7 +832,7 @@ extension _Actions on _SftpPageState {
|
||||
Widget _buildHomeBtn() {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
final user = widget.spi.user;
|
||||
final user = widget.args.spi.user;
|
||||
_status.path.path = user != 'root' ? '/home/$user' : '/root';
|
||||
_listDir();
|
||||
},
|
||||
|
||||
@@ -10,6 +10,11 @@ class SftpMissionPage extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<SftpMissionPage> createState() => _SftpMissionPageState();
|
||||
|
||||
static const route = AppRouteNoArg(
|
||||
page: SftpMissionPage.new,
|
||||
path: '/sftp/mission',
|
||||
);
|
||||
}
|
||||
|
||||
class _SftpMissionPageState extends State<SftpMissionPage> {
|
||||
|
||||
Reference in New Issue
Block a user