mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
make running snippet more convenient
This commit is contained in:
@@ -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 =
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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":
|
||||||
|
|||||||
@@ -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主要色"),
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
@@ -145,5 +145,6 @@
|
|||||||
"path": "路径",
|
"path": "路径",
|
||||||
"goto": "前往",
|
"goto": "前往",
|
||||||
"showDistLogo": "显示发行版 Logo",
|
"showDistLogo": "显示发行版 Logo",
|
||||||
"onServerDetailPage": "在服务器详情页"
|
"onServerDetailPage": "在服务器详情页",
|
||||||
|
"addOne": "前去新增"
|
||||||
}
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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(
|
textAlign: TextAlign.center,
|
||||||
top: 36,
|
))
|
||||||
bottom: 36,
|
.toList(),
|
||||||
left: 0,
|
(idx) => _selectedSpi = provider.servers[idx].info);
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
childCount: provider.servers.length),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
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,
|
||||||
|
|||||||
36
lib/view/widget/picker.dart
Normal file
36
lib/view/widget/picker.dart
Normal 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),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user