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 {
|
||||
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 sftp =
|
||||
DropdownBtnItem(text: 'SFTP', icon: Icons.insert_drive_file);
|
||||
static const snippet = DropdownBtnItem(text: 'Snippet', icon: Icons.label);
|
||||
static const pkg =
|
||||
DropdownBtnItem(text: 'Pkg', icon: Icons.system_security_update);
|
||||
static const docker =
|
||||
|
||||
@@ -301,12 +301,13 @@ class ServerProvider extends BusyProvider {
|
||||
info.status.memory = mem;
|
||||
}
|
||||
|
||||
Future<String?> runSnippet(ServerPrivateInfo spi, Snippet snippet) async {
|
||||
return await _servers
|
||||
.firstWhere((element) => element.info == spi)
|
||||
.client!
|
||||
.run(snippet.script)
|
||||
.string;
|
||||
Future<String?> runSnippet(String id, Snippet snippet) async {
|
||||
final client =
|
||||
_servers.firstWhere((element) => element.info.id == id).client;
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
return await client.run(snippet.script).string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"aboutThanks": MessageLookupByLibrary.simpleMessage(
|
||||
"\nAll rights reserved.\n\nThanks to the following people who participated in the test."),
|
||||
"addAServer": MessageLookupByLibrary.simpleMessage("add a server"),
|
||||
"addOne": MessageLookupByLibrary.simpleMessage("Add one"),
|
||||
"addPrivateKey":
|
||||
MessageLookupByLibrary.simpleMessage("Add private key"),
|
||||
"alreadyLastDir":
|
||||
|
||||
@@ -61,6 +61,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
||||
"aboutThanks":
|
||||
MessageLookupByLibrary.simpleMessage("\n保留所有权利。\n\n感谢以下参与软件测试的各位。"),
|
||||
"addAServer": MessageLookupByLibrary.simpleMessage("添加服务器"),
|
||||
"addOne": MessageLookupByLibrary.simpleMessage("前去新增"),
|
||||
"addPrivateKey": MessageLookupByLibrary.simpleMessage("添加一个私钥"),
|
||||
"alreadyLastDir": MessageLookupByLibrary.simpleMessage("已经是最上层目录了"),
|
||||
"appPrimaryColor": MessageLookupByLibrary.simpleMessage("App主要色"),
|
||||
|
||||
@@ -1520,6 +1520,16 @@ class S {
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
|
||||
/// `Add one`
|
||||
String get addOne {
|
||||
return Intl.message(
|
||||
'Add one',
|
||||
name: 'addOne',
|
||||
desc: '',
|
||||
args: [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationDelegate extends LocalizationsDelegate<S> {
|
||||
|
||||
@@ -145,5 +145,6 @@
|
||||
"path": "Path",
|
||||
"goto": "Go to",
|
||||
"showDistLogo": "Show distribution logo",
|
||||
"onServerDetailPage": "On server detail page"
|
||||
"onServerDetailPage": "On server detail page",
|
||||
"addOne": "Add one"
|
||||
}
|
||||
@@ -145,5 +145,6 @@
|
||||
"path": "路径",
|
||||
"goto": "前往",
|
||||
"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_status.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/font_style.dart';
|
||||
import 'package:toolbox/generated/l10n.dart';
|
||||
import 'package:toolbox/locator.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/edit.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';
|
||||
|
||||
class ServerPage extends StatefulWidget {
|
||||
@@ -157,6 +160,8 @@ class _ServerPageState extends State<ServerPage>
|
||||
context, _s.error, Text(ss.failedInfo ?? ''), []),
|
||||
child: Text(_s.clickSee, style: style))
|
||||
: Text(topRightStr, style: style, textScaleFactor: 1.0),
|
||||
const SizedBox(width: 7),
|
||||
_buildSnippetBtn(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) {
|
||||
return buildPopuopMenu(
|
||||
items: <PopupMenuEntry>[
|
||||
@@ -217,9 +279,6 @@ class _ServerPageState extends State<ServerPage>
|
||||
case ServerTabMenuItems.sftp:
|
||||
AppRoute(SFTPPage(spi), 'SFTP').go(context);
|
||||
break;
|
||||
case ServerTabMenuItems.snippet:
|
||||
AppRoute(SnippetListPage(spi: spi), 'snippet list').go(context);
|
||||
break;
|
||||
case ServerTabMenuItems.edit:
|
||||
AppRoute(ServerEditPage(spi: spi), 'Edit server info').go(context);
|
||||
break;
|
||||
|
||||
@@ -23,7 +23,7 @@ class SettingPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SettingPageState extends State<SettingPage> {
|
||||
late SettingStore _setting;
|
||||
late final SettingStore _setting;
|
||||
late int _selectedColorValue;
|
||||
late int _launchPageIdx;
|
||||
late Color priColor;
|
||||
@@ -32,7 +32,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
late ThemeData _theme;
|
||||
late S _s;
|
||||
|
||||
var _intervalValue = 0.0;
|
||||
var _updateInterval = 5.0;
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
@@ -49,7 +49,7 @@ class _SettingPageState extends State<SettingPage> {
|
||||
_serverProvider = locator<ServerProvider>();
|
||||
_setting = locator<SettingStore>();
|
||||
_launchPageIdx = _setting.launchPage.fetch()!;
|
||||
_intervalValue = _setting.serverStatusUpdateInterval.fetch()!.toDouble();
|
||||
_updateInterval = _setting.serverStatusUpdateInterval.fetch()!.toDouble();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -126,30 +126,30 @@ class _SettingPageState extends State<SettingPage> {
|
||||
_s.willTakEeffectImmediately,
|
||||
style: textSize13Grey,
|
||||
),
|
||||
trailing: Text('${_intervalValue.toInt()} ${_s.second}'),
|
||||
trailing: Text('${_updateInterval.toInt()} ${_s.second}'),
|
||||
children: [
|
||||
Slider(
|
||||
thumbColor: priColor,
|
||||
activeColor: priColor.withOpacity(0.7),
|
||||
min: 0,
|
||||
max: 10,
|
||||
value: _intervalValue,
|
||||
value: _updateInterval,
|
||||
onChanged: (newValue) {
|
||||
setState(() {
|
||||
_intervalValue = newValue;
|
||||
_updateInterval = newValue;
|
||||
});
|
||||
},
|
||||
onChangeEnd: (val) {
|
||||
_setting.serverStatusUpdateInterval.put(val.toInt());
|
||||
_serverProvider.startAutoRefresh();
|
||||
},
|
||||
label: '${_intervalValue.toInt()} ${_s.second}',
|
||||
label: '${_updateInterval.toInt()} ${_s.second}',
|
||||
divisions: 10,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 3,
|
||||
),
|
||||
_intervalValue == 0.0
|
||||
_updateInterval == 0.0
|
||||
? Text(
|
||||
_s.updateIntervalEqual0,
|
||||
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/locator.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';
|
||||
|
||||
class SnippetListPage extends StatefulWidget {
|
||||
@@ -23,7 +24,7 @@ class SnippetListPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SnippetListPageState extends State<SnippetListPage> {
|
||||
late ServerPrivateInfo _selectedIndex;
|
||||
late ServerPrivateInfo _selectedSpi;
|
||||
|
||||
final _textStyle = TextStyle(color: primaryColor);
|
||||
|
||||
@@ -121,48 +122,23 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
||||
if (provider.servers.isEmpty) {
|
||||
return Text(_s.noServerAvailable);
|
||||
}
|
||||
_selectedIndex = provider.servers.first.info;
|
||||
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) =>
|
||||
_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),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
_selectedSpi = provider.servers.first.info;
|
||||
return buildPicker(
|
||||
provider.servers
|
||||
.map((e) => Text(
|
||||
e.info.name,
|
||||
textAlign: TextAlign.center,
|
||||
))
|
||||
.toList(),
|
||||
(idx) => _selectedSpi = provider.servers[idx].info);
|
||||
},
|
||||
),
|
||||
[
|
||||
TextButton(
|
||||
onPressed: () async => run(context, snippet),
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
run(context, snippet);
|
||||
},
|
||||
child: Text(_s.run),
|
||||
),
|
||||
TextButton(
|
||||
@@ -174,8 +150,8 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
||||
}
|
||||
|
||||
Future<void> run(BuildContext context, Snippet snippet) async {
|
||||
final result = await locator<ServerProvider>()
|
||||
.runSnippet(widget.spi ?? _selectedIndex, snippet);
|
||||
final id = (widget.spi ?? _selectedSpi).id;
|
||||
final result = await locator<ServerProvider>().runSnippet(id, snippet);
|
||||
if (result != null) {
|
||||
showRoundDialog(
|
||||
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