mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2026-01-31 13:25:10 +01:00
opt.: close after saving (#684)
This commit is contained in:
@@ -11,17 +11,17 @@ import 'package:flutter_highlight/themes/monokai.dart';
|
||||
import 'package:server_box/core/extension/context/locale.dart';
|
||||
import 'package:server_box/data/res/highlight.dart';
|
||||
import 'package:server_box/data/res/store.dart';
|
||||
import 'package:server_box/data/store/setting.dart';
|
||||
|
||||
import 'package:server_box/view/widget/two_line_text.dart';
|
||||
|
||||
enum EditorPageRetType { path, text }
|
||||
|
||||
final class EditorPageRet {
|
||||
/// If edit text, this includes the edited result
|
||||
final String? result;
|
||||
final EditorPageRetType typ;
|
||||
final String val;
|
||||
|
||||
/// Indicates whether it's ok to edit existing file
|
||||
final bool? editExistedOk;
|
||||
|
||||
const EditorPageRet({this.result, this.editExistedOk});
|
||||
const EditorPageRet(this.typ, this.val);
|
||||
}
|
||||
|
||||
final class EditorPageArgs {
|
||||
@@ -38,11 +38,14 @@ final class EditorPageArgs {
|
||||
|
||||
final String? title;
|
||||
|
||||
final void Function(BuildContext, EditorPageRet) onSave;
|
||||
|
||||
const EditorPageArgs({
|
||||
this.path,
|
||||
this.text,
|
||||
this.langCode,
|
||||
this.title,
|
||||
required this.onSave,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -51,7 +54,7 @@ class EditorPage extends StatefulWidget {
|
||||
|
||||
const EditorPage({super.key, this.args});
|
||||
|
||||
static const route = AppRoute<EditorPageRet, EditorPageArgs>(
|
||||
static const route = AppRoute<void, EditorPageArgs>(
|
||||
page: EditorPage.new,
|
||||
path: '/editor',
|
||||
);
|
||||
@@ -69,6 +72,7 @@ class _EditorPageState extends State<EditorPage> {
|
||||
TextStyle(fontSize: Stores.setting.editorFontSize.fetch());
|
||||
|
||||
String? _langCode;
|
||||
var _saved = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
@@ -99,10 +103,16 @@ class _EditorPageState extends State<EditorPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: _codeTheme['root']?.backgroundColor,
|
||||
appBar: _buildAppBar(),
|
||||
body: _buildBody(),
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
_pop();
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: _codeTheme['root']?.backgroundColor,
|
||||
appBar: _buildAppBar(),
|
||||
body: _buildBody(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -136,25 +146,7 @@ class _EditorPageState extends State<EditorPage> {
|
||||
IconButton(
|
||||
icon: const Icon(Icons.save),
|
||||
tooltip: l10n.save,
|
||||
onPressed: () async {
|
||||
// If path is not null, then it's a file editor
|
||||
// save the text and return true to pop the page
|
||||
final path = widget.args?.path;
|
||||
if (path != null) {
|
||||
final (res, _) = await context.showLoadingDialog(
|
||||
fn: () => File(path).writeAsString(_controller.text),
|
||||
);
|
||||
if (res == null) {
|
||||
context.showSnackBar(libL10n.fail);
|
||||
return;
|
||||
}
|
||||
context.pop(const EditorPageRet(editExistedOk: true));
|
||||
return;
|
||||
}
|
||||
// else it's a text editor
|
||||
// return the text to the previous page
|
||||
context.pop(EditorPageRet(result: _controller.text));
|
||||
},
|
||||
onPressed: _onSave,
|
||||
)
|
||||
],
|
||||
);
|
||||
@@ -210,4 +202,44 @@ extension on _EditorPageState {
|
||||
_controller.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
void _onSave() async {
|
||||
// If path is not null, then it's a file editor
|
||||
final path = widget.args?.path;
|
||||
if (path != null) {
|
||||
final (res, _) = await context.showLoadingDialog(
|
||||
fn: () => File(path).writeAsString(_controller.text),
|
||||
);
|
||||
if (res == null) {
|
||||
context.showSnackBar(libL10n.fail);
|
||||
return;
|
||||
}
|
||||
final ret = EditorPageRet(EditorPageRetType.path, path);
|
||||
widget.args?.onSave(context, ret);
|
||||
_saved = true;
|
||||
|
||||
final pop_ = SettingStore.instance.closeAfterSave.fetch();
|
||||
if (pop_) _pop();
|
||||
return;
|
||||
}
|
||||
// it's a text editor
|
||||
final ret = EditorPageRet(EditorPageRetType.text, _controller.text);
|
||||
widget.args?.onSave(context, ret);
|
||||
_saved = true;
|
||||
|
||||
final pop_ = SettingStore.instance.closeAfterSave.fetch();
|
||||
if (pop_) _pop();
|
||||
}
|
||||
|
||||
void _pop() async {
|
||||
if (!_saved) {
|
||||
final ret = await context.showRoundDialog(
|
||||
title: libL10n.attention,
|
||||
child: Text(libL10n.askContinue(libL10n.exit)),
|
||||
actions: Btnx.cancelOk,
|
||||
);
|
||||
if (ret != true) return;
|
||||
}
|
||||
context.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +305,7 @@ final class _AppSettingsPageState extends State<AppSettingsPage> {
|
||||
_buildEditorTheme(),
|
||||
_buildEditorDarkTheme(),
|
||||
_buildEditorHighlight(),
|
||||
_buildEditorCloseAfterEdit(),
|
||||
].map((e) => CardX(child: e)).toList(),
|
||||
);
|
||||
}
|
||||
@@ -1329,32 +1330,49 @@ final class _AppSettingsPageState extends State<AppSettingsPage> {
|
||||
final map = await Stores.setting.getAllMap(includeInternalKeys: true);
|
||||
final keys = map.keys;
|
||||
|
||||
void onSave(BuildContext context, EditorPageRet ret) {
|
||||
if (ret.typ != EditorPageRetType.text) {
|
||||
context.showRoundDialog(
|
||||
title: libL10n.fail,
|
||||
child: Text(l10n.invalid),
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
final newSettings = json.decode(ret.val) as Map<String, dynamic>;
|
||||
Stores.setting.box.putAll(newSettings);
|
||||
final newKeys = newSettings.keys;
|
||||
final removedKeys = keys.where((e) => !newKeys.contains(e));
|
||||
for (final key in removedKeys) {
|
||||
Stores.setting.box.delete(key);
|
||||
}
|
||||
} catch (e, trace) {
|
||||
context.showRoundDialog(
|
||||
title: libL10n.error,
|
||||
child: Text('${l10n.save}:\n$e'),
|
||||
);
|
||||
Loggers.app.warning('Update json settings failed', e, trace);
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode [map] to String with indent `\t`
|
||||
final text = jsonIndentEncoder.convert(map);
|
||||
final ret = await EditorPage.route.go(
|
||||
await EditorPage.route.go(
|
||||
context,
|
||||
args: EditorPageArgs(
|
||||
text: text,
|
||||
langCode: 'json',
|
||||
title: libL10n.setting,
|
||||
onSave: onSave,
|
||||
),
|
||||
);
|
||||
final result = ret?.result;
|
||||
if (result == null) return;
|
||||
try {
|
||||
final newSettings = json.decode(result) as Map<String, dynamic>;
|
||||
Stores.setting.box.putAll(newSettings);
|
||||
final newKeys = newSettings.keys;
|
||||
final removedKeys = keys.where((e) => !newKeys.contains(e));
|
||||
for (final key in removedKeys) {
|
||||
Stores.setting.box.delete(key);
|
||||
}
|
||||
} catch (e, trace) {
|
||||
context.showRoundDialog(
|
||||
title: libL10n.error,
|
||||
child: Text('${l10n.save}:\n$e'),
|
||||
);
|
||||
Loggers.app.warning('Update json settings failed', e, trace);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildEditorCloseAfterEdit() {
|
||||
return ListTile(
|
||||
leading: const Icon(MingCute.edit_fill),
|
||||
title: Text(l10n.closeAfterSave),
|
||||
trailing: StoreSwitch(prop: _setting.closeAfterSave),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,14 +217,17 @@ class _LocalFilePageState extends State<LocalFilePage>
|
||||
);
|
||||
return;
|
||||
}
|
||||
final ret = await EditorPage.route.go(
|
||||
|
||||
await EditorPage.route.go(
|
||||
context,
|
||||
args: EditorPageArgs(path: file.absolute.path),
|
||||
args: EditorPageArgs(
|
||||
path: file.absolute.path,
|
||||
onSave: (context, _) {
|
||||
context.showSnackBar(l10n.saved);
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
);
|
||||
if (ret?.editExistedOk == true) {
|
||||
context.showSnackBar(l10n.saved);
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
Btn.tile(
|
||||
|
||||
@@ -317,19 +317,21 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||
);
|
||||
if (suc == null || err != null) return;
|
||||
|
||||
final ret = await EditorPage.route.go(
|
||||
await EditorPage.route.go(
|
||||
context,
|
||||
args: EditorPageArgs(path: localPath),
|
||||
args: EditorPageArgs(
|
||||
path: localPath,
|
||||
onSave: (context, _) {
|
||||
SftpProvider.add(SftpReq(
|
||||
req.spi,
|
||||
remotePath,
|
||||
localPath,
|
||||
SftpReqType.upload,
|
||||
));
|
||||
context.showSnackBar(l10n.added2List);
|
||||
},
|
||||
),
|
||||
);
|
||||
if (ret?.editExistedOk == true) {
|
||||
SftpProvider.add(SftpReq(
|
||||
req.spi,
|
||||
remotePath,
|
||||
localPath,
|
||||
SftpReqType.upload,
|
||||
));
|
||||
context.showSnackBar(l10n.added2List);
|
||||
}
|
||||
}
|
||||
|
||||
void _download(SftpName name) {
|
||||
|
||||
Reference in New Issue
Block a user