make running snippet more convenient

This commit is contained in:
lollipopkit
2023-01-27 23:06:47 +08:00
parent b6ab4b7fde
commit 913ce312de
11 changed files with 148 additions and 63 deletions

View File

@@ -24,12 +24,11 @@ class DropdownBtnItem {
} }
class ServerTabMenuItems { class ServerTabMenuItems {
static const List<DropdownBtnItem> firstItems = [sftp, snippet, pkg, docker]; static const List<DropdownBtnItem> firstItems = [sftp, pkg, docker];
static const List<DropdownBtnItem> secondItems = [edit]; static const List<DropdownBtnItem> secondItems = [edit];
static const sftp = static const sftp =
DropdownBtnItem(text: 'SFTP', icon: Icons.insert_drive_file); DropdownBtnItem(text: 'SFTP', icon: Icons.insert_drive_file);
static const snippet = DropdownBtnItem(text: 'Snippet', icon: Icons.label);
static const pkg = static const pkg =
DropdownBtnItem(text: 'Pkg', icon: Icons.system_security_update); DropdownBtnItem(text: 'Pkg', icon: Icons.system_security_update);
static const docker = static const docker =

View File

@@ -301,12 +301,13 @@ class ServerProvider extends BusyProvider {
info.status.memory = mem; info.status.memory = mem;
} }
Future<String?> runSnippet(ServerPrivateInfo spi, Snippet snippet) async { Future<String?> runSnippet(String id, Snippet snippet) async {
return await _servers final client =
.firstWhere((element) => element.info == spi) _servers.firstWhere((element) => element.info.id == id).client;
.client! if (client == null) {
.run(snippet.script) return null;
.string; }
return await client.run(snippet.script).string;
} }
} }

View File

@@ -61,6 +61,7 @@ class MessageLookup extends MessageLookupByLibrary {
"aboutThanks": MessageLookupByLibrary.simpleMessage( "aboutThanks": MessageLookupByLibrary.simpleMessage(
"\nAll rights reserved.\n\nThanks to the following people who participated in the test."), "\nAll rights reserved.\n\nThanks to the following people who participated in the test."),
"addAServer": MessageLookupByLibrary.simpleMessage("add a server"), "addAServer": MessageLookupByLibrary.simpleMessage("add a server"),
"addOne": MessageLookupByLibrary.simpleMessage("Add one"),
"addPrivateKey": "addPrivateKey":
MessageLookupByLibrary.simpleMessage("Add private key"), MessageLookupByLibrary.simpleMessage("Add private key"),
"alreadyLastDir": "alreadyLastDir":

View File

@@ -61,6 +61,7 @@ class MessageLookup extends MessageLookupByLibrary {
"aboutThanks": "aboutThanks":
MessageLookupByLibrary.simpleMessage("\n保留所有权利。\n\n感谢以下参与软件测试的各位。"), MessageLookupByLibrary.simpleMessage("\n保留所有权利。\n\n感谢以下参与软件测试的各位。"),
"addAServer": MessageLookupByLibrary.simpleMessage("添加服务器"), "addAServer": MessageLookupByLibrary.simpleMessage("添加服务器"),
"addOne": MessageLookupByLibrary.simpleMessage("前去新增"),
"addPrivateKey": MessageLookupByLibrary.simpleMessage("添加一个私钥"), "addPrivateKey": MessageLookupByLibrary.simpleMessage("添加一个私钥"),
"alreadyLastDir": MessageLookupByLibrary.simpleMessage("已经是最上层目录了"), "alreadyLastDir": MessageLookupByLibrary.simpleMessage("已经是最上层目录了"),
"appPrimaryColor": MessageLookupByLibrary.simpleMessage("App主要色"), "appPrimaryColor": MessageLookupByLibrary.simpleMessage("App主要色"),

View File

@@ -1520,6 +1520,16 @@ class S {
args: [], args: [],
); );
} }
/// `Add one`
String get addOne {
return Intl.message(
'Add one',
name: 'addOne',
desc: '',
args: [],
);
}
} }
class AppLocalizationDelegate extends LocalizationsDelegate<S> { class AppLocalizationDelegate extends LocalizationsDelegate<S> {

View File

@@ -145,5 +145,6 @@
"path": "Path", "path": "Path",
"goto": "Go to", "goto": "Go to",
"showDistLogo": "Show distribution logo", "showDistLogo": "Show distribution logo",
"onServerDetailPage": "On server detail page" "onServerDetailPage": "On server detail page",
"addOne": "Add one"
} }

