mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
fmt
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
final _dockerImageReg = RegExp(r'(\S+) +(\S+) +(\S+) +(.+) +(\S+)');
|
final _dockerImageReg = RegExp(r'(\S+) +(\S+) +(\S+) +(.+) +(\S+)');
|
||||||
|
|
||||||
class DockerImage {
|
class DockerImage {
|
||||||
final String repo;
|
final String repo;
|
||||||
final String tag;
|
final String tag;
|
||||||
@@ -44,4 +45,3 @@ class DockerImage {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class DockerProvider extends BusyProvider {
|
|||||||
final verRaw = await client!.run('docker version'.withLangExport).string;
|
final verRaw = await client!.run('docker version'.withLangExport).string;
|
||||||
if (verRaw.contains(_dockerNotFound)) {
|
if (verRaw.contains(_dockerNotFound)) {
|
||||||
error = DockerErr(type: DockerErrType.notInstalled);
|
error = DockerErr(type: DockerErrType.notInstalled);
|
||||||
notifyListeners();
|
setBusyState(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +65,7 @@ class DockerProvider extends BusyProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setBusyState();
|
||||||
final cmd = _wrap(_dockerPS);
|
final cmd = _wrap(_dockerPS);
|
||||||
|
|
||||||
// run docker ps
|
// run docker ps
|
||||||
@@ -97,7 +98,7 @@ class DockerProvider extends BusyProvider {
|
|||||||
error = DockerErr(type: DockerErrType.unknown, message: e.toString());
|
error = DockerErr(type: DockerErrType.unknown, message: e.toString());
|
||||||
rethrow;
|
rethrow;
|
||||||
} finally {
|
} finally {
|
||||||
notifyListeners();
|
setBusyState(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +146,8 @@ class DockerProvider extends BusyProvider {
|
|||||||
|
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
setBusyState(false);
|
setBusyState(false);
|
||||||
return DockerErr(type: DockerErrType.unknown, message: errs.join('\n').trim());
|
return DockerErr(
|
||||||
|
type: DockerErrType.unknown, message: errs.join('\n').trim());
|
||||||
}
|
}
|
||||||
await refresh();
|
await refresh();
|
||||||
setBusyState(false);
|
setBusyState(false);
|
||||||
|
|||||||
@@ -61,21 +61,26 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
_aptProvider.init(
|
_aptProvider.init(
|
||||||
si.client!,
|
si.client!,
|
||||||
si.status.sysVer.dist,
|
si.status.sysVer.dist,
|
||||||
() =>
|
() => scrollController.jumpTo(scrollController.position.maxScrollExtent),
|
||||||
scrollController.jumpTo(scrollController.position.maxScrollExtent),
|
|
||||||
() => scrollControllerUpdate
|
() => scrollControllerUpdate
|
||||||
.jumpTo(scrollController.position.maxScrollExtent),
|
.jumpTo(scrollController.position.maxScrollExtent),
|
||||||
onPwdRequest,
|
onPwdRequest,
|
||||||
widget.spi.user);
|
widget.spi.user,
|
||||||
|
);
|
||||||
_aptProvider.refreshInstalled();
|
_aptProvider.refreshInstalled();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSubmitted() {
|
void onSubmitted() {
|
||||||
if (textController.text == '') {
|
if (textController.text == '') {
|
||||||
showRoundDialog(context, s.attention, Text(s.fieldMustNotEmpty), [
|
showRoundDialog(
|
||||||
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.fieldMustNotEmpty),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok)),
|
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok)),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@@ -108,7 +113,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
s.ok,
|
s.ok,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
)),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
return textController.text.trim();
|
return textController.text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +148,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
child: Text(
|
child: Text(
|
||||||
apt.error!,
|
apt.error!,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -154,9 +161,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
}
|
}
|
||||||
if (apt.updateLog != null && apt.upgradeable == null) {
|
if (apt.updateLog != null && apt.upgradeable == null) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: _media.size.height -
|
height:
|
||||||
_media.padding.top -
|
_media.size.height - _media.padding.top - _media.padding.bottom,
|
||||||
_media.padding.bottom,
|
|
||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints.expand(),
|
constraints: const BoxConstraints.expand(),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -164,7 +170,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
controller: scrollControllerUpdate,
|
controller: scrollControllerUpdate,
|
||||||
child: Text(apt.updateLog!),
|
child: Text(apt.updateLog!),
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ListView(
|
return ListView(
|
||||||
padding: const EdgeInsets.all(13),
|
padding: const EdgeInsets.all(13),
|
||||||
@@ -219,7 +226,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
children: apt.upgradeable!
|
children: apt.upgradeable!
|
||||||
.map((e) => _buildUpdateItem(e, apt))
|
.map((e) => _buildUpdateItem(e, apt))
|
||||||
.toList()),
|
.toList(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
@@ -232,7 +240,8 @@ class _AptManagePageState extends State<AptManagePage>
|
|||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
child: Text(apt.upgradeLog!),
|
child: Text(apt.upgradeLog!),
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -54,8 +54,12 @@ class BackupPage extends StatelessWidget {
|
|||||||
const SizedBox(height: 7),
|
const SizedBox(height: 7),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 7),
|
const SizedBox(height: 7),
|
||||||
_buildCard(s.backup, Icons.file_upload, media,
|
_buildCard(
|
||||||
() => _showExportDialog(context, s))
|
s.backup,
|
||||||
|
Icons.file_upload,
|
||||||
|
media,
|
||||||
|
() => _showExportDialog(context, s),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@@ -91,7 +95,9 @@ class BackupPage extends StatelessWidget {
|
|||||||
|
|
||||||
Future<void> _showExportDialog(BuildContext context, S s) async {
|
Future<void> _showExportDialog(BuildContext context, S s) async {
|
||||||
final exportFieldController = TextEditingController()
|
final exportFieldController = TextEditingController()
|
||||||
..text = _diyEncrtpt(json.encode(Backup(
|
..text = _diyEncrtpt(
|
||||||
|
json.encode(
|
||||||
|
Backup(
|
||||||
backupFormatVersion,
|
backupFormatVersion,
|
||||||
DateTime.now().toString().split('.').first,
|
DateTime.now().toString().split('.').first,
|
||||||
server.fetch(),
|
server.fetch(),
|
||||||
@@ -100,7 +106,9 @@ class BackupPage extends StatelessWidget {
|
|||||||
setting.primaryColor.fetch() ?? Colors.pinkAccent.value,
|
setting.primaryColor.fetch() ?? Colors.pinkAccent.value,
|
||||||
setting.serverStatusUpdateInterval.fetch() ?? 2,
|
setting.serverStatusUpdateInterval.fetch() ?? 2,
|
||||||
setting.launchPage.fetch() ?? 0,
|
setting.launchPage.fetch() ?? 0,
|
||||||
)));
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
await showRoundDialog(
|
await showRoundDialog(
|
||||||
context,
|
context,
|
||||||
s.export,
|
s.export,
|
||||||
@@ -115,12 +123,12 @@ class BackupPage extends StatelessWidget {
|
|||||||
TextButton(
|
TextButton(
|
||||||
child: Text(s.copy),
|
child: Text(s.copy),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(
|
Clipboard.setData(ClipboardData(text: exportFieldController.text));
|
||||||
ClipboardData(text: exportFieldController.text));
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showImportDialog(BuildContext context, S s) async {
|
Future<void> _showImportDialog(BuildContext context, S s) async {
|
||||||
@@ -138,13 +146,15 @@ class BackupPage extends StatelessWidget {
|
|||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async =>
|
onPressed: () async =>
|
||||||
await _import(importFieldController.text.trim(), context, s),
|
await _import(importFieldController.text.trim(), context, s),
|
||||||
child: const Text('GO'),
|
child: const Text('GO'),
|
||||||
)
|
)
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _import(String text, BuildContext context, S s) async {
|
Future<void> _import(String text, BuildContext context, S s) async {
|
||||||
@@ -165,7 +175,10 @@ class BackupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await showRoundDialog(
|
await showRoundDialog(
|
||||||
context, s.attention, Text(s.restoreSureWithDate(backup.date)), [
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.restoreSureWithDate(backup.date)),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel),
|
child: Text(s.cancel),
|
||||||
@@ -190,7 +203,8 @@ class BackupPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
child: Text(s.ok),
|
child: Text(s.ok),
|
||||||
),
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
showSnackBar(context, Text(s.invalidJson));
|
showSnackBar(context, Text(s.invalidJson));
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -47,12 +47,15 @@ class _ConvertPageState extends State<ConvertPage>
|
|||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 7),
|
padding: const EdgeInsets.symmetric(horizontal: 7),
|
||||||
controller: ScrollController(),
|
controller: ScrollController(),
|
||||||
child: Column(children: [
|
child: Column(
|
||||||
|
children: [
|
||||||
const SizedBox(height: 13),
|
const SizedBox(height: 13),
|
||||||
_buildInputTop(),
|
_buildInputTop(),
|
||||||
_buildTypeOption(),
|
_buildTypeOption(),
|
||||||
_buildResult(),
|
_buildResult(),
|
||||||
])),
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
try {
|
try {
|
||||||
@@ -119,7 +122,8 @@ class _ConvertPageState extends State<ConvertPage>
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
foregroundColor: MaterialStateProperty.all(primaryColor)),
|
foregroundColor: MaterialStateProperty.all(primaryColor),
|
||||||
|
),
|
||||||
child: Icon(Icons.copy, semanticLabel: s.copy),
|
child: Icon(Icons.copy, semanticLabel: s.copy),
|
||||||
onPressed: () => Clipboard.setData(
|
onPressed: () => Clipboard.setData(
|
||||||
ClipboardData(
|
ClipboardData(
|
||||||
@@ -136,13 +140,15 @@ class _ConvertPageState extends State<ConvertPage>
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(typeOption[_typeOptionIndex],
|
Text(
|
||||||
|
typeOption[_typeOptionIndex],
|
||||||
textScaleFactor: 1.0,
|
textScaleFactor: 1.0,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0,
|
fontSize: 16.0,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: primaryColor)),
|
color: primaryColor),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
s.currentMode,
|
s.currentMode,
|
||||||
textScaleFactor: 1.0,
|
textScaleFactor: 1.0,
|
||||||
@@ -153,7 +159,8 @@ class _ConvertPageState extends State<ConvertPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
children: typeOption
|
children: typeOption
|
||||||
.map((e) => ListTile(
|
.map(
|
||||||
|
(e) => ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
e,
|
e,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@@ -161,7 +168,8 @@ class _ConvertPageState extends State<ConvertPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
trailing: _buildRadio(typeOption.indexOf(e)),
|
trailing: _buildRadio(typeOption.indexOf(e)),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,8 +13,10 @@ class _DebugPageState extends State<DebugPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar:
|
appBar: AppBar(
|
||||||
AppBar(title: const Text('App log'), backgroundColor: Colors.black),
|
title: const Text('App log'),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
),
|
||||||
body: _buildTerminal(context),
|
body: _buildTerminal(context),
|
||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
);
|
);
|
||||||
@@ -31,12 +33,15 @@ class _DebugPageState extends State<DebugPage> {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
child: Consumer<DebugProvider>(builder: (_, debug, __) {
|
child: Consumer<DebugProvider>(
|
||||||
|
builder: (_, debug, __) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: debug.widgets);
|
children: debug.widgets,
|
||||||
}),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => docker.refresh(),
|
onPressed: () => docker.refresh(),
|
||||||
icon: const Icon(Icons.refresh))
|
icon: const Icon(Icons.refresh),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: _buildMain(docker),
|
body: _buildMain(docker),
|
||||||
@@ -124,8 +125,13 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
await _showAddCmdPreview(_buildAddCmd(imageCtrl.text.trim(),
|
await _showAddCmdPreview(
|
||||||
nameCtrl.text.trim(), argsCtrl.text.trim()));
|
_buildAddCmd(
|
||||||
|
imageCtrl.text.trim(),
|
||||||
|
nameCtrl.text.trim(),
|
||||||
|
argsCtrl.text.trim(),
|
||||||
|
),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Text(s.ok),
|
child: Text(s.ok),
|
||||||
)
|
)
|
||||||
@@ -208,14 +214,17 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => onSubmitted(),
|
onPressed: () => onSubmitted(),
|
||||||
child: Text(
|
child: Text(
|
||||||
s.ok,
|
s.ok,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
return textController.text.trim();
|
return textController.text.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,8 +295,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildLoading(DockerProvider docker) {
|
Widget _buildLoading(DockerProvider docker) {
|
||||||
@@ -319,7 +327,8 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => _showEditHostDialog(docker),
|
onPressed: () => _showEditHostDialog(docker),
|
||||||
child: Text(s.dockerEditHost))
|
child: Text(s.dockerEditHost),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -343,7 +352,8 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -399,14 +409,16 @@ class _DockerManagePageState extends State<DockerManagePage> {
|
|||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
title: Text(s.containerStatus),
|
title: Text(s.containerStatus),
|
||||||
subtitle: Text(_buildSubtitle(running), style: greyTextStyle),
|
subtitle: Text(_buildSubtitle(running), style: greyTextStyle),
|
||||||
children: running.map((item) {
|
children: running.map(
|
||||||
|
(item) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(item.image),
|
title: Text(item.image),
|
||||||
subtitle: Text(item.status),
|
subtitle: Text(item.status),
|
||||||
trailing:
|
trailing:
|
||||||
_buildMoreBtn(item.running, item.containerId, docker.isBusy),
|
_buildMoreBtn(item.running, item.containerId, docker.isBusy),
|
||||||
);
|
);
|
||||||
}).toList(),
|
},
|
||||||
|
).toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,10 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
? Colors.white12
|
? Colors.white12
|
||||||
: Colors.black.withOpacity(0.07)
|
: Colors.black.withOpacity(0.07)
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(50))),
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(50),
|
||||||
|
),
|
||||||
|
),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(item.icon),
|
icon: Icon(item.icon),
|
||||||
tooltip: tabTitleName(context, idx),
|
tooltip: tabTitleName(context, idx),
|
||||||
@@ -164,12 +167,15 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
width: _width,
|
width: _width,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: tabItems.map((item) {
|
children: tabItems.map(
|
||||||
|
(item) {
|
||||||
int itemIndex = tabItems.indexOf(item);
|
int itemIndex = tabItems.indexOf(item);
|
||||||
return _buildItem(itemIndex, item, _selectIndex == itemIndex);
|
return _buildItem(itemIndex, item, _selectIndex == itemIndex);
|
||||||
}).toList(),
|
},
|
||||||
|
).toList(),
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildDrawer() {
|
Widget _buildDrawer() {
|
||||||
@@ -217,18 +223,25 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
leading: const Icon(Icons.info),
|
leading: const Icon(Icons.info),
|
||||||
title: Text(s.feedback),
|
title: Text(s.feedback),
|
||||||
onTap: () => showRoundDialog(
|
onTap: () => showRoundDialog(
|
||||||
context, s.feedback, Text(s.feedbackOnGithub), [
|
context,
|
||||||
|
s.feedback,
|
||||||
|
Text(s.feedbackOnGithub),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Clipboard.setData(
|
onPressed: () => Clipboard.setData(
|
||||||
const ClipboardData(text: issueUrl)),
|
const ClipboardData(text: issueUrl)),
|
||||||
child: Text(s.copy)),
|
child: Text(s.copy),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => openUrl(issueUrl),
|
onPressed: () => openUrl(issueUrl),
|
||||||
child: Text(s.feedback)),
|
child: Text(s.feedback),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.close))
|
child: Text(s.close),
|
||||||
]),
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.snippet_folder),
|
leading: const Icon(Icons.snippet_folder),
|
||||||
@@ -274,7 +287,8 @@ class _MyHomePageState extends State<MyHomePage>
|
|||||||
constraints: const BoxConstraints(maxHeight: 53, maxWidth: 53),
|
constraints: const BoxConstraints(maxHeight: 53, maxWidth: 53),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: primaryColor,
|
color: primaryColor,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: const BoxConstraints(maxHeight: 83, maxWidth: 83),
|
constraints: const BoxConstraints(maxHeight: 83, maxWidth: 83),
|
||||||
child: appIcon,
|
child: appIcon,
|
||||||
|
|||||||
@@ -52,7 +52,8 @@ class _PingPageState extends State<PingPage>
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 7),
|
padding: const EdgeInsets.symmetric(horizontal: 7),
|
||||||
child: Column(children: [
|
child: Column(
|
||||||
|
children: [
|
||||||
const SizedBox(height: 13),
|
const SizedBox(height: 13),
|
||||||
buildInput(context, _textEditingController,
|
buildInput(context, _textEditingController,
|
||||||
hint: s.inputDomainHere,
|
hint: s.inputDomainHere,
|
||||||
@@ -69,7 +70,9 @@ class _PingPageState extends State<PingPage>
|
|||||||
return _buildResultItem(result);
|
return _buildResultItem(result);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
])),
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
heroTag: 'ping fab',
|
heroTag: 'ping fab',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -87,19 +90,30 @@ class _PingPageState extends State<PingPage>
|
|||||||
Widget _buildResultItem(PingResult result) {
|
Widget _buildResultItem(PingResult result) {
|
||||||
final unknown = s.unknown;
|
final unknown = s.unknown;
|
||||||
final ms = s.ms;
|
final ms = s.ms;
|
||||||
return RoundRectCard(ListTile(
|
return RoundRectCard(
|
||||||
|
ListTile(
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||||
title: Text(result.serverName,
|
title: Text(
|
||||||
|
result.serverName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18, fontWeight: FontWeight.bold, color: primaryColor)),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
_buildPingSummary(result, unknown, ms),
|
_buildPingSummary(result, unknown, ms),
|
||||||
style: summaryTextStyle,
|
style: summaryTextStyle,
|
||||||
),
|
),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
'${s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? s.unknown} $ms',
|
'${s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? s.unknown} $ms',
|
||||||
style: TextStyle(fontSize: 14, color: primaryColor)),
|
style: TextStyle(
|
||||||
));
|
fontSize: 14,
|
||||||
|
color: primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _buildPingSummary(PingResult result, String unknown, String ms) {
|
String _buildPingSummary(PingResult result, String unknown, String ms) {
|
||||||
|
|||||||
@@ -51,7 +51,9 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(s.edit, style: textSize18), actions: [
|
appBar: AppBar(
|
||||||
|
title: Text(s.edit, style: textSize18),
|
||||||
|
actions: [
|
||||||
widget.info != null
|
widget.info != null
|
||||||
? IconButton(
|
? IconButton(
|
||||||
tooltip: s.delete,
|
tooltip: s.delete,
|
||||||
@@ -61,7 +63,8 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage>
|
|||||||
},
|
},
|
||||||
icon: const Icon(Icons.delete))
|
icon: const Icon(Icons.delete))
|
||||||
: const SizedBox()
|
: const SizedBox()
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(13),
|
padding: const EdgeInsets.all(13),
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -58,12 +58,15 @@ class _PrivateKeyListState extends State<StoredPrivateKeysPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.edit,
|
s.edit,
|
||||||
style: _textStyle,
|
style: _textStyle,
|
||||||
))
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
: Center(child: Text(s.noSavedPrivateKey));
|
: Center(
|
||||||
|
child: Text(s.noSavedPrivateKey),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
|
|||||||
@@ -37,8 +37,9 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<ServerProvider>(builder: (_, provider, __) {
|
return Consumer<ServerProvider>(builder: (_, provider, __) {
|
||||||
return _buildMainPage(
|
return _buildMainPage(
|
||||||
provider.servers
|
provider.servers.firstWhere(
|
||||||
.firstWhere((e) => '${e.info.ip}:${e.info.port}' == widget.id),
|
(e) => '${e.info.ip}:${e.info.port}' == widget.id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -212,7 +213,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
(ss.memory.cache * mb).convertBytes, pColor.withAlpha(77)),
|
(ss.memory.cache * mb).convertBytes, pColor.withAlpha(77)),
|
||||||
_buildMemExplain(
|
_buildMemExplain(
|
||||||
((ss.memory.total - ss.memory.used) * mb).convertBytes,
|
((ss.memory.total - ss.memory.used) * mb).convertBytes,
|
||||||
progressColor.resolve(context))
|
progressColor.resolve(context),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@@ -367,7 +369,8 @@ class _ServerDetailPageState extends State<ServerDetailPage>
|
|||||||
child: Text(ns.speedOut(device: device),
|
child: Text(ns.speedOut(device: device),
|
||||||
style: textSize11,
|
style: textSize11,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
textScaleFactor: 1.0))
|
textScaleFactor: 1.0),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -63,12 +63,17 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(s.edit, style: textSize18), actions: [
|
appBar: AppBar(
|
||||||
|
title: Text(s.edit, style: textSize18),
|
||||||
|
actions: [
|
||||||
widget.spi != null
|
widget.spi != null
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showRoundDialog(context, s.attention,
|
showRoundDialog(
|
||||||
Text(s.sureToDeleteServer(widget.spi!.name)), [
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.sureToDeleteServer(widget.spi!.name)),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_serverProvider.delServer(widget.spi!);
|
_serverProvider.delServer(widget.spi!);
|
||||||
@@ -78,15 +83,20 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.ok,
|
s.ok,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel))
|
child: Text(s.cancel),
|
||||||
]);
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.delete))
|
icon: const Icon(Icons.delete),
|
||||||
|
)
|
||||||
: const SizedBox()
|
: const SizedBox()
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(17),
|
padding: const EdgeInsets.all(17),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -148,7 +158,8 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
usePublicKey
|
usePublicKey
|
||||||
? Consumer<PrivateKeyProvider>(builder: (_, key, __) {
|
? Consumer<PrivateKeyProvider>(
|
||||||
|
builder: (_, key, __) {
|
||||||
for (var item in key.infos) {
|
for (var item in key.infos) {
|
||||||
if (item.id == widget.spi?.pubKeyId) {
|
if (item.id == widget.spi?.pubKeyId) {
|
||||||
_pubKeyIndex ??= key.infos.indexOf(item);
|
_pubKeyIndex ??= key.infos.indexOf(item);
|
||||||
@@ -162,16 +173,19 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
trailing: _buildRadio(key.infos.indexOf(e), e)),
|
trailing: _buildRadio(key.infos.indexOf(e), e)),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
tiles.add(ListTile(
|
tiles.add(
|
||||||
|
ListTile(
|
||||||
title: Text(s.addPrivateKey),
|
title: Text(s.addPrivateKey),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
onPressed: () => AppRoute(const PrivateKeyEditPage(),
|
onPressed: () => AppRoute(
|
||||||
|
const PrivateKeyEditPage(),
|
||||||
'private key edit page')
|
'private key edit page')
|
||||||
.go(context),
|
.go(context),
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
textColor: primaryColor,
|
textColor: primaryColor,
|
||||||
iconColor: primaryColor,
|
iconColor: primaryColor,
|
||||||
@@ -183,7 +197,8 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
),
|
),
|
||||||
children: tiles,
|
children: tiles,
|
||||||
);
|
);
|
||||||
})
|
},
|
||||||
|
)
|
||||||
: const SizedBox()
|
: const SizedBox()
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -208,7 +223,8 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
onPressed: () => Navigator.of(context).pop(true),
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
child: Text(s.cancel))
|
child: Text(s.cancel))
|
||||||
],
|
],
|
||||||
barrierDismiss: false);
|
barrierDismiss: false,
|
||||||
|
);
|
||||||
if (cancel ?? true) {
|
if (cancel ?? true) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -235,7 +251,8 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
port: int.parse(portController.text),
|
port: int.parse(portController.text),
|
||||||
user: usernameController.text,
|
user: usernameController.text,
|
||||||
pwd: authorization,
|
pwd: authorization,
|
||||||
pubKeyId: usePublicKey ? _keyInfo!.id : null);
|
pubKeyId: usePublicKey ? _keyInfo!.id : null,
|
||||||
|
);
|
||||||
|
|
||||||
if (widget.spi == null) {
|
if (widget.spi == null) {
|
||||||
_serverProvider.addServer(spi);
|
_serverProvider.addServer(spi);
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
final child = Consumer<ServerProvider>(builder: (_, pro, __) {
|
final child = Consumer<ServerProvider>(
|
||||||
|
builder: (_, pro, __) {
|
||||||
if (pro.servers.isEmpty) {
|
if (pro.servers.isEmpty) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -78,7 +79,8 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
height: 3,
|
height: 3,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: child,
|
body: child,
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
@@ -104,7 +106,8 @@ class _ServerPageState extends State<ServerPage>
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(13),
|
padding: const EdgeInsets.all(13),
|
||||||
child: _buildRealServerCard(
|
child: _buildRealServerCard(
|
||||||
si.status, si.info.name, si.connectionState, si.info)),
|
si.status, si.info.name, si.connectionState, si.info),
|
||||||
|
),
|
||||||
onTap: () => AppRoute(ServerDetailPage('${si.info.ip}:${si.info.port}'),
|
onTap: () => AppRoute(ServerDetailPage('${si.info.ip}:${si.info.port}'),
|
||||||
'server detail page')
|
'server detail page')
|
||||||
.go(context),
|
.go(context),
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildCheckUpdate() {
|
Widget _buildCheckUpdate() {
|
||||||
return Consumer<AppProvider>(builder: (_, app, __) {
|
return Consumer<AppProvider>(
|
||||||
|
builder: (_, app, __) {
|
||||||
String display;
|
String display;
|
||||||
if (app.newestBuild != null) {
|
if (app.newestBuild != null) {
|
||||||
if (app.newestBuild! > BuildData.build) {
|
if (app.newestBuild! > BuildData.build) {
|
||||||
@@ -90,8 +91,10 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
style: textSize13,
|
style: textSize13,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
),
|
),
|
||||||
onTap: () => doUpdate(context, force: true));
|
onTap: () => doUpdate(context, force: true),
|
||||||
});
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildUpdateInterval() {
|
Widget _buildUpdateInterval() {
|
||||||
@@ -161,10 +164,8 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
s.appPrimaryColor,
|
s.appPrimaryColor,
|
||||||
style: textSize13,
|
style: textSize13,
|
||||||
),
|
),
|
||||||
children: [
|
children: [_buildAppColorPicker(priColor), _buildColorPickerConfirmBtn()],
|
||||||
_buildAppColorPicker(priColor),
|
);
|
||||||
_buildColorPickerConfirmBtn()
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAppColorPicker(Color selected) {
|
Widget _buildAppColorPicker(Color selected) {
|
||||||
@@ -204,7 +205,8 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
children: tabs
|
children: tabs
|
||||||
.map((e) => ListTile(
|
.map(
|
||||||
|
(e) => ListTile(
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
title: Text(
|
title: Text(
|
||||||
tabTitleName(context, tabs.indexOf(e)),
|
tabTitleName(context, tabs.indexOf(e)),
|
||||||
@@ -213,7 +215,8 @@ class _SettingPageState extends State<SettingPage> {
|
|||||||
color: _theme.textTheme.bodyText2!.color!.withAlpha(177)),
|
color: _theme.textTheme.bodyText2!.color!.withAlpha(177)),
|
||||||
),
|
),
|
||||||
trailing: _buildRadio(tabs.indexOf(e)),
|
trailing: _buildRadio(tabs.indexOf(e)),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,10 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
context, s.sureDelete(fileName), const SizedBox(), [
|
context,
|
||||||
|
s.sureDelete(fileName),
|
||||||
|
const SizedBox(),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel)),
|
||||||
@@ -164,7 +167,8 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
|||||||
},
|
},
|
||||||
child: Text(s.ok),
|
child: Text(s.ok),
|
||||||
),
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@@ -172,13 +176,15 @@ class _SFTPDownloadedPageState extends State<SFTPDownloadedPage> {
|
|||||||
title: Text(s.open),
|
title: Text(s.open),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
shareFiles(context, [file.absolute.path]);
|
shareFiles(context, [file.absolute.path]);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: (() => Navigator.of(context).pop()),
|
onPressed: (() => Navigator.of(context).pop()),
|
||||||
child: Text(s.close))
|
child: Text(s.close))
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
|
|
||||||
Widget _wrapInCard(SftpDownloadStatus status, String? subtitle,
|
Widget _wrapInCard(SftpDownloadStatus status, String? subtitle,
|
||||||
{Widget? trailing}) {
|
{Widget? trailing}) {
|
||||||
return RoundRectCard(ListTile(
|
return RoundRectCard(
|
||||||
|
ListTile(
|
||||||
title: Text(status.fileName),
|
title: Text(status.fileName),
|
||||||
subtitle: subtitle == null
|
subtitle: subtitle == null
|
||||||
? null
|
? null
|
||||||
@@ -67,7 +68,8 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
style: grey,
|
style: grey,
|
||||||
),
|
),
|
||||||
trailing: trailing,
|
trailing: trailing,
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildItem(SftpDownloadStatus status) {
|
Widget _buildItem(SftpDownloadStatus status) {
|
||||||
@@ -77,11 +79,14 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
switch (status.status) {
|
switch (status.status) {
|
||||||
case SftpWorkerStatus.finished:
|
case SftpWorkerStatus.finished:
|
||||||
final time = status.spentTime.toString();
|
final time = status.spentTime.toString();
|
||||||
return _wrapInCard(status,
|
return _wrapInCard(
|
||||||
|
status,
|
||||||
'${s.downloadFinished} ${s.spentTime(time == 'null' ? s.unknown : (time.substring(0, time.length - 7)))}',
|
'${s.downloadFinished} ${s.spentTime(time == 'null' ? s.unknown : (time.substring(0, time.length - 7)))}',
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
onPressed: () => shareFiles(context, [status.item.localPath]),
|
onPressed: () => shareFiles(context, [status.item.localPath]),
|
||||||
icon: const Icon(Icons.open_in_new)));
|
icon: const Icon(Icons.open_in_new),
|
||||||
|
),
|
||||||
|
);
|
||||||
case SftpWorkerStatus.downloading:
|
case SftpWorkerStatus.downloading:
|
||||||
return _wrapInCard(
|
return _wrapInCard(
|
||||||
status,
|
status,
|
||||||
@@ -94,11 +99,14 @@ class _SFTPDownloadingPageState extends State<SFTPDownloadingPage> {
|
|||||||
case SftpWorkerStatus.sshConnectted:
|
case SftpWorkerStatus.sshConnectted:
|
||||||
return _wrapInCard(status, s.sftpSSHConnected, trailing: loadingIcon);
|
return _wrapInCard(status, s.sftpSSHConnected, trailing: loadingIcon);
|
||||||
default:
|
default:
|
||||||
return _wrapInCard(status, s.unknown,
|
return _wrapInCard(
|
||||||
|
status,
|
||||||
|
s.unknown,
|
||||||
trailing: const Icon(
|
trailing: const Icon(
|
||||||
Icons.error,
|
Icons.error,
|
||||||
size: 40,
|
size: 40,
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,10 +79,12 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.close))
|
child: Text(s.close))
|
||||||
])),
|
],
|
||||||
|
)),
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
)
|
)
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
body: _buildFileView(),
|
body: _buildFileView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -157,7 +159,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onRefresh: () => listDir(path: _status.path?.path));
|
onRefresh: () => listDir(path: _status.path?.path),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,16 +192,20 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
),
|
),
|
||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(), child: Text(s.cancel))
|
||||||
child: Text(s.cancel))
|
],
|
||||||
]);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void download(BuildContext context, SftpName name) {
|
void download(BuildContext context, SftpName name) {
|
||||||
showRoundDialog(context, s.download,
|
showRoundDialog(
|
||||||
Text('${s.dl2Local(name.filename)}\n${s.keepForeground}'), [
|
context,
|
||||||
|
s.download,
|
||||||
|
Text('${s.dl2Local(name.filename)}\n${s.keepForeground}'),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.cancel)),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: Text(s.cancel)),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
@@ -207,32 +214,52 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
prePath + (prePath.endsWith('/') ? '' : '/') + name.filename;
|
prePath + (prePath.endsWith('/') ? '' : '/') + name.filename;
|
||||||
final local = '${(await sftpDownloadDir).path}$remotePath';
|
final local = '${(await sftpDownloadDir).path}$remotePath';
|
||||||
final pubKeyId = _status.spi!.pubKeyId;
|
final pubKeyId = _status.spi!.pubKeyId;
|
||||||
|
|
||||||
locator<SftpDownloadProvider>().add(
|
locator<SftpDownloadProvider>().add(
|
||||||
DownloadItem(_status.spi!, remotePath, local),
|
DownloadItem(
|
||||||
|
_status.spi!,
|
||||||
|
remotePath,
|
||||||
|
local,
|
||||||
|
),
|
||||||
key: pubKeyId == null
|
key: pubKeyId == null
|
||||||
? null
|
? null
|
||||||
: locator<PrivateKeyStore>().get(pubKeyId).privateKey);
|
: locator<PrivateKeyStore>().get(pubKeyId).privateKey,
|
||||||
|
);
|
||||||
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
showRoundDialog(context, s.goSftpDlPage, const SizedBox(), [
|
showRoundDialog(
|
||||||
|
context,
|
||||||
|
s.goSftpDlPage,
|
||||||
|
const SizedBox(),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
AppRoute(const SFTPDownloadingPage(), 'sftp downloading')
|
AppRoute(const SFTPDownloadingPage(), 'sftp downloading')
|
||||||
.go(context);
|
.go(context);
|
||||||
},
|
},
|
||||||
child: Text(s.ok))
|
child: Text(s.ok),
|
||||||
]);
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: Text(s.download))
|
child: Text(s.download),
|
||||||
]);
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete(BuildContext context, SftpName file) {
|
void delete(BuildContext context, SftpName file) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
showRoundDialog(context, s.attention, Text(s.sureDelete(file.filename)), [
|
showRoundDialog(
|
||||||
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.sureDelete(file.filename)),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: const Text('Cancel')),
|
child: const Text('Cancel')),
|
||||||
@@ -245,8 +272,10 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.delete,
|
s.delete,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mkdir(BuildContext context) {
|
void mkdir(BuildContext context) {
|
||||||
@@ -264,16 +293,21 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (textController.text == '') {
|
if (textController.text == '') {
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
context, s.attention, Text(s.fieldMustNotEmpty), [
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.fieldMustNotEmpty),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.ok)),
|
child: Text(s.ok)),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_status.client!
|
_status.client!
|
||||||
@@ -284,8 +318,10 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.ok,
|
s.ok,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void newFile(BuildContext context) {
|
void newFile(BuildContext context) {
|
||||||
@@ -303,16 +339,22 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
[
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.cancel)),
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (textController.text == '') {
|
if (textController.text == '') {
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
context, s.attention, Text(s.fieldMustNotEmpty), [
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.fieldMustNotEmpty),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.ok)),
|
child: Text(s.ok),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
(await _status.client!
|
(await _status.client!
|
||||||
@@ -324,8 +366,10 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.ok,
|
s.ok,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rename(BuildContext context, SftpName file) {
|
void rename(BuildContext context, SftpName file) {
|
||||||
@@ -348,23 +392,29 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (textController.text == '') {
|
if (textController.text == '') {
|
||||||
showRoundDialog(
|
showRoundDialog(
|
||||||
context, s.attention, Text(s.fieldMustNotEmpty), [
|
context,
|
||||||
|
s.attention,
|
||||||
|
Text(s.fieldMustNotEmpty),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
child: Text(s.ok)),
|
child: Text(s.ok),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await _status.client!
|
await _status.client!.rename(file.filename, textController.text);
|
||||||
.rename(file.filename, textController.text);
|
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
listDir();
|
listDir();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
s.rename,
|
s.rename,
|
||||||
style: const TextStyle(color: Colors.red),
|
style: const TextStyle(color: Colors.red),
|
||||||
)),
|
),
|
||||||
]);
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> listDir({String? path, SSHClient? client}) async {
|
Future<void> listDir({String? path, SSHClient? client}) async {
|
||||||
@@ -388,10 +438,17 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await showRoundDialog(context, s.error, Text(e.toString()), [
|
await showRoundDialog(
|
||||||
|
context,
|
||||||
|
s.error,
|
||||||
|
Text(e.toString()),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.ok))
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
]);
|
child: Text(s.ok),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
if (_status.path!.undo()) {
|
if (_status.path!.undo()) {
|
||||||
await listDir();
|
await listDir();
|
||||||
}
|
}
|
||||||
@@ -424,7 +481,8 @@ class _SFTPPageState extends State<SFTPPage> {
|
|||||||
.servers
|
.servers
|
||||||
.firstWhere((s) => s.info == spi)
|
.firstWhere((s) => s.info == spi)
|
||||||
.client,
|
.client,
|
||||||
path: '/');
|
path: '/',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ class _SnippetEditPageState extends State<SnippetEditPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text(s.edit, style: textSize18), actions: [
|
appBar: AppBar(
|
||||||
|
title: Text(s.edit, style: textSize18),
|
||||||
|
actions: [
|
||||||
widget.snippet != null
|
widget.snippet != null
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@@ -51,7 +53,8 @@ class _SnippetEditPageState extends State<SnippetEditPage>
|
|||||||
tooltip: s.delete,
|
tooltip: s.delete,
|
||||||
icon: const Icon(Icons.delete))
|
icon: const Icon(Icons.delete))
|
||||||
: const SizedBox()
|
: const SizedBox()
|
||||||
]),
|
],
|
||||||
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
padding: const EdgeInsets.all(13),
|
padding: const EdgeInsets.all(13),
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
itemCount: key.snippets.length,
|
itemCount: key.snippets.length,
|
||||||
itemExtent: 57,
|
itemExtent: 57,
|
||||||
itemBuilder: (context, idx) {
|
itemBuilder: (context, idx) {
|
||||||
return RoundRectCard(Padding(
|
return RoundRectCard(
|
||||||
|
Padding(
|
||||||
padding: roundRectCardPadding,
|
padding: roundRectCardPadding,
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@@ -69,7 +70,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
key.snippets[idx].name,
|
key.snippets[idx].name,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Row(children: [
|
Row(
|
||||||
|
children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => AppRoute(
|
onPressed: () => AppRoute(
|
||||||
SnippetEditPage(
|
SnippetEditPage(
|
||||||
@@ -79,7 +81,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.edit,
|
s.edit,
|
||||||
style: _textStyle,
|
style: _textStyle,
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final snippet = key.snippets[idx];
|
final snippet = key.snippets[idx];
|
||||||
@@ -92,27 +95,37 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
s.run,
|
s.run,
|
||||||
style: _textStyle,
|
style: _textStyle,
|
||||||
))
|
),
|
||||||
])
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
})
|
);
|
||||||
: Center(child: Text(s.noSavedSnippet));
|
},
|
||||||
|
)
|
||||||
|
: Center(
|
||||||
|
child: Text(s.noSavedSnippet),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showRunDialog(Snippet snippet) {
|
void _showRunDialog(Snippet snippet) {
|
||||||
showRoundDialog(context, s.chooseDestination,
|
showRoundDialog(
|
||||||
Consumer<ServerProvider>(builder: (_, provider, __) {
|
context,
|
||||||
|
s.chooseDestination,
|
||||||
|
Consumer<ServerProvider>(
|
||||||
|
builder: (_, provider, __) {
|
||||||
if (provider.servers.isEmpty) {
|
if (provider.servers.isEmpty) {
|
||||||
return Text(s.noServerAvailable);
|
return Text(s.noServerAvailable);
|
||||||
}
|
}
|
||||||
_selectedIndex = provider.servers.first.info;
|
_selectedIndex = provider.servers.first.info;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 111,
|
height: 111,
|
||||||
child: Stack(children: [
|
child: Stack(
|
||||||
|
children: [
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 36,
|
top: 36,
|
||||||
bottom: 36,
|
bottom: 36,
|
||||||
@@ -142,24 +155,39 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
),
|
),
|
||||||
childCount: provider.servers.length),
|
childCount: provider.servers.length),
|
||||||
)
|
)
|
||||||
]));
|
],
|
||||||
}), [
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async => run(context, snippet), child: Text(s.run)),
|
onPressed: () async => run(context, snippet),
|
||||||
|
child: Text(s.run),
|
||||||
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.cancel)),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
]);
|
child: Text(s.cancel),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> run(BuildContext context, Snippet snippet) async {
|
Future<void> run(BuildContext context, Snippet snippet) async {
|
||||||
final result = await locator<ServerProvider>()
|
final result = await locator<ServerProvider>()
|
||||||
.runSnippet(widget.spi ?? _selectedIndex, snippet);
|
.runSnippet(widget.spi ?? _selectedIndex, snippet);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
showRoundDialog(context, s.result,
|
showRoundDialog(
|
||||||
Text(result, style: const TextStyle(fontSize: 13)), [
|
context,
|
||||||
|
s.result,
|
||||||
|
Text(result, style: const TextStyle(fontSize: 13)),
|
||||||
|
[
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).pop(), child: Text(s.close))
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
]);
|
child: Text(s.close),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user