mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
Snippet support import/export.
This commit is contained in:
@@ -29,7 +29,8 @@ class ServerTabMenuItems {
|
|||||||
|
|
||||||
static const sftp = MenuItem(text: 'SFTP', icon: Icons.insert_drive_file);
|
static const sftp = MenuItem(text: 'SFTP', icon: Icons.insert_drive_file);
|
||||||
static const snippet = MenuItem(text: 'Snippet', icon: Icons.label);
|
static const snippet = MenuItem(text: 'Snippet', icon: Icons.label);
|
||||||
static const apt = MenuItem(text: 'Apt/Yum', icon: Icons.system_security_update);
|
static const apt =
|
||||||
|
MenuItem(text: 'Apt/Yum', icon: Icons.system_security_update);
|
||||||
static const docker = MenuItem(text: 'Docker', icon: Icons.view_agenda);
|
static const docker = MenuItem(text: 'Docker', icon: Icons.view_agenda);
|
||||||
static const edit = MenuItem(text: 'Edit', icon: Icons.edit);
|
static const edit = MenuItem(text: 'Edit', icon: Icons.edit);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:toolbox/core/provider_base.dart';
|
import 'package:toolbox/core/provider_base.dart';
|
||||||
import 'package:toolbox/data/model/server/snippet.dart';
|
import 'package:toolbox/data/model/server/snippet.dart';
|
||||||
import 'package:toolbox/data/store/snippet.dart';
|
import 'package:toolbox/data/store/snippet.dart';
|
||||||
@@ -11,22 +13,34 @@ class SnippetProvider extends BusyProvider {
|
|||||||
_snippets = locator<SnippetStore>().fetch();
|
_snippets = locator<SnippetStore>().fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInfo(Snippet snippet) {
|
void add(Snippet snippet) {
|
||||||
|
if (have(snippet)) return;
|
||||||
_snippets.add(snippet);
|
_snippets.add(snippet);
|
||||||
locator<SnippetStore>().put(snippet);
|
locator<SnippetStore>().put(snippet);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void delInfo(Snippet snippet) {
|
void del(Snippet snippet) {
|
||||||
_snippets.removeWhere((e) => e.name == snippet.name);
|
if (!have(snippet)) return;
|
||||||
|
_snippets.removeAt(index(snippet));
|
||||||
locator<SnippetStore>().delete(snippet);
|
locator<SnippetStore>().delete(snippet);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateInfo(Snippet old, Snippet newOne) {
|
int index(Snippet snippet) {
|
||||||
final idx = _snippets.indexWhere((e) => e.name == old.name);
|
return _snippets.indexWhere((e) => e.name == snippet.name);
|
||||||
_snippets[idx] = newOne;
|
}
|
||||||
|
|
||||||
|
bool have(Snippet snippet) {
|
||||||
|
return index(snippet) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(Snippet old, Snippet newOne) {
|
||||||
|
if (!have(old)) return;
|
||||||
|
_snippets[index(old)] = newOne;
|
||||||
locator<SnippetStore>().update(old, newOne);
|
locator<SnippetStore>().update(old, newOne);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get export => json.encode(snippets);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
class BuildData {
|
class BuildData {
|
||||||
static const String name = "ServerBox";
|
static const String name = "ServerBox";
|
||||||
static const int build = 110;
|
static const int build = 111;
|
||||||
static const String engine =
|
static const String engine =
|
||||||
"Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision c860cba910 (12 days ago) • 2022-03-25 00:23:12 -0500\nEngine • revision 57d3bac3dd\nTools • Dart 2.16.2 • DevTools 2.9.2\n";
|
"Flutter 2.10.4 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision c860cba910 (13 days ago) • 2022-03-25 00:23:12 -0500\nEngine • revision 57d3bac3dd\nTools • Dart 2.16.2 • DevTools 2.9.2\n";
|
||||||
static const String buildAt = "2022-04-06 13:48:27.717376";
|
static const String buildAt = "2022-04-07 19:53:12.283804";
|
||||||
static const int modifications = 0;
|
static const int modifications = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
|
|||||||
widget.snippet != null
|
widget.snippet != null
|
||||||
? IconButton(
|
? IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_provider.delInfo(widget.snippet!);
|
_provider.del(widget.snippet!);
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.delete))
|
icon: const Icon(Icons.delete))
|
||||||
@@ -71,9 +71,9 @@ class _SnippetEditPageState extends State<SnippetEditPage>
|
|||||||
}
|
}
|
||||||
final snippet = Snippet(name, script);
|
final snippet = Snippet(name, script);
|
||||||
if (widget.snippet != null) {
|
if (widget.snippet != null) {
|
||||||
_provider.updateInfo(widget.snippet!, snippet);
|
_provider.update(widget.snippet!, snippet);
|
||||||
} else {
|
} else {
|
||||||
_provider.addInfo(snippet);
|
_provider.add(snippet);
|
||||||
}
|
}
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:toolbox/core/route.dart';
|
import 'package:toolbox/core/route.dart';
|
||||||
@@ -23,12 +24,20 @@ class SnippetListPage extends StatefulWidget {
|
|||||||
class _SnippetListPageState extends State<SnippetListPage> {
|
class _SnippetListPageState extends State<SnippetListPage> {
|
||||||
late ServerPrivateInfo _selectedIndex;
|
late ServerPrivateInfo _selectedIndex;
|
||||||
|
|
||||||
|
final _importFieldController = TextEditingController();
|
||||||
|
final _exportFieldController = TextEditingController();
|
||||||
|
|
||||||
final _textStyle = TextStyle(color: primaryColor);
|
final _textStyle = TextStyle(color: primaryColor);
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Snippet List'),
|
title: const Text('Snippet List'),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => _showImportExport(),
|
||||||
|
icon: const Icon(Icons.import_export)),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: _buildBody(),
|
body: _buildBody(),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
@@ -39,6 +48,97 @@ class _SnippetListPageState extends State<SnippetListPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _showImportExport() async {
|
||||||
|
await showRoundDialog(
|
||||||
|
context,
|
||||||
|
'Choose',
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Import'),
|
||||||
|
leading: const Icon(Icons.download),
|
||||||
|
onTap: () => _showImportDialog(),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Export'),
|
||||||
|
leading: const Icon(Icons.file_upload),
|
||||||
|
onTap: () => _showExportDialog(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showExportDialog() async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
_exportFieldController.text = locator<SnippetProvider>().export;
|
||||||
|
await showRoundDialog(
|
||||||
|
context,
|
||||||
|
'Export',
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'JSON',
|
||||||
|
),
|
||||||
|
maxLines: 3,
|
||||||
|
controller: _exportFieldController,
|
||||||
|
),
|
||||||
|
[
|
||||||
|
TextButton(
|
||||||
|
child: const Text('OK'),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showImportDialog() async {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
await showRoundDialog(
|
||||||
|
context,
|
||||||
|
'Import',
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Url or JSON',
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
controller: _importFieldController,
|
||||||
|
),
|
||||||
|
[
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('Cancel')),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async =>
|
||||||
|
await _import(_importFieldController.text.trim()),
|
||||||
|
child: const Text('GO'),
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _import(String text) async {
|
||||||
|
if (text.isEmpty) {
|
||||||
|
showSnackBar(context, const Text('field can not be empty'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final snippetProvider = locator<SnippetProvider>();
|
||||||
|
if (text.startsWith('http')) {
|
||||||
|
final resp = await Dio().get(text);
|
||||||
|
if (resp.statusCode != 200) {
|
||||||
|
showSnackBar(
|
||||||
|
context, Text('request failed, status code: ${resp.statusCode}'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (final snippet in getSnippetList(resp.data)) {
|
||||||
|
snippetProvider.add(snippet);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (final snippet in getSnippetList(text)) {
|
||||||
|
snippetProvider.add(snippet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
Widget _buildBody() {
|
Widget _buildBody() {
|
||||||
return Consumer<SnippetProvider>(
|
return Consumer<SnippetProvider>(
|
||||||
builder: (_, key, __) {
|
builder: (_, key, __) {
|
||||||
|
|||||||
Reference in New Issue
Block a user