View File

@@ -145,5 +145,6 @@
"path": "路径", "path": "路径",
"goto": "前往", "goto": "前往",
"showDistLogo": "显示发行版 Logo", "showDistLogo": "显示发行版 Logo",
"onServerDetailPage": "在服务器详情页" "onServerDetailPage": "在服务器详情页",
"addOne": "前去新增"
} }

View File

@@ -10,7 +10,9 @@ import 'package:toolbox/data/model/server/server.dart';
import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/model/server/server_private_info.dart';
import 'package:toolbox/data/model/server/server_status.dart'; import 'package:toolbox/data/model/server/server_status.dart';
import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/provider/server.dart';
import 'package:toolbox/data/provider/snippet.dart';
import 'package:toolbox/data/res/color.dart'; import 'package:toolbox/data/res/color.dart';
import 'package:toolbox/data/res/font_style.dart';
import 'package:toolbox/generated/l10n.dart'; import 'package:toolbox/generated/l10n.dart';
import 'package:toolbox/locator.dart'; import 'package:toolbox/locator.dart';
import 'package:toolbox/view/page/pkg.dart'; import 'package:toolbox/view/page/pkg.dart';
@@ -18,7 +20,8 @@ import 'package:toolbox/view/page/docker.dart';
import 'package:toolbox/view/page/server/detail.dart'; import 'package:toolbox/view/page/server/detail.dart';
import 'package:toolbox/view/page/server/edit.dart'; import 'package:toolbox/view/page/server/edit.dart';
import 'package:toolbox/view/page/sftp/view.dart'; import 'package:toolbox/view/page/sftp/view.dart';
import 'package:toolbox/view/page/snippet/list.dart'; import 'package:toolbox/view/page/snippet/edit.dart';
import 'package:toolbox/view/widget/picker.dart';
import 'package:toolbox/view/widget/round_rect_card.dart'; import 'package:toolbox/view/widget/round_rect_card.dart';
class ServerPage extends StatefulWidget { class ServerPage extends StatefulWidget {
@@ -157,6 +160,8 @@ class _ServerPageState extends State<ServerPage>
context, _s.error, Text(ss.failedInfo ?? ''), []), context, _s.error, Text(ss.failedInfo ?? ''), []),
child: Text(_s.clickSee, style: style)) child: Text(_s.clickSee, style: style))
: Text(topRightStr, style: style, textScaleFactor: 1.0), : Text(topRightStr, style: style, textScaleFactor: 1.0),
const SizedBox(width: 7),
_buildSnippetBtn(spi),
_buildMoreBtn(spi), _buildMoreBtn(spi),
], ],
) )
@@ -191,6 +196,63 @@ class _ServerPageState extends State<ServerPage>
); );
} }
Widget _buildSnippetBtn(ServerPrivateInfo spi) {
return GestureDetector(
child: const Icon(Icons.play_arrow),
onTap: () {
final provider = locator<SnippetProvider>();
if (provider.snippets.isEmpty) {
showRoundDialog(
context,
_s.attention,
Text(_s.noSavedSnippet),
[
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(_s.ok),
),
TextButton(
onPressed: () =>
AppRoute(const SnippetEditPage(), 'edit snippet')
.go(context),
child: Text(_s.addOne),
)
],
);
return;
}
var snippet = provider.snippets.first;
showRoundDialog(
context,
_s.choose,
buildPicker(provider.snippets.map((e) => Text(e.name)).toList(),
(idx) => snippet = provider.snippets[idx]),
[
TextButton(
onPressed: () async {
Navigator.of(context).pop();
final result =
await locator<ServerProvider>().runSnippet(spi.id, snippet);
showRoundDialog(
context,
_s.result,
Text(result ?? _s.error, style: textSize13),
[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text(_s.ok))
],
);
},
child: Text(_s.run),
)
],
);
},
);
}
Widget _buildMoreBtn(ServerPrivateInfo spi) { Widget _buildMoreBtn(ServerPrivateInfo spi) {
return buildPopuopMenu( return buildPopuopMenu(
items: <PopupMenuEntry>[ items: <PopupMenuEntry>[
@@ -217,9 +279,6 @@ class _ServerPageState extends State<ServerPage>
case ServerTabMenuItems.sftp: case ServerTabMenuItems.sftp:
AppRoute(SFTPPage(spi), 'SFTP').go(context); AppRoute(SFTPPage(spi), 'SFTP').go(context);
break; break;
case ServerTabMenuItems.snippet:
AppRoute(SnippetListPage(spi: spi), 'snippet list').go(context);
break;
case ServerTabMenuItems.edit: case ServerTabMenuItems.edit:
AppRoute(ServerEditPage(spi: spi), 'Edit server info').go(context); AppRoute(ServerEditPage(spi: spi), 'Edit server info').go(context);
break; break;

View File

@@ -23,7 +23,7 @@ class SettingPage extends StatefulWidget {
} }
class _SettingPageState extends State<SettingPage> { class _SettingPageState extends State<SettingPage> {
late SettingStore _setting; late final SettingStore _setting;
late int _selectedColorValue; late int _selectedColorValue;
late int _launchPageIdx; late int _launchPageIdx;
late Color priColor; late Color priColor;
@@ -32,7 +32,7 @@ class _SettingPageState extends State<SettingPage> {
late ThemeData _theme; late ThemeData _theme;
late S _s; late S _s;
var _intervalValue = 0.0; var _updateInterval = 5.0;
@override @override
void didChangeDependencies() { void didChangeDependencies() {
@@ -49,7 +49,7 @@ class _SettingPageState extends State<SettingPage> {
_serverProvider = locator<ServerProvider>(); _serverProvider = locator<ServerProvider>();
_setting = locator<SettingStore>(); _setting = locator<SettingStore>();
_launchPageIdx = _setting.launchPage.fetch()!; _launchPageIdx = _setting.launchPage.fetch()!;
_intervalValue = _setting.serverStatusUpdateInterval.fetch()!.toDouble(); _updateInterval = _setting.serverStatusUpdateInterval.fetch()!.toDouble();
} }
@override @override
@@ -126,30 +126,30 @@ class _SettingPageState extends State<SettingPage> {
_s.willTakEeffectImmediately, _s.willTakEeffectImmediately,
style: textSize13Grey, style: textSize13Grey,
), ),
trailing: Text('${_intervalValue.toInt()} ${_s.second}'), trailing: Text('${_updateInterval.toInt()} ${_s.second}'),
children: [ children: [
Slider( Slider(
thumbColor: priColor, thumbColor: priColor,
activeColor: priColor.withOpacity(0.7), activeColor: priColor.withOpacity(0.7),
min: 0, min: 0,
max: 10, max: 10,
value: _intervalValue, value: _updateInterval,
onChanged: (newValue) { onChanged: (newValue) {
setState(() { setState(() {
_intervalValue = newValue; _updateInterval = newValue;
}); });
}, },
onChangeEnd: (val) { onChangeEnd: (val) {
_setting.serverStatusUpdateInterval.put(val.toInt()); _setting.serverStatusUpdateInterval.put(val.toInt());
_serverProvider.startAutoRefresh(); _serverProvider.startAutoRefresh();
}, },
label: '${_intervalValue.toInt()} ${_s.second}', label: '${_updateInterval.toInt()} ${_s.second}',
divisions: 10, divisions: 10,
), ),
const SizedBox( const SizedBox(
height: 3, height: 3,
), ),
_intervalValue == 0.0 _updateInterval == 0.0
? Text( ? Text(
_s.updateIntervalEqual0, _s.updateIntervalEqual0,
style: const TextStyle(color: Colors.grey, fontSize: 12), style: const TextStyle(color: Colors.grey, fontSize: 12),

View File

@@ -12,6 +12,7 @@ import 'package:toolbox/data/res/padding.dart';
import 'package:toolbox/generated/l10n.dart'; import 'package:toolbox/generated/l10n.dart';
import 'package:toolbox/locator.dart'; import 'package:toolbox/locator.dart';
import 'package:toolbox/view/page/snippet/edit.dart'; import 'package:toolbox/view/page/snippet/edit.dart';
import 'package:toolbox/view/widget/picker.dart';
import 'package:toolbox/view/widget/round_rect_card.dart'; import 'package:toolbox/view/widget/round_rect_card.dart';
class SnippetListPage extends StatefulWidget { class SnippetListPage extends StatefulWidget {
@@ -23,7 +24,7 @@ class SnippetListPage extends StatefulWidget {
} }
class _SnippetListPageState extends State<SnippetListPage> { class _SnippetListPageState extends State<SnippetListPage> {
late ServerPrivateInfo _selectedIndex; late ServerPrivateInfo _selectedSpi;
final _textStyle = TextStyle(color: primaryColor); final _textStyle = TextStyle(color: primaryColor);
@@ -121,48 +122,23 @@ class _SnippetListPageState extends State<SnippetListPage> {
if (provider.servers.isEmpty) { if (provider.servers.isEmpty) {
return Text(_s.noServerAvailable); return Text(_s.noServerAvailable);
} }
_selectedIndex = provider.servers.first.info; _selectedSpi = provider.servers.first.info;
return SizedBox( return buildPicker(
height: 111, provider.servers
child: Stack( .map((e) => Text(
children: [ e.info.name,
Positioned(
top: 36,
bottom: 36,
left: 0,
right: 0,
child: Container(
height: 37,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(7)),
color: Colors.black12,
),
),
),
ListWheelScrollView.useDelegate(
itemExtent: 37,
diameterRatio: 1.2,
controller: FixedExtentScrollController(initialItem: 0),
onSelectedItemChanged: (idx) =>
_selectedIndex = provider.servers[idx].info,
physics: const FixedExtentScrollPhysics(),
childDelegate: ListWheelChildBuilderDelegate(
builder: (context, index) => Center(
child: Text(
provider.servers[index].info.name,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ))
), .toList(),
childCount: provider.servers.length), (idx) => _selectedSpi = provider.servers[idx].info);
)
],
),
);
}, },
), ),
[ [
TextButton( TextButton(
onPressed: () async => run(context, snippet), onPressed: () async {
Navigator.of(context).pop();
run(context, snippet);
},
child: Text(_s.run), child: Text(_s.run),
), ),
TextButton( TextButton(
@@ -174,8 +150,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
} }
Future<void> run(BuildContext context, Snippet snippet) async { Future<void> run(BuildContext context, Snippet snippet) async {
final result = await locator<ServerProvider>() final id = (widget.spi ?? _selectedSpi).id;
.runSnippet(widget.spi ?? _selectedIndex, snippet); final result = await locator<ServerProvider>().runSnippet(id, snippet);
if (result != null) { if (result != null) {
showRoundDialog( showRoundDialog(
context, context,

View File

@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
Widget buildPicker(List<Widget> items, Function(int idx) onSelected) {
return SizedBox(
height: 111,
child: Stack(
children: [
Positioned(
top: 36,
bottom: 36,
left: 0,
right: 0,
child: Container(
height: 37,
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(7)),
color: Colors.black12,
),
),
),
ListWheelScrollView.useDelegate(
itemExtent: 37,
diameterRatio: 1.2,
controller: FixedExtentScrollController(initialItem: 0),
onSelectedItemChanged: (idx) => onSelected(idx),
physics: const FixedExtentScrollPhysics(),
childDelegate: ListWheelChildBuilderDelegate(
builder: (context, index) => Center(
child: items[index],
),
childCount: items.length),
)
],
),
);
}