opt.: no app restart required

This commit is contained in:
lollipopkit
2023-09-21 20:08:54 +08:00
parent cc4a05bf11
commit e928a29353
34 changed files with 498 additions and 620 deletions

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import '../../../data/model/server/snippet.dart'; import '../../../data/model/server/snippet.dart';
@@ -41,37 +41,35 @@ extension DialogX on BuildContext {
String? user, String? user,
) async { ) async {
if (!mounted) return null; if (!mounted) return null;
final s = S.of(this)!;
return await showRoundDialog<String>( return await showRoundDialog<String>(
title: Text(user ?? s.pwd), title: Text(user ?? l10n.pwd),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
type: TextInputType.visiblePassword, type: TextInputType.visiblePassword,
obscureText: true, obscureText: true,
onSubmitted: (val) => pop(val.trim()), onSubmitted: (val) => pop(val.trim()),
label: s.pwd, label: l10n.pwd,
), ),
); );
} }
void showSnippetDialog( void showSnippetDialog(
S s,
void Function(Snippet s) onSelected, void Function(Snippet s) onSelected,
) { ) {
if (Providers.snippet.snippets.isEmpty) { if (Providers.snippet.snippets.isEmpty) {
showRoundDialog( showRoundDialog(
child: Text(s.noSavedSnippet), child: Text(l10n.noSavedSnippet),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => pop(), onPressed: () => pop(),
child: Text(s.ok), child: Text(l10n.ok),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
pop(); pop();
AppRoute.snippetEdit().go(this); AppRoute.snippetEdit().go(this);
}, },
child: Text(s.add), child: Text(l10n.add),
) )
], ],
); );
@@ -80,7 +78,7 @@ extension DialogX on BuildContext {
var snippet = Providers.snippet.snippets.first; var snippet = Providers.snippet.snippets.first;
showRoundDialog( showRoundDialog(
title: Text(s.choose), title: Text(l10n.choose),
child: Picker( child: Picker(
items: Providers.snippet.snippets.map((e) => Text(e.name)).toList(), items: Providers.snippet.snippets.map((e) => Text(e.name)).toList(),
onSelected: (idx) => snippet = Providers.snippet.snippets[idx], onSelected: (idx) => snippet = Providers.snippet.snippets[idx],
@@ -91,7 +89,7 @@ extension DialogX on BuildContext {
pop(); pop();
onSelected(snippet); onSelected(snippet);
}, },
child: Text(s.ok), child: Text(l10n.ok),
) )
], ],
); );

View File

@@ -0,0 +1,7 @@
import 'package:flutter_gen/gen_l10n/l10n.dart';
late S _s;
S get l10n => _s;
set l10n(S s) {
_s = s;
}

View File

@@ -2,10 +2,10 @@ import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:r_upgrade/r_upgrade.dart'; import 'package:r_upgrade/r_upgrade.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/model/app/update.dart'; import 'package:toolbox/data/model/app/update.dart';
@@ -54,17 +54,15 @@ Future<void> doUpdate(BuildContext context, {bool force = false}) async {
return; return;
} }
final s = S.of(context);
final min = update.build.min.current; final min = update.build.min.current;
if (min != null && min > BuildData.build) { if (min != null && min > BuildData.build) {
context.showRoundDialog( context.showRoundDialog(
child: Text(s?.updateTipTooLow(newest) ?? 'Update: $newest'), child: Text(l10n.updateTipTooLow(newest)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => _doUpdate(update, context, s), onPressed: () => _doUpdate(update, context),
child: Text(s?.ok ?? 'Ok'), child: Text(l10n.ok),
) )
], ],
); );
@@ -72,13 +70,13 @@ Future<void> doUpdate(BuildContext context, {bool force = false}) async {
} }
context.showSnackBarWithAction( context.showSnackBarWithAction(
'${s?.updateTip(newest) ?? "Update: $newest"} \n${update.changelog.current}', '${l10n.updateTip(newest)} \n${update.changelog.current}',
s?.update ?? 'Update', l10n.update,
() => _doUpdate(update, context, s), () => _doUpdate(update, context),
); );
} }
Future<void> _doUpdate(AppUpdate update, BuildContext context, S? s) async { Future<void> _doUpdate(AppUpdate update, BuildContext context) async {
final url = update.url.current; final url = update.url.current;
if (url == null) return; if (url == null) return;
@@ -91,11 +89,11 @@ Future<void> _doUpdate(AppUpdate update, BuildContext context, S? s) async {
await openUrl(url); await openUrl(url);
} else { } else {
context.showRoundDialog( context.showRoundDialog(
child: Text(s?.platformNotSupportUpdate ?? 'Unsupported platform'), child: Text(l10n.platformNotSupportUpdate),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(s?.ok ?? 'Ok'), child: Text(l10n.ok),
) )
], ],
); );

View File

@@ -3,9 +3,9 @@ import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:plain_notification_token/plain_notification_token.dart'; import 'package:plain_notification_token/plain_notification_token.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
@@ -19,7 +19,7 @@ Future<bool> shareFiles(BuildContext context, List<String> filePaths) async {
if (filePaths.length == 1) { if (filePaths.length == 1) {
text = filePaths.first.split('/').last; text = filePaths.first.split('/').last;
} else { } else {
text = '${filePaths.length} ${S.of(context)!.files}'; text = '${filePaths.length} ${l10n.files}';
} }
Providers.app.moveBg = false; Providers.app.moveBg = false;
// ignore: deprecated_member_use // ignore: deprecated_member_use

View File

@@ -5,23 +5,23 @@ class _RebuildNode implements ValueListenable<Null> {
final List<VoidCallback> _listeners = []; final List<VoidCallback> _listeners = [];
_RebuildNode(); _RebuildNode();
@override @override
void addListener(VoidCallback listener) { void addListener(VoidCallback listener) {
_listeners.add(listener); _listeners.add(listener);
} }
@override @override
void removeListener(VoidCallback listener) { void removeListener(VoidCallback listener) {
_listeners.remove(listener); _listeners.remove(listener);
} }
void rebuild() { void rebuild() {
for (var listener in _listeners) { for (var listener in _listeners) {
listener(); listener();
} }
} }
@override @override
Null get value => null; Null get value => null;
} }
@@ -30,4 +30,4 @@ class RebuildNodes {
const RebuildNodes._(); const RebuildNodes._();
static final _RebuildNode app = _RebuildNode(); static final _RebuildNode app = _RebuildNode();
} }

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/extension/context/locale.dart';
enum ServerTabMenuType { enum ServerTabMenuType {
terminal, terminal,
@@ -27,20 +27,20 @@ enum ServerTabMenuType {
} }
} }
String text(S s) { String get toStr {
switch (this) { switch (this) {
case ServerTabMenuType.sftp: case ServerTabMenuType.sftp:
return 'SFTP'; return 'SFTP';
case ServerTabMenuType.snippet: case ServerTabMenuType.snippet:
return s.snippet; return l10n.snippet;
case ServerTabMenuType.pkg: case ServerTabMenuType.pkg:
return s.pkg; return l10n.pkg;
case ServerTabMenuType.docker: case ServerTabMenuType.docker:
return 'Docker'; return 'Docker';
case ServerTabMenuType.process: case ServerTabMenuType.process:
return s.process; return l10n.process;
case ServerTabMenuType.terminal: case ServerTabMenuType.terminal:
return s.terminal; return l10n.terminal;
} }
} }
} }
@@ -89,26 +89,26 @@ enum DockerMenuType {
} }
} }
String text(S s) { String get toStr {
switch (this) { switch (this) {
case DockerMenuType.start: case DockerMenuType.start:
return s.start; return l10n.start;
case DockerMenuType.stop: case DockerMenuType.stop:
return s.stop; return l10n.stop;
case DockerMenuType.restart: case DockerMenuType.restart:
return s.restart; return l10n.restart;
case DockerMenuType.rm: case DockerMenuType.rm:
return s.delete; return l10n.delete;
case DockerMenuType.logs: case DockerMenuType.logs:
return s.log; return l10n.log;
case DockerMenuType.terminal: case DockerMenuType.terminal:
return s.terminal; return l10n.terminal;
// case DockerMenuType.stats: // case DockerMenuType.stats:
// return s.stats; // return s.stats;
} }
} }
PopupMenuItem<DockerMenuType> build(S s) => _build(this, icon, text(s)); PopupMenuItem<DockerMenuType> get widget => _build(this, icon, toStr);
} }
PopupMenuItem<T> _build<T>(T t, IconData icon, String text) { PopupMenuItem<T> _build<T>(T t, IconData icon, String text) {

View File

@@ -1,5 +1,5 @@
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/model/server/server_status.dart'; import 'package:toolbox/data/model/server/server_status.dart';
part 'net_view.g.dart'; part 'net_view.g.dart';
@@ -13,14 +13,14 @@ enum NetViewType {
@HiveField(2) @HiveField(2)
traffic; traffic;
String l10n(S s) { String get toStr {
switch (this) { switch (this) {
case NetViewType.conn: case NetViewType.conn:
return s.conn; return l10n.conn;
case NetViewType.traffic: case NetViewType.traffic:
return s.traffic; return l10n.traffic;
case NetViewType.speed: case NetViewType.speed:
return s.speed; return l10n.speed;
} }
} }

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:xterm/core.dart'; import 'package:xterm/core.dart';
part 'virtual_key.g.dart'; part 'virtual_key.g.dart';
@@ -148,12 +148,12 @@ enum VirtKey {
} }
} }
String? help(S s) { String? get help {
switch (this) { switch (this) {
case VirtKey.sftp: case VirtKey.sftp:
return s.virtKeyHelpSFTP; return l10n.virtKeyHelpSFTP;
case VirtKey.clipboard: case VirtKey.clipboard:
return s.virtKeyHelpClipboard; return l10n.virtKeyHelpClipboard;
default: default:
return null; return null;
} }

View File

@@ -3,9 +3,9 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/core/utils/rebuild.dart'; import 'package:toolbox/core/utils/rebuild.dart';
@@ -25,34 +25,33 @@ class BackupPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final s = S.of(context)!;
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(s.backupAndRestore, style: UIs.textSize18), title: Text(l10n.backupAndRestore, style: UIs.textSize18),
), ),
body: _buildBody(context, s), body: _buildBody(context),
); );
} }
Widget _buildBody(BuildContext context, S s) { Widget _buildBody(BuildContext context) {
return Column( return Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (isMacOS || isIOS) _buildIcloudSync(context, s), if (isMacOS || isIOS) _buildIcloudSync(context),
UIs.height13, UIs.height13,
Padding( Padding(
padding: const EdgeInsets.all(37), padding: const EdgeInsets.all(37),
child: Text( child: Text(
s.backupTip, l10n.backupTip,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
UIs.height77, UIs.height77,
_buildCard( _buildCard(
s.restore, l10n.restore,
Icons.download, Icons.download,
() => _onRestore(context, s), () => _onRestore(context),
), ),
UIs.height13, UIs.height13,
const SizedBox( const SizedBox(
@@ -61,7 +60,7 @@ class BackupPage extends StatelessWidget {
), ),
UIs.height13, UIs.height13,
_buildCard( _buildCard(
s.backup, l10n.backup,
Icons.save, Icons.save,
() async { () async {
await Backup.backup(); await Backup.backup();
@@ -96,7 +95,7 @@ class BackupPage extends StatelessWidget {
); );
} }
Widget _buildIcloudSync(BuildContext context, S s) { Widget _buildIcloudSync(BuildContext context) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@@ -121,19 +120,19 @@ class BackupPage extends StatelessWidget {
); );
} }
Future<void> _onRestore(BuildContext context, S s) async { Future<void> _onRestore(BuildContext context) async {
final path = await pickOneFile(); final path = await pickOneFile();
if (path == null) return; if (path == null) return;
final file = File(path); final file = File(path);
if (!await file.exists()) { if (!await file.exists()) {
context.showSnackBar(s.fileNotExist(path)); context.showSnackBar(l10n.fileNotExist(path));
return; return;
} }
final text = await file.readAsString(); final text = await file.readAsString();
if (text.isEmpty) { if (text.isEmpty) {
context.showSnackBar(s.fieldMustNotEmpty); context.showSnackBar(l10n.fieldMustNotEmpty);
return; return;
} }
@@ -141,17 +140,17 @@ class BackupPage extends StatelessWidget {
context.showLoadingDialog(); context.showLoadingDialog();
final backup = await compute(Backup.fromJsonString, text.trim()); final backup = await compute(Backup.fromJsonString, text.trim());
if (backupFormatVersion != backup.version) { if (backupFormatVersion != backup.version) {
context.showSnackBar(s.backupVersionNotMatch); context.showSnackBar(l10n.backupVersionNotMatch);
return; return;
} }
await context.showRoundDialog( await context.showRoundDialog(
title: Text(s.restore), title: Text(l10n.restore),
child: Text(s.restoreSureWithDate(backup.date)), child: Text(l10n.restoreSureWithDate(backup.date)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -159,7 +158,7 @@ class BackupPage extends StatelessWidget {
context.pop(); context.pop();
RebuildNodes.app.rebuild(); RebuildNodes.app.rebuild();
}, },
child: Text(s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/route.dart';
import 'package:toolbox/data/model/docker/image.dart'; import 'package:toolbox/data/model/docker/image.dart';
@@ -33,7 +33,6 @@ class DockerManagePage extends StatefulWidget {
class _DockerManagePageState extends State<DockerManagePage> { class _DockerManagePageState extends State<DockerManagePage> {
final _textController = TextEditingController(); final _textController = TextEditingController();
late S _s;
@override @override
void dispose() { void dispose() {
@@ -42,12 +41,6 @@ class _DockerManagePageState extends State<DockerManagePage> {
_textController.dispose(); _textController.dispose();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -103,27 +96,27 @@ class _DockerManagePageState extends State<DockerManagePage> {
final nameCtrl = TextEditingController(); final nameCtrl = TextEditingController();
final argsCtrl = TextEditingController(); final argsCtrl = TextEditingController();
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.newContainer), title: Text(l10n.newContainer),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Input( Input(
autoFocus: true, autoFocus: true,
type: TextInputType.text, type: TextInputType.text,
label: _s.image, label: l10n.image,
hint: 'xxx:1.1', hint: 'xxx:1.1',
controller: imageCtrl, controller: imageCtrl,
), ),
Input( Input(
type: TextInputType.text, type: TextInputType.text,
controller: nameCtrl, controller: nameCtrl,
label: _s.containerName, label: l10n.containerName,
hint: 'xxx', hint: 'xxx',
), ),
Input( Input(
type: TextInputType.text, type: TextInputType.text,
controller: argsCtrl, controller: argsCtrl,
label: _s.extraArgs, label: l10n.extraArgs,
hint: '-p 2222:22 -v ~/.xxx/:/xxx', hint: '-p 2222:22 -v ~/.xxx/:/xxx',
), ),
], ],
@@ -131,7 +124,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -144,7 +137,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
), ),
); );
}, },
child: Text(_s.ok), child: Text(l10n.ok),
) )
], ],
); );
@@ -152,12 +145,12 @@ class _DockerManagePageState extends State<DockerManagePage> {
Future<void> _showAddCmdPreview(String cmd) async { Future<void> _showAddCmdPreview(String cmd) async {
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.preview), title: Text(l10n.preview),
child: Text(cmd), child: Text(cmd),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -166,10 +159,10 @@ class _DockerManagePageState extends State<DockerManagePage> {
final result = await Providers.docker.run(cmd); final result = await Providers.docker.run(cmd);
context.pop(); context.pop();
if (result != null) { if (result != null) {
context.showSnackBar(result.message ?? _s.unknownError); context.showSnackBar(result.message ?? l10n.unknownError);
} }
}, },
child: Text(_s.run), child: Text(l10n.run),
) )
], ],
); );
@@ -200,7 +193,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
size: 37, size: 37,
), ),
const SizedBox(height: 27), const SizedBox(height: 27),
Text(Providers.docker.error?.message ?? _s.unknownError), Text(Providers.docker.error?.message ?? l10n.unknownError),
const SizedBox(height: 27), const SizedBox(height: 27),
Padding( Padding(
padding: const EdgeInsets.all(17), padding: const EdgeInsets.all(17),
@@ -230,9 +223,9 @@ class _DockerManagePageState extends State<DockerManagePage> {
Widget _buildImage() { Widget _buildImage() {
final items = <Widget>[ final items = <Widget>[
ListTile( ListTile(
title: Text(_s.imagesList), title: Text(l10n.imagesList),
subtitle: Text( subtitle: Text(
_s.dockerImagesFmt(Providers.docker.images!.length), l10n.dockerImagesFmt(Providers.docker.images!.length),
style: UIs.textGrey, style: UIs.textGrey,
), ),
), ),
@@ -256,12 +249,12 @@ class _DockerManagePageState extends State<DockerManagePage> {
void _showImageRmDialog(DockerImage e) { void _showImageRmDialog(DockerImage e) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(e.repo)), child: Text(l10n.sureDelete(e.repo)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -270,10 +263,10 @@ class _DockerManagePageState extends State<DockerManagePage> {
'docker rmi ${e.id} -f', 'docker rmi ${e.id} -f',
); );
if (result != null) { if (result != null) {
context.showSnackBar(result.message ?? _s.unknownError); context.showSnackBar(result.message ?? l10n.unknownError);
} }
}, },
child: Text(_s.ok, style: UIs.textRed), child: Text(l10n.ok, style: UIs.textRed),
), ),
], ],
); );
@@ -299,14 +292,14 @@ class _DockerManagePageState extends State<DockerManagePage> {
switch (err.type) { switch (err.type) {
case DockerErrType.notInstalled: case DockerErrType.notInstalled:
return UrlText( return UrlText(
text: _s.installDockerWithUrl, text: l10n.installDockerWithUrl,
replace: _s.install, replace: l10n.install,
); );
case DockerErrType.noClient: case DockerErrType.noClient:
return Text(_s.waitConnection); return Text(l10n.waitConnection);
case DockerErrType.invalidVersion: case DockerErrType.invalidVersion:
return UrlText( return UrlText(
text: _s.invalidVersionHelp(Urls.appHelp), text: l10n.invalidVersionHelp(Urls.appHelp),
replace: 'Github', replace: 'Github',
); );
case DockerErrType.parseImages: case DockerErrType.parseImages:
@@ -330,8 +323,8 @@ class _DockerManagePageState extends State<DockerManagePage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(Providers.docker.edition ?? _s.unknown), Text(Providers.docker.edition ?? l10n.unknown),
Text(Providers.docker.version ?? _s.unknown), Text(Providers.docker.version ?? l10n.unknown),
], ],
), ),
); );
@@ -340,7 +333,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
Widget _buildPs() { Widget _buildPs() {
final items = <Widget>[ final items = <Widget>[
ListTile( ListTile(
title: Text(_s.containerStatus), title: Text(l10n.containerStatus),
subtitle: Text( subtitle: Text(
_buildPsCardSubtitle(Providers.docker.items!), _buildPsCardSubtitle(Providers.docker.items!),
style: UIs.textGrey, style: UIs.textGrey,
@@ -367,17 +360,13 @@ class _DockerManagePageState extends State<DockerManagePage> {
Widget _buildMoreBtn(DockerPsItem dItem) { Widget _buildMoreBtn(DockerPsItem dItem) {
return PopupMenu( return PopupMenu(
items: DockerMenuType.items(dItem.running) items: DockerMenuType.items(dItem.running).map((e) => e.widget).toList(),
.map(
(e) => e.build(_s),
)
.toList(),
onSelected: (DockerMenuType item) async { onSelected: (DockerMenuType item) async {
switch (item) { switch (item) {
case DockerMenuType.rm: case DockerMenuType.rm:
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(dItem.name)), child: Text(l10n.sureDelete(dItem.name)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -386,7 +375,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
await Providers.docker.delete(dItem.containerId); await Providers.docker.delete(dItem.containerId);
context.pop(); context.pop();
}, },
child: Text(_s.ok), child: Text(l10n.ok),
) )
], ],
); );
@@ -421,7 +410,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
// case DockerMenuType.stats: // case DockerMenuType.stats:
// showRoundDialog( // showRoundDialog(
// context: context, // context: context,
// title: Text(_s.stats), // title: Text(l10n.stats),
// child: Text( // child: Text(
// 'CPU: ${dItem.cpu}\n' // 'CPU: ${dItem.cpu}\n'
// 'Mem: ${dItem.mem}\n' // 'Mem: ${dItem.mem}\n'
@@ -431,7 +420,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
// actions: [ // actions: [
// TextButton( // TextButton(
// onPressed: () => context.pop(), // onPressed: () => context.pop(),
// child: Text(_s.ok), // child: Text(l10n.ok),
// ), // ),
// ], // ],
// ); // );
@@ -445,9 +434,9 @@ class _DockerManagePageState extends State<DockerManagePage> {
final runningCount = running.where((element) => element.running).length; final runningCount = running.where((element) => element.running).length;
final stoped = running.length - runningCount; final stoped = running.length - runningCount;
if (stoped == 0) { if (stoped == 0) {
return _s.dockerStatusRunningFmt(runningCount); return l10n.dockerStatusRunningFmt(runningCount);
} }
return _s.dockerStatusRunningAndStoppedFmt(runningCount, stoped); return l10n.dockerStatusRunningAndStoppedFmt(runningCount, stoped);
} }
Widget _buildEditHost() { Widget _buildEditHost() {
@@ -456,7 +445,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
children.add(Padding( children.add(Padding(
padding: const EdgeInsets.fromLTRB(17, 17, 17, 0), padding: const EdgeInsets.fromLTRB(17, 17, 17, 0),
child: Text( child: Text(
_s.dockerEmptyRunningItems, l10n.dockerEmptyRunningItems,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
)); ));
@@ -464,7 +453,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
children.add( children.add(
TextButton( TextButton(
onPressed: _showEditHostDialog, onPressed: _showEditHostDialog,
child: Text(_s.dockerEditHost), child: Text(l10n.dockerEditHost),
), ),
); );
return Column( return Column(
@@ -477,7 +466,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
final host = Stores.docker.fetch(id) ?? 'unix:///run/user/1000/docker.sock'; final host = Stores.docker.fetch(id) ?? 'unix:///run/user/1000/docker.sock';
final ctrl = TextEditingController(text: host); final ctrl = TextEditingController(text: host);
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.dockerEditHost), title: Text(l10n.dockerEditHost),
child: Input( child: Input(
maxLines: 1, maxLines: 1,
controller: ctrl, controller: ctrl,
@@ -486,7 +475,7 @@ class _DockerManagePageState extends State<DockerManagePage> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => _onSaveDockerHost(ctrl.text), onPressed: () => _onSaveDockerHost(ctrl.text),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -3,12 +3,12 @@ import 'dart:io';
import 'package:code_text_field/code_text_field.dart'; import 'package:code_text_field/code_text_field.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_highlight/theme_map.dart';
import 'package:flutter_highlight/themes/a11y-light.dart'; import 'package:flutter_highlight/themes/a11y-light.dart';
import 'package:flutter_highlight/themes/monokai.dart'; import 'package:flutter_highlight/themes/monokai.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
import 'package:toolbox/data/res/highlight.dart'; import 'package:toolbox/data/res/highlight.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -47,7 +47,6 @@ class _EditorPageState extends State<EditorPage> {
late CodeController _controller; late CodeController _controller;
late Map<String, TextStyle> _codeTheme; late Map<String, TextStyle> _codeTheme;
late S _s;
late final _textStyle = late final _textStyle =
TextStyle(fontSize: Stores.setting.editorFontSize.fetch()); TextStyle(fontSize: Stores.setting.editorFontSize.fetch());
@@ -77,7 +76,6 @@ class _EditorPageState extends State<EditorPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
if (context.isDark) { if (context.isDark) {
_codeTheme = _codeTheme =
@@ -126,8 +124,8 @@ class _EditorPageState extends State<EditorPage> {
return CustomAppBar( return CustomAppBar(
centerTitle: true, centerTitle: true,
title: TwoLineText( title: TwoLineText(
up: widget.title ?? getFileName(widget.path) ?? _s.unknown, up: widget.title ?? getFileName(widget.path) ?? l10n.unknown,
down: _s.editor, down: l10n.editor,
), ),
actions: [ actions: [
PopupMenuButton<String>( PopupMenuButton<String>(

View File

@@ -4,9 +4,9 @@ import 'dart:math';
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:circle_chart/circle_chart.dart'; import 'package:circle_chart/circle_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/route.dart';
import 'package:toolbox/data/model/server/disk.dart'; import 'package:toolbox/data/model/server/disk.dart';
import 'package:toolbox/data/provider/server.dart'; import 'package:toolbox/data/provider/server.dart';
@@ -31,7 +31,6 @@ class FullScreenPage extends StatefulWidget {
} }
class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin { class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin {
late S _s;
late MediaQueryData _media; late MediaQueryData _media;
late ThemeData _theme; late ThemeData _theme;
late Timer _timer; late Timer _timer;
@@ -63,7 +62,6 @@ class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_theme = Theme.of(context); _theme = Theme.of(context);
} }
@@ -131,7 +129,7 @@ class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin {
child: TextButton( child: TextButton(
onPressed: () => AppRoute.serverEdit().go(context), onPressed: () => AppRoute.serverEdit().go(context),
child: Text( child: Text(
_s.addAServer, l10n.addAServer,
style: const TextStyle(fontSize: 27), style: const TextStyle(fontSize: 27),
)), )),
); );
@@ -143,7 +141,7 @@ class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin {
final id = pro.serverOrder[idx]; final id = pro.serverOrder[idx];
final s = pro.servers[id]; final s = pro.servers[id];
if (s == null) { if (s == null) {
return Center(child: Text(_s.noClient)); return Center(child: Text(l10n.noClient));
} }
return _buildRealServerCard(s.status, s.state, s.spi); return _buildRealServerCard(s.status, s.state, s.spi);
}, },
@@ -272,25 +270,25 @@ class _FullScreenPageState extends State<FullScreenPage> with AfterLayoutMixin {
) { ) {
switch (cs) { switch (cs) {
case ServerState.disconnected: case ServerState.disconnected:
return _s.disconnected; return l10n.disconnected;
case ServerState.connected: case ServerState.connected:
final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C'; final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
final items = [tempStr, upTime]; final items = [tempStr, upTime];
final str = items.where((element) => element.isNotEmpty).join(' | '); final str = items.where((element) => element.isNotEmpty).join(' | ');
if (str.isEmpty) return _s.serverTabLoading; if (str.isEmpty) return l10n.serverTabLoading;
return str; return str;
case ServerState.connecting: case ServerState.connecting:
return _s.serverTabConnecting; return l10n.serverTabConnecting;
case ServerState.failed: case ServerState.failed:
if (failedInfo == null) { if (failedInfo == null) {
return _s.serverTabFailed; return l10n.serverTabFailed;
} }
if (failedInfo.contains('encypted')) { if (failedInfo.contains('encypted')) {
return _s.serverTabPlzSave; return l10n.serverTabPlzSave;
} }
return failedInfo; return failedInfo;
default: default:
return _s.serverTabUnkown; return l10n.serverTabUnkown;
} }
} }

View File

@@ -7,6 +7,7 @@ import 'package:get_it/get_it.dart';
import 'package:toolbox/core/channel/bg_run.dart'; import 'package:toolbox/core/channel/bg_run.dart';
import 'package:toolbox/core/channel/home_widget.dart'; import 'package:toolbox/core/channel/home_widget.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/utils/platform/auth.dart'; import 'package:toolbox/core/utils/platform/auth.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/res/github_id.dart'; import 'package:toolbox/data/res/github_id.dart';
@@ -44,7 +45,6 @@ class _HomePageState extends State<HomePage>
late final PageController _pageController; late final PageController _pageController;
final _selectIndex = ValueNotifier(0); final _selectIndex = ValueNotifier(0);
late S _s;
bool _switchingPage = false; bool _switchingPage = false;
bool _isAuthing = false; bool _isAuthing = false;
@@ -65,7 +65,7 @@ class _HomePageState extends State<HomePage>
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!; l10n = S.of(context)!;
} }
@override @override
@@ -133,7 +133,7 @@ class _HomePageState extends State<HomePage>
final actions = <Widget>[ final actions = <Widget>[
IconButton( IconButton(
icon: const Icon(Icons.developer_mode, size: 23), icon: const Icon(Icons.developer_mode, size: 23),
tooltip: _s.debug, tooltip: l10n.debug,
onPressed: () => AppRoute.debug().go(context), onPressed: () => AppRoute.debug().go(context),
), ),
]; ];
@@ -182,12 +182,12 @@ class _HomePageState extends State<HomePage>
destinations: [ destinations: [
NavigationDestination( NavigationDestination(
icon: const Icon(Icons.cloud_outlined), icon: const Icon(Icons.cloud_outlined),
label: _s.server, label: l10n.server,
selectedIcon: const Icon(Icons.cloud), selectedIcon: const Icon(Icons.cloud),
), ),
NavigationDestination( NavigationDestination(
icon: const Icon(Icons.snippet_folder_outlined), icon: const Icon(Icons.snippet_folder_outlined),
label: _s.snippet, label: l10n.snippet,
selectedIcon: const Icon(Icons.snippet_folder), selectedIcon: const Icon(Icons.snippet_folder),
), ),
const NavigationDestination( const NavigationDestination(
@@ -232,28 +232,28 @@ class _HomePageState extends State<HomePage>
children: [ children: [
ListTile( ListTile(
leading: const Icon(Icons.settings), leading: const Icon(Icons.settings),
title: Text(_s.setting), title: Text(l10n.setting),
onTap: () => AppRoute.settings().go(context), onTap: () => AppRoute.settings().go(context),
onLongPress: _onLongPressSetting, onLongPress: _onLongPressSetting,
), ),
ListTile( ListTile(
leading: const Icon(Icons.vpn_key), leading: const Icon(Icons.vpn_key),
title: Text(_s.privateKey), title: Text(l10n.privateKey),
onTap: () => AppRoute.keyList().go(context), onTap: () => AppRoute.keyList().go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.file_open), leading: const Icon(Icons.file_open),
title: Text(_s.files), title: Text(l10n.files),
onTap: () => AppRoute.localStorage().go(context), onTap: () => AppRoute.localStorage().go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.import_export), leading: const Icon(Icons.import_export),
title: Text(_s.backupAndRestore), title: Text(l10n.backupAndRestore),
onTap: () => AppRoute.backup().go(context), onTap: () => AppRoute.backup().go(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.text_snippet), leading: const Icon(Icons.text_snippet),
title: Text('${_s.about} & ${_s.feedback}'), title: Text('${l10n.about} & ${l10n.feedback}'),
onTap: _showAboutDialog, onTap: _showAboutDialog,
) )
].map((e) => RoundRectCard(e)).toList(), ].map((e) => RoundRectCard(e)).toList(),
@@ -263,7 +263,7 @@ class _HomePageState extends State<HomePage>
void _showAboutDialog() { void _showAboutDialog() {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.about), title: Text(l10n.about),
child: _buildAboutContent(), child: _buildAboutContent(),
actions: [ actions: [
TextButton( TextButton(
@@ -272,11 +272,11 @@ class _HomePageState extends State<HomePage>
), ),
TextButton( TextButton(
onPressed: () => openUrl(Urls.appHelp), onPressed: () => openUrl(Urls.appHelp),
child: Text(_s.feedback), child: Text(l10n.feedback),
), ),
TextButton( TextButton(
onPressed: () => showLicensePage(context: context), onPressed: () => showLicensePage(context: context),
child: Text(_s.license), child: Text(l10n.license),
), ),
], ],
); );
@@ -289,12 +289,12 @@ class _HomePageState extends State<HomePage>
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
UrlText( UrlText(
text: _s.madeWithLove(Urls.myGithub), text: l10n.madeWithLove(Urls.myGithub),
replace: 'lollipopkit', replace: 'lollipopkit',
), ),
UIs.height13, UIs.height13,
// Use [UrlText] for same text style // Use [UrlText] for same text style
Text(_s.aboutThanks), Text(l10n.aboutThanks),
UIs.height13, UIs.height13,
const Text('Contributors:'), const Text('Contributors:'),
...GithubIds.contributors.map( ...GithubIds.contributors.map(
@@ -365,7 +365,7 @@ class _HomePageState extends State<HomePage>
final result = await AppRoute.editor( final result = await AppRoute.editor(
text: text, text: text,
langCode: 'json', langCode: 'json',
title: _s.setting, title: l10n.setting,
).go(context); ).go(context);
if (result == null) { if (result == null) {
return; return;
@@ -380,8 +380,8 @@ class _HomePageState extends State<HomePage>
} }
} catch (e, trace) { } catch (e, trace) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text('${_s.save}:\n$e'), child: Text('${l10n.save}:\n$e'),
); );
Loggers.app.warning('Update json settings failed', e, trace); Loggers.app.warning('Update json settings failed', e, trace);
} }
@@ -391,7 +391,7 @@ class _HomePageState extends State<HomePage>
if (Stores.setting.useBioAuth.fetch()) { if (Stores.setting.useBioAuth.fetch()) {
if (!_isAuthing) { if (!_isAuthing) {
_isAuthing = true; _isAuthing = true;
BioAuth.auth(_s.authRequired).then( BioAuth.auth(l10n.authRequired).then(
(val) { (val) {
switch (val) { switch (val) {
case AuthResult.success: case AuthResult.success:

View File

@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/uint8list.dart'; import 'package:toolbox/core/extension/uint8list.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
@@ -31,8 +31,6 @@ class _PingPageState extends State<PingPage>
with AutomaticKeepAliveClientMixin, AfterLayoutMixin { with AutomaticKeepAliveClientMixin, AfterLayoutMixin {
late TextEditingController _textEditingController; late TextEditingController _textEditingController;
final _results = ValueNotifier(<PingResult>[]); final _results = ValueNotifier(<PingResult>[]);
late S _s;
bool get isInit => _results.value.isEmpty; bool get isInit => _results.value.isEmpty;
@override @override
@@ -41,12 +39,6 @@ class _PingPageState extends State<PingPage>
_textEditingController = TextEditingController(text: ''); _textEditingController = TextEditingController(text: '');
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
@@ -71,16 +63,16 @@ class _PingPageState extends State<PingPage>
heroTag: 'ping', heroTag: 'ping',
onPressed: () { onPressed: () {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.choose), title: Text(l10n.choose),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
controller: _textEditingController, controller: _textEditingController,
hint: _s.inputDomainHere, hint: l10n.inputDomainHere,
maxLines: 1, maxLines: 1,
onSubmitted: (_) => _doPing(), onSubmitted: (_) => _doPing(),
), ),
actions: [ actions: [
TextButton(onPressed: _doPing, child: Text(_s.ok)), TextButton(onPressed: _doPing, child: Text(l10n.ok)),
], ],
); );
}, },
@@ -94,12 +86,12 @@ class _PingPageState extends State<PingPage>
await doPing(); await doPing();
} catch (e) { } catch (e) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text(e.toString()), child: Text(e.toString()),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => copy2Clipboard(e.toString()), onPressed: () => copy2Clipboard(e.toString()),
child: Text(_s.copy), child: Text(l10n.copy),
), ),
], ],
); );
@@ -111,7 +103,7 @@ class _PingPageState extends State<PingPage>
if (isInit) { if (isInit) {
return Center( return Center(
child: Text( child: Text(
_s.noResult, l10n.noResult,
style: const TextStyle(fontSize: 18), style: const TextStyle(fontSize: 18),
), ),
); );
@@ -125,8 +117,8 @@ class _PingPageState extends State<PingPage>
} }
Widget _buildResultItem(PingResult result) { Widget _buildResultItem(PingResult result) {
final unknown = _s.unknown; final unknown = l10n.unknown;
final ms = _s.ms; final ms = l10n.ms;
return RoundRectCard( return RoundRectCard(
ListTile( ListTile(
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17), contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
@@ -143,7 +135,7 @@ class _PingPageState extends State<PingPage>
style: UIs.textSize11, style: UIs.textSize11,
), ),
trailing: Text( trailing: Text(
'${_s.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? _s.unknown} $ms', '${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
color: primaryColor, color: primaryColor,
@@ -156,13 +148,13 @@ class _PingPageState extends State<PingPage>
String _buildPingSummary(PingResult result, String unknown, String ms) { String _buildPingSummary(PingResult result, String unknown, String ms) {
final ip = result.ip ?? unknown; final ip = result.ip ?? unknown;
if (result.results == null || result.results!.isEmpty) { if (result.results == null || result.results!.isEmpty) {
return '$ip - ${_s.noResult}'; return '$ip - ${l10n.noResult}';
} }
final ttl = result.results?.first.ttl ?? unknown; final ttl = result.results?.first.ttl ?? unknown;
final loss = result.statistic?.loss ?? unknown; final loss = result.statistic?.loss ?? unknown;
final min = result.statistic?.min ?? unknown; final min = result.statistic?.min ?? unknown;
final max = result.statistic?.max ?? unknown; final max = result.statistic?.max ?? unknown;
return '$ip\n${_s.ttl}: $ttl, ${_s.loss}: $loss%\n${_s.min}: $min $ms, ${_s.max}: $max $ms'; return '$ip\n${l10n.ttl}: $ttl, ${l10n.loss}: $loss%\n${l10n.min}: $min $ms, ${l10n.max}: $max $ms';
} }
Future<void> doPing() async { Future<void> doPing() async {
@@ -170,18 +162,18 @@ class _PingPageState extends State<PingPage>
_results.value.clear(); _results.value.clear();
final target = _textEditingController.text.trim(); final target = _textEditingController.text.trim();
if (target.isEmpty) { if (target.isEmpty) {
context.showSnackBar(_s.pingInputIP); context.showSnackBar(l10n.pingInputIP);
return; return;
} }
if (Providers.server.servers.isEmpty) { if (Providers.server.servers.isEmpty) {
context.showSnackBar(_s.pingNoServer); context.showSnackBar(l10n.pingNoServer);
return; return;
} }
/// avoid ping command injection /// avoid ping command injection
if (!targetReg.hasMatch(target)) { if (!targetReg.hasMatch(target)) {
context.showSnackBar(_s.pingInputIP); context.showSnackBar(l10n.pingInputIP);
return; return;
} }

View File

@@ -3,9 +3,9 @@ import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/numx.dart'; import 'package:toolbox/core/extension/numx.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
@@ -38,7 +38,6 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
final _pwdNode = FocusNode(); final _pwdNode = FocusNode();
late FocusScopeNode _focusScope; late FocusScopeNode _focusScope;
late S _s;
Widget? _loading; Widget? _loading;
@@ -73,7 +72,6 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_focusScope = FocusScope.of(context); _focusScope = FocusScope.of(context);
} }
@@ -89,11 +87,11 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
PreferredSizeWidget _buildAppBar() { PreferredSizeWidget _buildAppBar() {
final actions = [ final actions = [
IconButton( IconButton(
tooltip: _s.delete, tooltip: l10n.delete,
onPressed: () { onPressed: () {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(widget.pki!.id)), child: Text(l10n.sureDelete(widget.pki!.id)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
@@ -102,7 +100,7 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
context.pop(); context.pop();
}, },
child: Text( child: Text(
_s.ok, l10n.ok,
style: UIs.textRed, style: UIs.textRed,
), ),
), ),
@@ -113,20 +111,20 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
) )
]; ];
return CustomAppBar( return CustomAppBar(
title: Text(_s.edit, style: UIs.textSize18), title: Text(l10n.edit, style: UIs.textSize18),
actions: widget.pki == null ? null : actions, actions: widget.pki == null ? null : actions,
); );
} }
Widget _buildFAB() { Widget _buildFAB() {
return FloatingActionButton( return FloatingActionButton(
tooltip: _s.save, tooltip: l10n.save,
onPressed: () async { onPressed: () async {
final name = _nameController.text; final name = _nameController.text;
final key = _keyController.text.trim(); final key = _keyController.text.trim();
final pwd = _pwdController.text; final pwd = _pwdController.text;
if (name.isEmpty || key.isEmpty) { if (name.isEmpty || key.isEmpty) {
context.showSnackBar(_s.fieldMustNotEmpty); context.showSnackBar(l10n.fieldMustNotEmpty);
return; return;
} }
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
@@ -165,7 +163,7 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
type: TextInputType.text, type: TextInputType.text,
node: _nameNode, node: _nameNode,
onSubmitted: (_) => _focusScope.requestFocus(_keyNode), onSubmitted: (_) => _focusScope.requestFocus(_keyNode),
label: _s.name, label: l10n.name,
icon: Icons.info, icon: Icons.info,
), ),
Input( Input(
@@ -175,26 +173,26 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
type: TextInputType.text, type: TextInputType.text,
node: _keyNode, node: _keyNode,
onSubmitted: (_) => _focusScope.requestFocus(_pwdNode), onSubmitted: (_) => _focusScope.requestFocus(_pwdNode),
label: _s.privateKey, label: l10n.privateKey,
icon: Icons.vpn_key, icon: Icons.vpn_key,
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
final path = await pickOneFile(); final path = await pickOneFile();
if (path == null) { if (path == null) {
context.showSnackBar(_s.fieldMustNotEmpty); context.showSnackBar(l10n.fieldMustNotEmpty);
return; return;
} }
final file = File(path); final file = File(path);
if (!file.existsSync()) { if (!file.existsSync()) {
context.showSnackBar(_s.fileNotExist(path)); context.showSnackBar(l10n.fileNotExist(path));
return; return;
} }
final size = (await file.stat()).size; final size = (await file.stat()).size;
if (size > Miscs.privateKeyMaxSize) { if (size > Miscs.privateKeyMaxSize) {
context.showSnackBar( context.showSnackBar(
_s.fileTooLarge( l10n.fileTooLarge(
path, path,
size.convertBytes, size.convertBytes,
Miscs.privateKeyMaxSize.convertBytes, Miscs.privateKeyMaxSize.convertBytes,
@@ -205,14 +203,14 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
_keyController.text = await file.readAsString(); _keyController.text = await file.readAsString();
}, },
child: Text(_s.pickFile), child: Text(l10n.pickFile),
), ),
Input( Input(
controller: _pwdController, controller: _pwdController,
type: TextInputType.text, type: TextInputType.text,
node: _pwdNode, node: _pwdNode,
obscureText: true, obscureText: true,
label: _s.pwd, label: l10n.pwd,
icon: Icons.password, icon: Icons.password,
), ),
SizedBox(height: MediaQuery.of(context).size.height * 0.1), SizedBox(height: MediaQuery.of(context).size.height * 0.1),

View File

@@ -2,10 +2,10 @@ import 'dart:io';
import 'dart:async'; import 'dart:async';
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/core/utils/platform/path.dart'; import 'package:toolbox/core/utils/platform/path.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -26,19 +26,11 @@ class PrivateKeysListPage extends StatefulWidget {
class _PrivateKeyListState extends State<PrivateKeysListPage> class _PrivateKeyListState extends State<PrivateKeysListPage>
with AfterLayoutMixin { with AfterLayoutMixin {
late S _s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.privateKey, style: UIs.textSize18), title: Text(l10n.privateKey, style: UIs.textSize18),
), ),
body: _buildBody(), body: _buildBody(),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
@@ -53,7 +45,7 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
builder: (_, key, __) { builder: (_, key, __) {
if (key.pkis.isEmpty) { if (key.pkis.isEmpty) {
return Center( return Center(
child: Text(_s.noSavedPrivateKey), child: Text(l10n.noSavedPrivateKey),
); );
} }
return ListView.builder( return ListView.builder(
@@ -71,7 +63,7 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
), ),
), ),
title: Text(item.id), title: Text(item.id),
subtitle: Text(item.type ?? _s.unknown, style: UIs.textGrey), subtitle: Text(item.type ?? l10n.unknown, style: UIs.textGrey),
onTap: () => AppRoute.keyEdit(pki: item).go(context), onTap: () => AppRoute.keyEdit(pki: item).go(context),
trailing: const Icon(Icons.edit), trailing: const Icon(Icons.edit),
), ),
@@ -94,19 +86,19 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
key: idRsaFile.readAsStringSync(), key: idRsaFile.readAsStringSync(),
); );
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.addSystemPrivateKeyTip), child: Text(l10n.addSystemPrivateKeyTip),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
context.pop(); context.pop();
AppRoute.keyEdit(pki: sysPk).go(context); AppRoute.keyEdit(pki: sysPk).go(context);
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
TextButton( TextButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
], ],
); );

View File

@@ -2,9 +2,9 @@ import 'dart:async';
import 'package:dartssh2/dartssh2.dart'; import 'package:dartssh2/dartssh2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/uint8list.dart'; import 'package:toolbox/core/extension/uint8list.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
@@ -28,7 +28,6 @@ class ProcessPage extends StatefulWidget {
} }
class _ProcessPageState extends State<ProcessPage> { class _ProcessPageState extends State<ProcessPage> {
late S _s;
late Timer _timer; late Timer _timer;
late MediaQueryData _media; late MediaQueryData _media;
@@ -55,7 +54,6 @@ class _ProcessPageState extends State<ProcessPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
} }
@@ -63,7 +61,7 @@ class _ProcessPageState extends State<ProcessPage> {
if (mounted) { if (mounted) {
final result = await _client?.run(AppShellFuncType.process.exec).string; final result = await _client?.run(AppShellFuncType.process.exec).string;
if (result == null || result.isEmpty) { if (result == null || result.isEmpty) {
context.showSnackBar(_s.noResult); context.showSnackBar(l10n.noResult);
return; return;
} }
_result = PsResult.parse(result, sort: _procSortMode); _result = PsResult.parse(result, sort: _procSortMode);
@@ -110,12 +108,12 @@ class _ProcessPageState extends State<ProcessPage> {
actions.add(IconButton( actions.add(IconButton(
icon: const Icon(Icons.error), icon: const Icon(Icons.error),
onPressed: () => context.showRoundDialog( onPressed: () => context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: SingleChildScrollView(child: Text(_result.error!)), child: SingleChildScrollView(child: Text(_result.error!)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => copy2Clipboard(_result.error!), onPressed: () => copy2Clipboard(_result.error!),
child: Text(_s.copy), child: Text(l10n.copy),
), ),
], ],
), ),
@@ -134,7 +132,7 @@ class _ProcessPageState extends State<ProcessPage> {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
centerTitle: true, centerTitle: true,
title: TwoLineText(up: widget.spi.name, down: _s.process), title: TwoLineText(up: widget.spi.name, down: l10n.process),
actions: actions, actions: actions,
), ),
body: child, body: child,
@@ -162,8 +160,8 @@ class _ProcessPageState extends State<ProcessPage> {
onTap: () => _lastFocusId = proc.pid, onTap: () => _lastFocusId = proc.pid,
onLongPress: () { onLongPress: () {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureStop(proc.pid)), child: Text(l10n.sureStop(proc.pid)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -171,7 +169,7 @@ class _ProcessPageState extends State<ProcessPage> {
await _refresh(); await _refresh();
context.pop(); context.pop();
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/data/model/server/cpu.dart'; import 'package:toolbox/data/model/server/cpu.dart';
import 'package:toolbox/data/model/server/net_speed.dart'; import 'package:toolbox/data/model/server/net_speed.dart';
@@ -34,7 +34,6 @@ class ServerDetailPage extends StatefulWidget {
class _ServerDetailPageState extends State<ServerDetailPage> class _ServerDetailPageState extends State<ServerDetailPage>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
late MediaQueryData _media; late MediaQueryData _media;
late S _s;
final Order<String> _cardsOrder = []; final Order<String> _cardsOrder = [];
late final _textFactor = Stores.setting.textFactor.fetch(); late final _textFactor = Stores.setting.textFactor.fetch();
@@ -58,7 +57,6 @@ class _ServerDetailPageState extends State<ServerDetailPage>
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_s = S.of(context)!;
} }
@override @override
@@ -74,7 +72,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
if (s == null) { if (s == null) {
return Scaffold( return Scaffold(
body: Center( body: Center(
child: Text(_s.noClient), child: Text(l10n.noClient),
), ),
); );
} }
@@ -108,7 +106,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
itemCount: buildFuncs ? _cardsOrder.length + 1 : _cardsOrder.length, itemCount: buildFuncs ? _cardsOrder.length + 1 : _cardsOrder.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == 0 && buildFuncs) { if (index == 0 && buildFuncs) {
return ServerFuncBtns(spi: widget.spi, s: _s, iconSize: 19); return ServerFuncBtns(spi: widget.spi, iconSize: 19);
} }
if (buildFuncs) index--; if (buildFuncs) index--;
return _cardBuildMap[_cardsOrder[index]]?.call(si.status); return _cardBuildMap[_cardsOrder[index]]?.call(si.status);
@@ -369,7 +367,7 @@ class _ServerDetailPageState extends State<ServerDetailPage>
if (ns.devices.isEmpty) { if (ns.devices.isEmpty) {
children.add(Center( children.add(Center(
child: Text( child: Text(
_s.noInterface, l10n.noInterface,
style: const TextStyle(color: Colors.grey, fontSize: 13), style: const TextStyle(color: Colors.grey, fontSize: 13),
), ),
)); ));

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
@@ -40,7 +40,6 @@ class _ServerEditPageState extends State<ServerEditPage> {
final _usernameFocus = FocusNode(); final _usernameFocus = FocusNode();
late FocusScopeNode _focusScope; late FocusScopeNode _focusScope;
late S _s;
final _keyIdx = ValueNotifier<int?>(null); final _keyIdx = ValueNotifier<int?>(null);
final _autoConnect = ValueNotifier(true); final _autoConnect = ValueNotifier(true);
@@ -95,7 +94,6 @@ class _ServerEditPageState extends State<ServerEditPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_focusScope = FocusScope.of(context); _focusScope = FocusScope.of(context);
} }
@@ -112,8 +110,8 @@ class _ServerEditPageState extends State<ServerEditPage> {
final delBtn = IconButton( final delBtn = IconButton(
onPressed: () { onPressed: () {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureToDeleteServer(widget.spi!.name)), child: Text(l10n.sureToDeleteServer(widget.spi!.name)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
@@ -121,7 +119,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
context.pop(); context.pop();
context.pop(true); context.pop(true);
}, },
child: Text(_s.ok, style: UIs.textRed), child: Text(l10n.ok, style: UIs.textRed),
), ),
], ],
); );
@@ -130,7 +128,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
); );
final actions = widget.spi != null ? [delBtn] : null; final actions = widget.spi != null ? [delBtn] : null;
return CustomAppBar( return CustomAppBar(
title: Text(_s.edit, style: UIs.textSize18), title: Text(l10n.edit, style: UIs.textSize18),
actions: actions, actions: actions,
); );
} }
@@ -143,8 +141,8 @@ class _ServerEditPageState extends State<ServerEditPage> {
type: TextInputType.text, type: TextInputType.text,
node: _nameFocus, node: _nameFocus,
onSubmitted: (_) => _focusScope.requestFocus(_ipFocus), onSubmitted: (_) => _focusScope.requestFocus(_ipFocus),
hint: _s.exampleName, hint: l10n.exampleName,
label: _s.name, label: l10n.name,
icon: Icons.info, icon: Icons.info,
), ),
Input( Input(
@@ -152,7 +150,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
type: TextInputType.text, type: TextInputType.text,
onSubmitted: (_) => _focusScope.requestFocus(_portFocus), onSubmitted: (_) => _focusScope.requestFocus(_portFocus),
node: _ipFocus, node: _ipFocus,
label: _s.host, label: l10n.host,
icon: Icons.computer, icon: Icons.computer,
hint: 'example.com', hint: 'example.com',
), ),
@@ -161,7 +159,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
type: TextInputType.number, type: TextInputType.number,
node: _portFocus, node: _portFocus,
onSubmitted: (_) => _focusScope.requestFocus(_usernameFocus), onSubmitted: (_) => _focusScope.requestFocus(_usernameFocus),
label: _s.port, label: l10n.port,
icon: Icons.format_list_numbered, icon: Icons.format_list_numbered,
hint: '22', hint: '22',
), ),
@@ -170,7 +168,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
type: TextInputType.text, type: TextInputType.text,
node: _usernameFocus, node: _usernameFocus,
onSubmitted: (_) => _focusScope.requestFocus(_alterUrlFocus), onSubmitted: (_) => _focusScope.requestFocus(_alterUrlFocus),
label: _s.user, label: l10n.user,
icon: Icons.account_box, icon: Icons.account_box,
hint: 'root', hint: 'root',
), ),
@@ -178,20 +176,19 @@ class _ServerEditPageState extends State<ServerEditPage> {
controller: _altUrlController, controller: _altUrlController,
type: TextInputType.text, type: TextInputType.text,
node: _alterUrlFocus, node: _alterUrlFocus,
label: _s.alterUrl, label: l10n.alterUrl,
icon: Icons.computer, icon: Icons.computer,
hint: 'user@ip:port', hint: 'user@ip:port',
), ),
TagEditor( TagEditor(
tags: _tags, tags: _tags,
onChanged: (p0) => _tags = p0, onChanged: (p0) => _tags = p0,
s: _s,
allTags: [...Providers.server.tags], allTags: [...Providers.server.tags],
onRenameTag: Providers.server.renameTag, onRenameTag: Providers.server.renameTag,
), ),
_buildAuth(), _buildAuth(),
ListTile( ListTile(
title: Text(_s.autoConnect), title: Text(l10n.autoConnect),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _autoConnect, listenable: _autoConnect,
build: () => Switch( build: () => Switch(
@@ -215,7 +212,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
Widget _buildAuth() { Widget _buildAuth() {
final switch_ = ListTile( final switch_ = ListTile(
title: Text(_s.keyAuth), title: Text(l10n.keyAuth),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _keyIdx, listenable: _keyIdx,
build: () => Switch( build: () => Switch(
@@ -243,9 +240,9 @@ class _ServerEditPageState extends State<ServerEditPage> {
controller: _passwordController, controller: _passwordController,
obscureText: true, obscureText: true,
type: TextInputType.text, type: TextInputType.text,
label: _s.pwd, label: l10n.pwd,
icon: Icons.password, icon: Icons.password,
hint: _s.pwd, hint: l10n.pwd,
onSubmitted: (_) => _onSave(), onSubmitted: (_) => _onSave(),
)); ));
} }
@@ -267,7 +264,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
), ),
title: Text(e.id, textAlign: TextAlign.start), title: Text(e.id, textAlign: TextAlign.start),
subtitle: Text( subtitle: Text(
e.type ?? _s.unknown, e.type ?? l10n.unknown,
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: UIs.textGrey, style: UIs.textGrey,
), ),
@@ -276,7 +273,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
}); });
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(_s.addPrivateKey), title: Text(l10n.addPrivateKey),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
trailing: IconButton( trailing: IconButton(
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
@@ -319,21 +316,21 @@ class _ServerEditPageState extends State<ServerEditPage> {
void _onSave() async { void _onSave() async {
if (_ipController.text == '') { if (_ipController.text == '') {
context.showSnackBar(_s.plzEnterHost); context.showSnackBar(l10n.plzEnterHost);
return; return;
} }
if (_keyIdx.value == null && _passwordController.text == '') { if (_keyIdx.value == null && _passwordController.text == '') {
final cancel = await context.showRoundDialog<bool>( final cancel = await context.showRoundDialog<bool>(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureNoPwd), child: Text(l10n.sureNoPwd),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(false), onPressed: () => context.pop(false),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
TextButton( TextButton(
onPressed: () => context.pop(true), onPressed: () => context.pop(true),
child: Text(_s.cancel), child: Text(l10n.cancel),
) )
], ],
); );
@@ -343,7 +340,7 @@ class _ServerEditPageState extends State<ServerEditPage> {
} }
// If [_pubKeyIndex] is -1, it means that the user has not selected // If [_pubKeyIndex] is -1, it means that the user has not selected
if (_keyIdx.value == -1) { if (_keyIdx.value == -1) {
context.showSnackBar(_s.plzSelectKey); context.showSnackBar(l10n.plzSelectKey);
return; return;
} }
if (_usernameController.text.isEmpty) { if (_usernameController.text.isEmpty) {

View File

@@ -1,10 +1,10 @@
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:circle_chart/circle_chart.dart'; import 'package:circle_chart/circle_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/media_queryx.dart'; import 'package:toolbox/core/extension/media_queryx.dart';
import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/extension/ssh_client.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
@@ -36,7 +36,6 @@ class ServerPage extends StatefulWidget {
class _ServerPageState extends State<ServerPage> class _ServerPageState extends State<ServerPage>
with AutomaticKeepAliveClientMixin, AfterLayoutMixin { with AutomaticKeepAliveClientMixin, AfterLayoutMixin {
late MediaQueryData _media; late MediaQueryData _media;
late S _s;
final _flipedCardIds = <String>{}; final _flipedCardIds = <String>{};
@@ -48,7 +47,6 @@ class _ServerPageState extends State<ServerPage>
super.didChangeDependencies(); super.didChangeDependencies();
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_useDoubleColumn = _media.useDoubleColumn; _useDoubleColumn = _media.useDoubleColumn;
_s = S.of(context)!;
} }
@override @override
@@ -58,7 +56,7 @@ class _ServerPageState extends State<ServerPage>
body: _buildBody(), body: _buildBody(),
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
onPressed: () => AppRoute.serverEdit().go(context), onPressed: () => AppRoute.serverEdit().go(context),
tooltip: _s.addAServer, tooltip: l10n.addAServer,
heroTag: 'server', heroTag: 'server',
child: const Icon(Icons.add), child: const Icon(Icons.add),
), ),
@@ -74,7 +72,7 @@ class _ServerPageState extends State<ServerPage>
if (pro.serverOrder.isEmpty) { if (pro.serverOrder.isEmpty) {
return Center( return Center(
child: Text( child: Text(
_s.serverTabEmpty, l10n.serverTabEmpty,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
); );
@@ -108,7 +106,7 @@ class _ServerPageState extends State<ServerPage>
_tag = p0; _tag = p0;
}), }),
initTag: _tag, initTag: _tag,
all: _s.all, all: l10n.all,
); );
} }
@@ -294,7 +292,7 @@ class _ServerPageState extends State<ServerPage>
!Stores.setting.serverTabUseOldUI.fetch()) !Stores.setting.serverTabUseOldUI.fetch())
SizedBox( SizedBox(
height: 27, height: 27,
child: ServerFuncBtns(spi: spi, s: _s), child: ServerFuncBtns(spi: spi),
), ),
]; ];
} }
@@ -318,7 +316,7 @@ class _ServerPageState extends State<ServerPage>
), ),
); );
} else if (Stores.setting.serverTabUseOldUI.fetch()) { } else if (Stores.setting.serverTabUseOldUI.fetch()) {
rightCorner = ServerFuncBtnsTopRight(spi: spi, s: _s); rightCorner = ServerFuncBtnsTopRight(spi: spi);
} }
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 7), padding: const EdgeInsets.symmetric(horizontal: 7),
@@ -361,7 +359,7 @@ class _ServerPageState extends State<ServerPage>
return GestureDetector( return GestureDetector(
onTap: () => _showFailReason(ss), onTap: () => _showFailReason(ss),
child: Text( child: Text(
_s.viewErr, l10n.viewErr,
style: UIs.textSize11Grey, style: UIs.textSize11Grey,
textScaleFactor: 1.0, textScaleFactor: 1.0,
), ),
@@ -376,14 +374,14 @@ class _ServerPageState extends State<ServerPage>
void _showFailReason(ServerStatus ss) { void _showFailReason(ServerStatus ss) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Text(ss.failedInfo ?? _s.unknownError), child: Text(ss.failedInfo ?? l10n.unknownError),
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => copy2Clipboard(ss.failedInfo!), onPressed: () => copy2Clipboard(ss.failedInfo!),
child: Text(_s.copy), child: Text(l10n.copy),
) )
], ],
); );
@@ -478,25 +476,25 @@ class _ServerPageState extends State<ServerPage>
) { ) {
switch (cs) { switch (cs) {
case ServerState.disconnected: case ServerState.disconnected:
return _s.disconnected; return l10n.disconnected;
case ServerState.finished: case ServerState.finished:
final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C'; final tempStr = temp == null ? '' : '${temp.toStringAsFixed(1)}°C';
final items = [tempStr, upTime]; final items = [tempStr, upTime];
final str = items.where((element) => element.isNotEmpty).join(' | '); final str = items.where((element) => element.isNotEmpty).join(' | ');
if (str.isEmpty) return _s.noResult; if (str.isEmpty) return l10n.noResult;
return str; return str;
case ServerState.loading: case ServerState.loading:
return _s.serverTabLoading; return l10n.serverTabLoading;
case ServerState.connected: case ServerState.connected:
return _s.connected; return l10n.connected;
case ServerState.connecting: case ServerState.connecting:
return _s.serverTabConnecting; return l10n.serverTabConnecting;
case ServerState.failed: case ServerState.failed:
if (failedInfo == null) { if (failedInfo == null) {
return _s.serverTabFailed; return l10n.serverTabFailed;
} }
if (failedInfo.contains('encypted')) { if (failedInfo.contains('encypted')) {
return _s.serverTabPlzSave; return l10n.serverTabPlzSave;
} }
return failedInfo; return failedInfo;
} }

View File

@@ -1,10 +1,10 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import 'package:toolbox/view/widget/custom_appbar.dart'; import 'package:toolbox/view/widget/custom_appbar.dart';
@@ -20,15 +20,8 @@ class AndroidSettingsPage extends StatefulWidget {
} }
class _AndroidSettingsPageState extends State<AndroidSettingsPage> { class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
late S _s;
late SharedPreferences _sp; late SharedPreferences _sp;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -53,7 +46,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
Widget _buildBgRun() { Widget _buildBgRun() {
return ListTile( return ListTile(
title: Text(_s.bgRun), title: Text(l10n.bgRun),
trailing: StoreSwitch(prop: Stores.setting.bgRun), trailing: StoreSwitch(prop: Stores.setting.bgRun),
); );
} }
@@ -69,7 +62,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
map.forEach((key, value) { map.forEach((key, value) {
_sp.setString(key, value); _sp.setString(key, value);
}); });
context.showSnackBar(_s.success); context.showSnackBar(l10n.success);
} catch (e) { } catch (e) {
context.showSnackBar(e.toString()); context.showSnackBar(e.toString());
} }
@@ -77,7 +70,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
Widget _buildAndroidWidgetSharedPreference() { Widget _buildAndroidWidgetSharedPreference() {
return ListTile( return ListTile(
title: Text(_s.homeWidgetUrlConfig), title: Text(l10n.homeWidgetUrlConfig),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () { onTap: () {
final data = <String, String>{}; final data = <String, String>{};
@@ -89,7 +82,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
}); });
final ctrl = TextEditingController(text: json.encode(data)); final ctrl = TextEditingController(text: json.encode(data));
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.homeWidgetUrlConfig), title: Text(l10n.homeWidgetUrlConfig),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
controller: ctrl, controller: ctrl,
@@ -103,7 +96,7 @@ class _AndroidSettingsPageState extends State<AndroidSettingsPage> {
onPressed: () { onPressed: () {
_saveWidgetSP(ctrl.text, data); _saveWidgetSP(ctrl.text, data);
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -1,11 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_highlight/theme_map.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/colorx.dart'; import 'package:toolbox/core/extension/colorx.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/locale.dart'; import 'package:toolbox/core/extension/locale.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
@@ -53,8 +54,6 @@ class _SettingPageState extends State<SettingPage> {
final _netViewTypeKey = GlobalKey<PopupMenuButtonState<NetViewType>>(); final _netViewTypeKey = GlobalKey<PopupMenuButtonState<NetViewType>>();
final _setting = Stores.setting; final _setting = Stores.setting;
late S _s;
final _selectedColorValue = ValueNotifier(0); final _selectedColorValue = ValueNotifier(0);
final _nightMode = ValueNotifier(0); final _nightMode = ValueNotifier(0);
final _maxRetryCount = ValueNotifier(0); final _maxRetryCount = ValueNotifier(0);
@@ -71,10 +70,9 @@ class _SettingPageState extends State<SettingPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
final localeSettingVal = _setting.locale.fetch(); final localeSettingVal = _setting.locale.fetch();
if (localeSettingVal.isEmpty) { if (localeSettingVal.isEmpty) {
_localeCode.value = _s.localeName; _localeCode.value = l10n.localeName;
} else { } else {
_localeCode.value = localeSettingVal; _localeCode.value = localeSettingVal;
} }
@@ -100,26 +98,27 @@ class _SettingPageState extends State<SettingPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.setting), title: Text(l10n.setting),
actions: [ actions: [
IconButton( IconButton(
onPressed: () => context.showRoundDialog( onPressed: () => context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(_s.all)), child: Text(l10n.sureDelete(l10n.all)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
_setting.box.deleteAll(_setting.box.keys); _setting.box.deleteAll(_setting.box.keys);
context.pop(); context.pop();
context.showSnackBar(_s.success); context.showSnackBar(l10n.success);
}, },
child: Text(_s.ok, style: const TextStyle(color: Colors.red)), child:
Text(l10n.ok, style: const TextStyle(color: Colors.red)),
), ),
], ],
), ),
// onDoubleTap: () => context.showRoundDialog( // onDoubleTap: () => context.showRoundDialog(
// title: Text(_s.attention), // title: Text(l10n.attention),
// child: Text(_s.sureDelete(_s.all)), // child: Text(l10n.sureDelete(l10n.all)),
// actions: [ // actions: [
// TextButton( // TextButton(
// onPressed: () { // onPressed: () {
@@ -130,9 +129,9 @@ class _SettingPageState extends State<SettingPage> {
// Stores.snippet.box.deleteFromDisk(); // Stores.snippet.box.deleteFromDisk();
// Stores.key.box.deleteFromDisk(); // Stores.key.box.deleteFromDisk();
// context.pop(); // context.pop();
// context.showSnackBar(_s.success); // context.showSnackBar(l10n.success);
// }, // },
// child: Text(_s.ok, style: const TextStyle(color: Colors.red)), // child: Text(l10n.ok, style: const TextStyle(color: Colors.red)),
// ), // ),
// ], // ],
// ), // ),
@@ -145,13 +144,13 @@ class _SettingPageState extends State<SettingPage> {
children: [ children: [
_buildTitle('App'), _buildTitle('App'),
_buildApp(), _buildApp(),
_buildTitle(_s.server), _buildTitle(l10n.server),
_buildServer(), _buildServer(),
_buildTitle('SSH'), _buildTitle('SSH'),
_buildSSH(), _buildSSH(),
_buildTitle(_s.editor), _buildTitle(l10n.editor),
_buildEditor(), _buildEditor(),
_buildTitle(_s.fullScreen), _buildTitle(l10n.fullScreen),
_buildFullScreen(), _buildFullScreen(),
const SizedBox(height: 37), const SizedBox(height: 37),
], ],
@@ -247,15 +246,15 @@ class _SettingPageState extends State<SettingPage> {
String display; String display;
if (app.newestBuild != null) { if (app.newestBuild != null) {
if (app.newestBuild! > BuildData.build) { if (app.newestBuild! > BuildData.build) {
display = _s.versionHaveUpdate(app.newestBuild!); display = l10n.versionHaveUpdate(app.newestBuild!);
} else { } else {
display = _s.versionUpdated(BuildData.build); display = l10n.versionUpdated(BuildData.build);
} }
} else { } else {
display = _s.versionUnknownUpdate(BuildData.build); display = l10n.versionUnknownUpdate(BuildData.build);
} }
return ListTile( return ListTile(
title: Text(_s.autoCheckUpdate), title: Text(l10n.autoCheckUpdate),
subtitle: Text(display, style: UIs.textGrey), subtitle: Text(display, style: UIs.textGrey),
onTap: () => doUpdate(ctx, force: true), onTap: () => doUpdate(ctx, force: true),
trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate), trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate),
@@ -269,17 +268,17 @@ class _SettingPageState extends State<SettingPage> {
10, 10,
(index) => PopupMenuItem( (index) => PopupMenuItem(
value: index, value: index,
child: Text('$index ${_s.second}'), child: Text('$index ${l10n.second}'),
), ),
growable: false, growable: false,
).toList(); ).toList();
return ListTile( return ListTile(
title: Text( title: Text(
_s.updateServerStatusInterval, l10n.updateServerStatusInterval,
), ),
subtitle: Text( subtitle: Text(
_s.willTakEeffectImmediately, l10n.willTakEeffectImmediately,
style: UIs.textGrey, style: UIs.textGrey,
), ),
onTap: () { onTap: () {
@@ -296,11 +295,11 @@ class _SettingPageState extends State<SettingPage> {
_setting.serverStatusUpdateInterval.put(val); _setting.serverStatusUpdateInterval.put(val);
Providers.server.startAutoRefresh(); Providers.server.startAutoRefresh();
if (val == 0) { if (val == 0) {
context.showSnackBar(_s.updateIntervalEqual0); context.showSnackBar(l10n.updateIntervalEqual0);
} }
}, },
child: Text( child: Text(
'${_updateInterval.value} ${_s.second}', '${_updateInterval.value} ${l10n.second}',
style: UIs.textSize15, style: UIs.textSize15,
), ),
), ),
@@ -317,17 +316,17 @@ class _SettingPageState extends State<SettingPage> {
width: 27, width: 27,
), ),
), ),
title: Text(_s.primaryColorSeed), title: Text(l10n.primaryColorSeed),
onTap: () async { onTap: () async {
final ctrl = TextEditingController(text: primaryColor.toHex); final ctrl = TextEditingController(text: primaryColor.toHex);
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.primaryColorSeed), title: Text(l10n.primaryColorSeed),
child: StatefulBuilder(builder: (context, setState) { child: StatefulBuilder(builder: (context, setState) {
final children = <Widget>[ final children = <Widget>[
/// Plugin [dynamic_color] is not supported on iOS /// Plugin [dynamic_color] is not supported on iOS
if (!isIOS) if (!isIOS)
ListTile( ListTile(
title: Text(_s.followSystem), title: Text(l10n.followSystem),
trailing: StoreSwitch( trailing: StoreSwitch(
prop: _setting.useSystemPrimaryColor, prop: _setting.useSystemPrimaryColor,
func: (_) => setState(() {}), func: (_) => setState(() {}),
@@ -356,7 +355,7 @@ class _SettingPageState extends State<SettingPage> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => _onSaveColor(ctrl.text), onPressed: () => _onSaveColor(ctrl.text),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
]); ]);
}, },
@@ -366,7 +365,7 @@ class _SettingPageState extends State<SettingPage> {
void _onSaveColor(String s) { void _onSaveColor(String s) {
final color = s.hexToColor; final color = s.hexToColor;
if (color == null) { if (color == null) {
context.showSnackBar(_s.failed); context.showSnackBar(l10n.failed);
return; return;
} }
_selectedColorValue.value = color.value; _selectedColorValue.value = color.value;
@@ -388,7 +387,7 @@ class _SettingPageState extends State<SettingPage> {
// return ListTile( // return ListTile(
// title: Text( // title: Text(
// _s.launchPage, // l10n.launchPage,
// ), // ),
// onTap: () { // onTap: () {
// _startPageKey.currentState?.showButtonMenu(); // _startPageKey.currentState?.showButtonMenu();
@@ -421,16 +420,17 @@ class _SettingPageState extends State<SettingPage> {
10, 10,
(index) => PopupMenuItem( (index) => PopupMenuItem(
value: index, value: index,
child: Text('$index ${_s.times}'), child: Text('$index ${l10n.times}'),
), ),
growable: false, growable: false,
).toList(); ).toList();
final help = final help = _maxRetryCount.value == 0
_maxRetryCount.value == 0 ? _s.maxRetryCountEqual0 : _s.canPullRefresh; ? l10n.maxRetryCountEqual0
: l10n.canPullRefresh;
return ListTile( return ListTile(
title: Text( title: Text(
_s.maxRetryCount, l10n.maxRetryCount,
textAlign: TextAlign.start, textAlign: TextAlign.start,
), ),
subtitle: Text(help, style: UIs.textGrey), subtitle: Text(help, style: UIs.textGrey),
@@ -447,7 +447,7 @@ class _SettingPageState extends State<SettingPage> {
_setting.maxRetryCount.put(_maxRetryCount.value); _setting.maxRetryCount.put(_maxRetryCount.value);
}, },
child: Text( child: Text(
'${_maxRetryCount.value} ${_s.times}', '${_maxRetryCount.value} ${l10n.times}',
style: UIs.textSize15, style: UIs.textSize15,
), ),
), ),
@@ -471,7 +471,7 @@ class _SettingPageState extends State<SettingPage> {
return ListTile( return ListTile(
title: Text( title: Text(
_s.themeMode, l10n.themeMode,
), ),
onTap: () { onTap: () {
_themeKey.currentState?.showButtonMenu(); _themeKey.currentState?.showButtonMenu();
@@ -486,7 +486,7 @@ class _SettingPageState extends State<SettingPage> {
_nightMode.value = idx; _nightMode.value = idx;
_setting.themeMode.put(_nightMode.value); _setting.themeMode.put(_nightMode.value);
RebuildNodes.app.rebuild(); RebuildNodes.app.rebuild();
}, },
child: Text( child: Text(
_buildThemeModeStr(_nightMode.value), _buildThemeModeStr(_nightMode.value),
@@ -500,39 +500,39 @@ class _SettingPageState extends State<SettingPage> {
String _buildThemeModeStr(int n) { String _buildThemeModeStr(int n) {
switch (n) { switch (n) {
case 1: case 1:
return _s.light; return l10n.light;
case 2: case 2:
return _s.dark; return l10n.dark;
case 3: case 3:
return 'AMOLED'; return 'AMOLED';
default: default:
return _s.auto; return l10n.auto;
} }
} }
Widget _buildFont() { Widget _buildFont() {
final fontName = getFileName(_setting.fontPath.fetch()); final fontName = getFileName(_setting.fontPath.fetch());
return ListTile( return ListTile(
title: Text(_s.font), title: Text(l10n.font),
trailing: Text( trailing: Text(
fontName ?? _s.notSelected, fontName ?? l10n.notSelected,
style: UIs.textSize15, style: UIs.textSize15,
), ),
onTap: () { onTap: () {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.font), title: Text(l10n.font),
actions: [ actions: [
TextButton( TextButton(
onPressed: () async => await _pickFontFile(), onPressed: () async => await _pickFontFile(),
child: Text(_s.pickFile), child: Text(l10n.pickFile),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
_setting.fontPath.delete(); _setting.fontPath.delete();
context.pop(); context.pop();
RebuildNodes.app.rebuild(); RebuildNodes.app.rebuild();
}, },
child: Text(_s.clear), child: Text(l10n.clear),
) )
], ],
); );
@@ -554,17 +554,17 @@ class _SettingPageState extends State<SettingPage> {
} }
context.pop(); context.pop();
RebuildNodes.app.rebuild(); RebuildNodes.app.rebuild();
return; return;
} }
context.showSnackBar(_s.failed); context.showSnackBar(l10n.failed);
} }
Widget _buildTermFontSize() { Widget _buildTermFontSize() {
return ValueBuilder( return ValueBuilder(
listenable: _termFontSize, listenable: _termFontSize,
build: () => ListTile( build: () => ListTile(
title: Text(_s.fontSize), title: Text(l10n.fontSize),
trailing: Text( trailing: Text(
_termFontSize.value.toString(), _termFontSize.value.toString(),
style: UIs.textSize15, style: UIs.textSize15,
@@ -577,8 +577,8 @@ class _SettingPageState extends State<SettingPage> {
// Widget _buildDiskIgnorePath() { // Widget _buildDiskIgnorePath() {
// final paths = _setting.diskIgnorePath.fetch(); // final paths = _setting.diskIgnorePath.fetch();
// return ListTile( // return ListTile(
// title: Text(_s.diskIgnorePath), // title: Text(l10n.diskIgnorePath),
// trailing: Text(_s.edit, style: textSize15), // trailing: Text(l10n.edit, style: textSize15),
// onTap: () { // onTap: () {
// final ctrller = TextEditingController(text: json.encode(paths)); // final ctrller = TextEditingController(text: json.encode(paths));
// void onSubmit() { // void onSubmit() {
@@ -586,7 +586,7 @@ class _SettingPageState extends State<SettingPage> {
// final list = List<String>.from(json.decode(ctrller.text)); // final list = List<String>.from(json.decode(ctrller.text));
// _setting.diskIgnorePath.put(list); // _setting.diskIgnorePath.put(list);
// context.pop(); // context.pop();
// showSnackBar(context, Text(_s.success)); // showSnackBar(context, Text(l10n.success));
// } catch (e) { // } catch (e) {
// showSnackBar(context, Text(e.toString())); // showSnackBar(context, Text(e.toString()));
// } // }
@@ -594,7 +594,7 @@ class _SettingPageState extends State<SettingPage> {
// showRoundDialog( // showRoundDialog(
// context: context, // context: context,
// title: Text(_s.diskIgnorePath), // title: Text(l10n.diskIgnorePath),
// child: Input( // child: Input(
// autoFocus: true, // autoFocus: true,
// controller: ctrller, // controller: ctrller,
@@ -604,7 +604,7 @@ class _SettingPageState extends State<SettingPage> {
// onSubmitted: (_) => onSubmit(), // onSubmitted: (_) => onSubmit(),
// ), // ),
// actions: [ // actions: [
// TextButton(onPressed: onSubmit, child: Text(_s.ok)), // TextButton(onPressed: onSubmit, child: Text(l10n.ok)),
// ], // ],
// ); // );
// }, // },
@@ -621,7 +621,7 @@ class _SettingPageState extends State<SettingPage> {
) )
.toList(); .toList();
return ListTile( return ListTile(
title: Text(_s.language), title: Text(l10n.language),
onTap: () { onTap: () {
_localeKey.currentState?.showButtonMenu(); _localeKey.currentState?.showButtonMenu();
}, },
@@ -634,10 +634,10 @@ class _SettingPageState extends State<SettingPage> {
onSelected: (String idx) { onSelected: (String idx) {
_localeCode.value = idx; _localeCode.value = idx;
_setting.locale.put(idx); _setting.locale.put(idx);
RebuildNodes.app.rebuild(); RebuildNodes.app.rebuild();
}, },
child: Text( child: Text(
_s.languageName, l10n.languageName,
style: UIs.textSize15, style: UIs.textSize15,
), ),
), ),
@@ -647,7 +647,7 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildSSHVirtualKeyAutoOff() { Widget _buildSSHVirtualKeyAutoOff() {
return ListTile( return ListTile(
title: Text(_s.sshVirtualKeyAutoOff), title: Text(l10n.sshVirtualKeyAutoOff),
subtitle: const Text('Ctrl & Alt', style: UIs.textGrey), subtitle: const Text('Ctrl & Alt', style: UIs.textGrey),
trailing: StoreSwitch(prop: _setting.sshVirtualKeyAutoOff), trailing: StoreSwitch(prop: _setting.sshVirtualKeyAutoOff),
); );
@@ -663,7 +663,7 @@ class _SettingPageState extends State<SettingPage> {
}, },
).toList(); ).toList();
return ListTile( return ListTile(
title: Text('${_s.light} ${_s.theme.toLowerCase()}'), title: Text('${l10n.light} ${l10n.theme.toLowerCase()}'),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _editorTheme, listenable: _editorTheme,
build: () => PopupMenuButton( build: () => PopupMenuButton(
@@ -696,7 +696,7 @@ class _SettingPageState extends State<SettingPage> {
}, },
).toList(); ).toList();
return ListTile( return ListTile(
title: Text('${_s.dark} ${_s.theme.toLowerCase()}'), title: Text('${l10n.dark} ${l10n.theme.toLowerCase()}'),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _editorDarkTheme, listenable: _editorDarkTheme,
build: () => PopupMenuButton( build: () => PopupMenuButton(
@@ -721,19 +721,18 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildFullScreenSwitch() { Widget _buildFullScreenSwitch() {
return ListTile( return ListTile(
title: Text(_s.fullScreen), title: Text(l10n.fullScreen),
trailing: StoreSwitch( trailing: StoreSwitch(
prop: _setting.fullScreen, prop: _setting.fullScreen,
func: (_) => func: (_) => RebuildNodes.app.rebuild(),
RebuildNodes.app.rebuild(),
), ),
); );
} }
Widget _buildFullScreenJitter() { Widget _buildFullScreenJitter() {
return ListTile( return ListTile(
title: Text(_s.fullScreenJitter), title: Text(l10n.fullScreenJitter),
subtitle: Text(_s.fullScreenJitterHelp, style: UIs.textGrey), subtitle: Text(l10n.fullScreenJitterHelp, style: UIs.textGrey),
trailing: StoreSwitch(prop: _setting.fullScreenJitter), trailing: StoreSwitch(prop: _setting.fullScreenJitter),
); );
} }
@@ -748,7 +747,7 @@ class _SettingPageState extends State<SettingPage> {
}).toList(); }).toList();
return ListTile( return ListTile(
title: Text(_s.rotateAngel), title: Text(l10n.rotateAngel),
onTap: () { onTap: () {
_rotateQuarterKey.currentState?.showButtonMenu(); _rotateQuarterKey.currentState?.showButtonMenu();
}, },
@@ -798,8 +797,8 @@ class _SettingPageState extends State<SettingPage> {
}, },
).toList(); ).toList();
return ListTile( return ListTile(
title: Text(_s.keyboardType), title: Text(l10n.keyboardType),
subtitle: Text(_s.keyboardCompatibility, style: UIs.textGrey), subtitle: Text(l10n.keyboardCompatibility, style: UIs.textGrey),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _keyboardType, listenable: _keyboardType,
build: () => PopupMenuButton<int>( build: () => PopupMenuButton<int>(
@@ -824,7 +823,7 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildSSHVirtKeys() { Widget _buildSSHVirtKeys() {
return ListTile( return ListTile(
title: Text(_s.editVirtKeys), title: Text(l10n.editVirtKeys),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => AppRoute.sshVirtKeySetting().go(context), onTap: () => AppRoute.sshVirtKeySetting().go(context),
); );
@@ -834,11 +833,11 @@ class _SettingPageState extends State<SettingPage> {
final items = NetViewType.values final items = NetViewType.values
.map((e) => PopupMenuItem( .map((e) => PopupMenuItem(
value: e, value: e,
child: Text(e.l10n(_s)), child: Text(e.toStr),
)) ))
.toList(); .toList();
return ListTile( return ListTile(
title: Text(_s.netViewType), title: Text(l10n.netViewType),
trailing: ValueBuilder( trailing: ValueBuilder(
listenable: _netViewType, listenable: _netViewType,
build: () => PopupMenuButton<NetViewType>( build: () => PopupMenuButton<NetViewType>(
@@ -850,7 +849,7 @@ class _SettingPageState extends State<SettingPage> {
_setting.netViewType.put(idx); _setting.netViewType.put(idx);
}, },
child: Text( child: Text(
_netViewType.value.l10n(_s), _netViewType.value.toStr,
style: UIs.textSize15, style: UIs.textSize15,
), ),
), ),
@@ -863,18 +862,18 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildDeleteServers() { Widget _buildDeleteServers() {
return ListTile( return ListTile(
title: Text(_s.deleteServers), title: Text(l10n.deleteServers),
trailing: const Icon(Icons.delete_forever), trailing: const Icon(Icons.delete_forever),
onTap: () async { onTap: () async {
final all = Stores.server.box.keys.map( final all = Stores.server.box.keys.map(
(e) => TextButton( (e) => TextButton(
onPressed: () => context.showRoundDialog( onPressed: () => context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(e)), child: Text(l10n.sureDelete(e)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Providers.server.delServer(e), onPressed: () => Providers.server.delServer(e),
child: Text(_s.ok), child: Text(l10n.ok),
) )
], ],
), ),
@@ -882,7 +881,7 @@ class _SettingPageState extends State<SettingPage> {
), ),
); );
context.showRoundDialog<List<String>>( context.showRoundDialog<List<String>>(
title: Text(_s.choose), title: Text(l10n.choose),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -896,30 +895,30 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildMoveOutServerFuncBtns() { Widget _buildMoveOutServerFuncBtns() {
return ListTile( return ListTile(
title: Text(_s.moveOutServerFuncBtns), title: Text(l10n.moveOutServerFuncBtns),
subtitle: Text(_s.moveOutServerFuncBtnsHelp, style: UIs.textSize13Grey), subtitle: Text(l10n.moveOutServerFuncBtnsHelp, style: UIs.textSize13Grey),
trailing: StoreSwitch(prop: _setting.moveOutServerTabFuncBtns), trailing: StoreSwitch(prop: _setting.moveOutServerTabFuncBtns),
); );
} }
Widget _buildServerOrder() { Widget _buildServerOrder() {
return ListTile( return ListTile(
title: Text(_s.serverOrder), title: Text(l10n.serverOrder),
subtitle: Text('${_s.serverOrder} / ${_s.serverDetailOrder}', subtitle: Text('${l10n.serverOrder} / ${l10n.serverDetailOrder}',
style: UIs.textGrey), style: UIs.textGrey),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => context.showRoundDialog( onTap: () => context.showRoundDialog(
title: Text(_s.choose), title: Text(l10n.choose),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
ListTile( ListTile(
title: Text(_s.serverOrder), title: Text(l10n.serverOrder),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => AppRoute.serverOrder().go(context), onTap: () => AppRoute.serverOrder().go(context),
), ),
ListTile( ListTile(
title: Text(_s.serverDetailOrder), title: Text(l10n.serverDetailOrder),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () => AppRoute.serverDetailOrder().go(context), onTap: () => AppRoute.serverDetailOrder().go(context),
), ),
@@ -933,7 +932,7 @@ class _SettingPageState extends State<SettingPage> {
return ValueBuilder( return ValueBuilder(
listenable: _editorFontSize, listenable: _editorFontSize,
build: () => ListTile( build: () => ListTile(
title: Text(_s.fontSize), title: Text(l10n.fontSize),
trailing: Text( trailing: Text(
_editorFontSize.value.toString(), _editorFontSize.value.toString(),
style: UIs.textSize15, style: UIs.textSize15,
@@ -954,7 +953,7 @@ class _SettingPageState extends State<SettingPage> {
final fontSize = double.tryParse(ctrller.text); final fontSize = double.tryParse(ctrller.text);
if (fontSize == null) { if (fontSize == null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.failed), title: Text(l10n.failed),
child: Text('Parsed failed: ${ctrller.text}'), child: Text('Parsed failed: ${ctrller.text}'),
); );
return; return;
@@ -964,7 +963,7 @@ class _SettingPageState extends State<SettingPage> {
} }
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.fontSize), title: Text(l10n.fontSize),
child: Input( child: Input(
controller: ctrller, controller: ctrller,
autoFocus: true, autoFocus: true,
@@ -975,7 +974,7 @@ class _SettingPageState extends State<SettingPage> {
actions: [ actions: [
TextButton( TextButton(
onPressed: onSave, onPressed: onSave,
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );
@@ -984,14 +983,14 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildSftpRmrfDir() { Widget _buildSftpRmrfDir() {
return ListTile( return ListTile(
title: const Text('rm -rf'), title: const Text('rm -rf'),
subtitle: Text(_s.sftpRmrfDirSummary, style: UIs.textGrey), subtitle: Text(l10n.sftpRmrfDirSummary, style: UIs.textGrey),
trailing: StoreSwitch(prop: _setting.sftpRmrfDir), trailing: StoreSwitch(prop: _setting.sftpRmrfDir),
); );
} }
// Widget _buildDoubleColumnServersPage() { // Widget _buildDoubleColumnServersPage() {
// return ListTile( // return ListTile(
// title: Text(_s.doubleColumnMode), // title: Text(l10n.doubleColumnMode),
// trailing: StoreSwitch(prop: _setting.doubleColumnServersPage), // trailing: StoreSwitch(prop: _setting.doubleColumnServersPage),
// ); // );
// } // }
@@ -1000,16 +999,16 @@ class _SettingPageState extends State<SettingPage> {
return FutureWidget<bool>( return FutureWidget<bool>(
future: BioAuth.isAvail, future: BioAuth.isAvail,
loading: ListTile( loading: ListTile(
title: Text(_s.bioAuth), title: Text(l10n.bioAuth),
subtitle: Text(_s.serverTabLoading, style: UIs.textGrey), subtitle: Text(l10n.serverTabLoading, style: UIs.textGrey),
), ),
error: (e, __) => ListTile( error: (e, __) => ListTile(
title: Text(_s.bioAuth), title: Text(l10n.bioAuth),
subtitle: Text('${_s.failed}: $e', style: UIs.textGrey), subtitle: Text('${l10n.failed}: $e', style: UIs.textGrey),
), ),
success: (can) { success: (can) {
return ListTile( return ListTile(
title: Text(_s.bioAuth), title: Text(l10n.bioAuth),
subtitle: can subtitle: can
? null ? null
: const Text('Error: Bio auth is not available', : const Text('Error: Bio auth is not available',
@@ -1023,7 +1022,7 @@ class _SettingPageState extends State<SettingPage> {
return; return;
} }
// Only auth when turn off (val == false) // Only auth when turn off (val == false)
final result = await BioAuth.auth(_s.authRequired); final result = await BioAuth.auth(l10n.authRequired);
// If failed, turn on again // If failed, turn on again
if (result != AuthResult.success) { if (result != AuthResult.success) {
Stores.setting.useBioAuth.put(true); Stores.setting.useBioAuth.put(true);
@@ -1039,7 +1038,7 @@ class _SettingPageState extends State<SettingPage> {
Widget _buildPlatformSetting() { Widget _buildPlatformSetting() {
return ListTile( return ListTile(
title: Text('${OS.type} ${_s.setting}'), title: Text('${OS.type} ${l10n.setting}'),
trailing: const Icon(Icons.keyboard_arrow_right), trailing: const Icon(Icons.keyboard_arrow_right),
onTap: () { onTap: () {
switch (OS.type) { switch (OS.type) {

View File

@@ -1,8 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/route.dart';
import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/misc.dart';
@@ -24,18 +24,10 @@ class IOSSettingsPage extends StatefulWidget {
} }
class _IOSSettingsPageState extends State<IOSSettingsPage> { class _IOSSettingsPageState extends State<IOSSettingsPage> {
late S _s;
final _pushToken = ValueNotifier<String?>(null); final _pushToken = ValueNotifier<String?>(null);
final wc = WatchConnectivity(); final wc = WatchConnectivity();
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -55,9 +47,7 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
Widget _buildPushToken() { Widget _buildPushToken() {
return ListTile( return ListTile(
title: Text( title: Text(l10n.pushToken),
_s.pushToken,
),
trailing: IconButton( trailing: IconButton(
icon: const Icon(Icons.copy), icon: const Icon(Icons.copy),
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
@@ -65,21 +55,21 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
onPressed: () { onPressed: () {
if (_pushToken.value != null) { if (_pushToken.value != null) {
copy2Clipboard(_pushToken.value!); copy2Clipboard(_pushToken.value!);
context.showSnackBar(_s.success); context.showSnackBar(l10n.success);
} else { } else {
context.showSnackBar(_s.getPushTokenFailed); context.showSnackBar(l10n.getPushTokenFailed);
} }
}, },
), ),
subtitle: FutureWidget<String?>( subtitle: FutureWidget<String?>(
future: getToken(), future: getToken(),
loading: Text(_s.gettingToken), loading: Text(l10n.gettingToken),
error: (error, trace) => Text('${_s.error}: $error'), error: (error, trace) => Text('${l10n.error}: $error'),
noData: Text(_s.nullToken), noData: Text(l10n.nullToken),
success: (text) { success: (text) {
_pushToken.value = text; _pushToken.value = text;
return Text( return Text(
text ?? _s.nullToken, text ?? l10n.nullToken,
style: UIs.textGrey, style: UIs.textGrey,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
@@ -91,8 +81,8 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
Widget _buildAutoUpdateHomeWidget() { Widget _buildAutoUpdateHomeWidget() {
return ListTile( return ListTile(
title: Text(_s.autoUpdateHomeWidget), title: Text(l10n.autoUpdateHomeWidget),
subtitle: Text(_s.whenOpenApp, style: UIs.textGrey), subtitle: Text(l10n.whenOpenApp, style: UIs.textGrey),
trailing: StoreSwitch(prop: Stores.setting.autoUpdateHomeWidget), trailing: StoreSwitch(prop: Stores.setting.autoUpdateHomeWidget),
); );
} }
@@ -110,14 +100,14 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
Loggers.app.warning('WatchOS error', e, trace); Loggers.app.warning('WatchOS error', e, trace);
return ListTile( return ListTile(
title: const Text('Watch app'), title: const Text('Watch app'),
subtitle: Text('${_s.error}: $e', style: UIs.textGrey), subtitle: Text('${l10n.error}: $e', style: UIs.textGrey),
); );
}, },
success: (ctx) { success: (ctx) {
if (ctx == null) { if (ctx == null) {
return ListTile( return ListTile(
title: const Text('Watch app'), title: const Text('Watch app'),
subtitle: Text(_s.watchNotPaired, style: UIs.textGrey), subtitle: Text(l10n.watchNotPaired, style: UIs.textGrey),
); );
} }
return ListTile( return ListTile(
@@ -146,8 +136,8 @@ class _IOSSettingsPageState extends State<IOSSettingsPage> {
await wc.updateApplicationContext(newCtx); await wc.updateApplicationContext(newCtx);
} catch (e, trace) { } catch (e, trace) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text('${_s.save}:\n$e'), child: Text('${l10n.save}:\n$e'),
); );
Loggers.app.warning('Update watch config failed', e, trace); Loggers.app.warning('Update watch config failed', e, trace);
} }

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
import '../../../core/extension/order.dart'; import '../../../core/extension/order.dart';
@@ -16,14 +16,6 @@ class ServerDetailOrderPage extends StatefulWidget {
class _ServerDetailOrderPageState extends State<ServerDetailOrderPage> { class _ServerDetailOrderPageState extends State<ServerDetailOrderPage> {
final Order<String> _cardsOrder = []; final Order<String> _cardsOrder = [];
late S _s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -34,7 +26,7 @@ class _ServerDetailOrderPageState extends State<ServerDetailOrderPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.serverOrder), title: Text(l10n.serverOrder),
), ),
body: _buildBody(), body: _buildBody(),
); );

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -15,19 +15,11 @@ class ServerOrderPage extends StatefulWidget {
} }
class _ServerOrderPageState extends State<ServerOrderPage> { class _ServerOrderPageState extends State<ServerOrderPage> {
late S _s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.serverOrder), title: Text(l10n.serverOrder),
), ),
body: _buildBody(), body: _buildBody(),
); );
@@ -35,7 +27,7 @@ class _ServerOrderPageState extends State<ServerOrderPage> {
Widget _buildBody() { Widget _buildBody() {
if (Providers.server.serverOrder.isEmpty) { if (Providers.server.serverOrder.isEmpty) {
return Center(child: Text(_s.noServerAvailable)); return Center(child: Text(l10n.noServerAvailable));
} }
return ReorderableListView.builder( return ReorderableListView.builder(
footer: const SizedBox(height: 77), footer: const SizedBox(height: 77),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
@@ -18,19 +18,11 @@ class SSHVirtKeySettingPage extends StatefulWidget {
} }
class _SSHVirtKeySettingPageState extends State<SSHVirtKeySettingPage> { class _SSHVirtKeySettingPageState extends State<SSHVirtKeySettingPage> {
late S _s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.editVirtKeys), title: Text(l10n.editVirtKeys),
), ),
body: _buildBody(), body: _buildBody(),
); );
@@ -48,7 +40,7 @@ class _SSHVirtKeySettingPageState extends State<SSHVirtKeySettingPage> {
padding: const EdgeInsets.all(7), padding: const EdgeInsets.all(7),
itemBuilder: (_, idx) { itemBuilder: (_, idx) {
final key = allKeys[idx]; final key = allKeys[idx];
final help = key.help(_s); final help = key.help;
return RoundRectCard( return RoundRectCard(
key: ValueKey(idx), key: ValueKey(idx),
ListTile( ListTile(
@@ -62,7 +54,7 @@ class _SSHVirtKeySettingPageState extends State<SSHVirtKeySettingPage> {
itemCount: allKeys.length, itemCount: allKeys.length,
onReorder: (o, n) { onReorder: (o, n) {
if (o >= keys.length || n >= keys.length) { if (o >= keys.length || n >= keys.length) {
context.showSnackBar(_s.disabled); context.showSnackBar(l10n.disabled);
return; return;
} }
keys.moveByItem(keys, o, n, property: Stores.setting.sshVirtKeys); keys.moveByItem(keys, o, n, property: Stores.setting.sshVirtKeys);

View File

@@ -1,7 +1,7 @@
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/input_field.dart';
@@ -27,8 +27,6 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final _noteController = TextEditingController(); final _noteController = TextEditingController();
final _scriptNode = FocusNode(); final _scriptNode = FocusNode();
late S _s;
List<String> _tags = []; List<String> _tags = [];
@override @override
@@ -39,17 +37,11 @@ class _SnippetEditPageState extends State<SnippetEditPage>
_scriptNode.dispose(); _scriptNode.dispose();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.edit, style: UIs.textSize18), title: Text(l10n.edit, style: UIs.textSize18),
actions: _buildAppBarActions(), actions: _buildAppBarActions(),
), ),
body: _buildBody(), body: _buildBody(),
@@ -67,7 +59,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
Providers.snippet.del(widget.snippet!); Providers.snippet.del(widget.snippet!);
context.pop(); context.pop();
}, },
tooltip: _s.delete, tooltip: l10n.delete,
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),
) )
]; ];
@@ -81,7 +73,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
final name = _nameController.text; final name = _nameController.text;
final script = _scriptController.text; final script = _scriptController.text;
if (name.isEmpty || script.isEmpty) { if (name.isEmpty || script.isEmpty) {
context.showSnackBar(_s.fieldMustNotEmpty); context.showSnackBar(l10n.fieldMustNotEmpty);
return; return;
} }
final note = _noteController.text; final note = _noteController.text;
@@ -110,7 +102,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
controller: _nameController, controller: _nameController,
type: TextInputType.text, type: TextInputType.text,
onSubmitted: (_) => FocusScope.of(context).requestFocus(_scriptNode), onSubmitted: (_) => FocusScope.of(context).requestFocus(_scriptNode),
label: _s.name, label: l10n.name,
icon: Icons.info, icon: Icons.info,
), ),
Input( Input(
@@ -118,7 +110,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
minLines: 3, minLines: 3,
maxLines: 3, maxLines: 3,
type: TextInputType.multiline, type: TextInputType.multiline,
label: _s.note, label: l10n.note,
icon: Icons.note, icon: Icons.note,
), ),
TagEditor( TagEditor(
@@ -126,7 +118,6 @@ class _SnippetEditPageState extends State<SnippetEditPage>
onChanged: (p0) => setState(() { onChanged: (p0) => setState(() {
_tags = p0; _tags = p0;
}), }),
s: _s,
allTags: [...Providers.server.tags], allTags: [...Providers.server.tags],
onRenameTag: (old, n) => setState(() { onRenameTag: (old, n) => setState(() {
Providers.server.renameTag(old, n); Providers.server.renameTag(old, n);
@@ -138,7 +129,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
minLines: 3, minLines: 3,
maxLines: 10, maxLines: 10,
type: TextInputType.multiline, type: TextInputType.multiline,
label: _s.snippet, label: l10n.snippet,
icon: Icons.code, icon: Icons.code,
), ),
], ],

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/order.dart'; import 'package:toolbox/core/extension/order.dart';
import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/provider.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -23,7 +23,6 @@ class SnippetListPage extends StatefulWidget {
} }
class _SnippetListPageState extends State<SnippetListPage> { class _SnippetListPageState extends State<SnippetListPage> {
late S _s;
late MediaQueryData _media; late MediaQueryData _media;
String? _tag; String? _tag;
@@ -31,7 +30,6 @@ class _SnippetListPageState extends State<SnippetListPage> {
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
} }
@@ -52,7 +50,7 @@ class _SnippetListPageState extends State<SnippetListPage> {
builder: (_, provider, __) { builder: (_, provider, __) {
if (provider.snippets.isEmpty) { if (provider.snippets.isEmpty) {
return Center( return Center(
child: Text(_s.noSavedSnippet), child: Text(l10n.noSavedSnippet),
); );
} }
@@ -77,7 +75,7 @@ class _SnippetListPageState extends State<SnippetListPage> {
tags: provider.tags, tags: provider.tags,
onTagChanged: (tag) => setState(() => _tag = tag), onTagChanged: (tag) => setState(() => _tag = tag),
initTag: _tag, initTag: _tag,
all: _s.all, all: l10n.all,
width: _media.size.width, width: _media.size.width,
), ),
footer: UIs.height77, footer: UIs.height77,
@@ -148,12 +146,12 @@ class _SnippetListPageState extends State<SnippetListPage> {
results, results,
).entries.map((e) => '${e.key}:\n${e.value}').join('\n'); ).entries.map((e) => '${e.key}:\n${e.value}').join('\n');
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.result), title: Text(l10n.result),
child: Text(result), child: Text(result),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => copy2Clipboard(result), onPressed: () => copy2Clipboard(result),
child: Text(_s.copy), child: Text(l10n.copy),
) )
], ],
); );

View File

@@ -5,10 +5,10 @@ import 'package:dartssh2/dartssh2.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
import 'package:toolbox/data/res/store.dart'; import 'package:toolbox/data/res/store.dart';
@@ -43,7 +43,6 @@ class _SSHPageState extends State<SSHPage> {
final List<List<VirtKey>> _virtKeysList = []; final List<List<VirtKey>> _virtKeysList = [];
late MediaQueryData _media; late MediaQueryData _media;
late S _s;
late TerminalStyle _terminalStyle; late TerminalStyle _terminalStyle;
late TerminalTheme _terminalTheme; late TerminalTheme _terminalTheme;
late TextInputType _keyboardType; late TextInputType _keyboardType;
@@ -88,7 +87,6 @@ class _SSHPageState extends State<SSHPage> {
super.didChangeDependencies(); super.didChangeDependencies();
_isDark = context.isDark; _isDark = context.isDark;
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
_s = S.of(context)!;
_terminalTheme = _isDark ? TerminalThemes.dark : TerminalThemes.light; _terminalTheme = _isDark ? TerminalThemes.dark : TerminalThemes.light;
// Because the virtual keyboard only displayed on mobile devices // Because the virtual keyboard only displayed on mobile devices
@@ -252,7 +250,7 @@ class _SSHPageState extends State<SSHPage> {
} }
break; break;
case VirtualKeyFunc.snippet: case VirtualKeyFunc.snippet:
context.showSnippetDialog(_s, (s) { context.showSnippetDialog((s) {
_terminal.textInput(s.script); _terminal.textInput(s.script);
_terminal.keyInput(TerminalKey.enter); _terminal.keyInput(TerminalKey.enter);
}); });
@@ -269,7 +267,7 @@ class _SSHPageState extends State<SSHPage> {
final initPath = cmds[idx + 1].toString(); final initPath = cmds[idx + 1].toString();
if (initPath.isEmpty || !initPath.startsWith('/')) { if (initPath.isEmpty || !initPath.startsWith('/')) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: const Text('Failed to get current path'), child: const Text('Failed to get current path'),
); );
return; return;
@@ -401,8 +399,8 @@ class _SSHPageState extends State<SSHPage> {
if (!mounted) return; if (!mounted) return;
_write('\n\nConnection lost\r\n'); _write('\n\nConnection lost\r\n');
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text('${_s.disconnected}\n${_s.goBackQ}'), child: Text('${l10n.disconnected}\n${l10n.goBackQ}'),
barrierDismiss: false, barrierDismiss: false,
actions: [ actions: [
TextButton( TextButton(
@@ -412,7 +410,7 @@ class _SSHPageState extends State<SSHPage> {
context.pop(); context.pop();
} }
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -1,9 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/data/model/sftp/req.dart'; import 'package:toolbox/data/model/sftp/req.dart';
import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/misc.dart';
@@ -37,7 +37,6 @@ class LocalStoragePage extends StatefulWidget {
class _LocalStoragePageState extends State<LocalStoragePage> { class _LocalStoragePageState extends State<LocalStoragePage> {
LocalPath? _path; LocalPath? _path;
late S _s;
@override @override
void initState() { void initState() {
@@ -55,12 +54,6 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
} }
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -74,7 +67,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
context.pop(); context.pop();
}, },
), ),
title: Text(_s.files), title: Text(l10n.files),
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.downloading), icon: const Icon(Icons.downloading),
@@ -96,7 +89,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
(_path?.path ?? _s.loadingFiles).omitStartStr(), (_path?.path ?? l10n.loadingFiles).omitStartStr(),
_buildBtns(), _buildBtns(),
], ],
), ),
@@ -200,7 +193,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
context.pop(); context.pop();
_showRenameDialog(file); _showRenameDialog(file);
}, },
title: Text(_s.rename), title: Text(l10n.rename),
leading: const Icon(Icons.abc), leading: const Icon(Icons.abc),
), ),
ListTile( ListTile(
@@ -208,7 +201,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
context.pop(); context.pop();
_showDeleteDialog(file); _showDeleteDialog(file);
}, },
title: Text(_s.delete), title: Text(l10n.delete),
leading: const Icon(Icons.delete), leading: const Icon(Icons.delete),
), ),
], ],
@@ -220,7 +213,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
final fileName = file.path.split('/').last; final fileName = file.path.split('/').last;
if (widget.isPickFile) { if (widget.isPickFile) {
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.pickFile), title: Text(l10n.pickFile),
child: Text(fileName), child: Text(fileName),
actions: [ actions: [
TextButton( TextButton(
@@ -228,7 +221,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
context.pop(); context.pop();
context.pop(file.path); context.pop(file.path);
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
]); ]);
return; return;
@@ -239,14 +232,14 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
children: [ children: [
ListTile( ListTile(
leading: const Icon(Icons.edit), leading: const Icon(Icons.edit),
title: Text(_s.edit), title: Text(l10n.edit),
onTap: () async { onTap: () async {
context.pop(); context.pop();
final stat = await file.stat(); final stat = await file.stat();
if (stat.size > Miscs.editorMaxSize) { if (stat.size > Miscs.editorMaxSize) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.fileTooLarge(fileName, stat.size, '1m')), child: Text(l10n.fileTooLarge(fileName, stat.size, '1m')),
); );
return; return;
} }
@@ -256,14 +249,14 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
final f = File(file.absolute.path); final f = File(file.absolute.path);
if (result != null) { if (result != null) {
f.writeAsString(result); f.writeAsString(result);
context.showSnackBar(_s.saved); context.showSnackBar(l10n.saved);
setState(() {}); setState(() {});
} }
}, },
), ),
ListTile( ListTile(
leading: const Icon(Icons.abc), leading: const Icon(Icons.abc),
title: Text(_s.rename), title: Text(l10n.rename),
onTap: () { onTap: () {
context.pop(); context.pop();
_showRenameDialog(file); _showRenameDialog(file);
@@ -271,7 +264,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
), ),
ListTile( ListTile(
leading: const Icon(Icons.delete), leading: const Icon(Icons.delete),
title: Text(_s.delete), title: Text(l10n.delete),
onTap: () { onTap: () {
context.pop(); context.pop();
_showDeleteDialog(file); _showDeleteDialog(file);
@@ -279,20 +272,20 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
), ),
ListTile( ListTile(
leading: const Icon(Icons.upload), leading: const Icon(Icons.upload),
title: Text(_s.upload), title: Text(l10n.upload),
onTap: () async { onTap: () async {
context.pop(); context.pop();
final ids = Providers.server.serverOrder; final ids = Providers.server.serverOrder;
var idx = 0; var idx = 0;
await context.showRoundDialog( await context.showRoundDialog(
title: Text(_s.server), title: Text(l10n.server),
child: Picker( child: Picker(
items: ids.map((e) => Text(e)).toList(), items: ids.map((e) => Text(e)).toList(),
onSelected: (idx_) => idx = idx_, onSelected: (idx_) => idx = idx_,
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), child: Text(_s.ok)), onPressed: () => context.pop(), child: Text(l10n.ok)),
], ],
); );
final id = ids[idx]; final id = ids[idx];
@@ -313,12 +306,12 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
file.absolute.path, file.absolute.path,
SftpReqType.upload, SftpReqType.upload,
)); ));
context.showSnackBar(_s.added2List); context.showSnackBar(l10n.added2List);
}, },
), ),
ListTile( ListTile(
leading: const Icon(Icons.open_in_new), leading: const Icon(Icons.open_in_new),
title: Text(_s.open), title: Text(l10n.open),
onTap: () { onTap: () {
shareFiles(context, [file.absolute.path]); shareFiles(context, [file.absolute.path]);
}, },
@@ -331,7 +324,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
void _showRenameDialog(FileSystemEntity file) { void _showRenameDialog(FileSystemEntity file) {
final fileName = file.path.split('/').last; final fileName = file.path.split('/').last;
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.rename), title: Text(l10n.rename),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
controller: TextEditingController(text: fileName), controller: TextEditingController(text: fileName),
@@ -341,7 +334,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
try { try {
file.renameSync(newPath); file.renameSync(newPath);
} catch (e) { } catch (e) {
context.showSnackBar('${_s.failed}:\n$e'); context.showSnackBar('${l10n.failed}:\n$e');
return; return;
} }
@@ -354,12 +347,12 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
void _showDeleteDialog(FileSystemEntity file) { void _showDeleteDialog(FileSystemEntity file) {
final fileName = file.path.split('/').last; final fileName = file.path.split('/').last;
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.delete), title: Text(l10n.delete),
child: Text(_s.sureDelete(fileName)), child: Text(l10n.sureDelete(fileName)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
@@ -367,12 +360,12 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
try { try {
file.deleteSync(recursive: true); file.deleteSync(recursive: true);
} catch (e) { } catch (e) {
context.showSnackBar('${_s.failed}:\n$e'); context.showSnackBar('${l10n.failed}:\n$e');
return; return;
} }
setState(() {}); setState(() {});
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );

View File

@@ -3,9 +3,9 @@ import 'dart:async';
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:dartssh2/dartssh2.dart'; import 'package:dartssh2/dartssh2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/sftpfile.dart'; import 'package:toolbox/core/extension/sftpfile.dart';
import 'package:toolbox/core/utils/platform/base.dart'; import 'package:toolbox/core/utils/platform/base.dart';
@@ -49,14 +49,11 @@ class SftpPage extends StatefulWidget {
class _SftpPageState extends State<SftpPage> with AfterLayoutMixin { class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
final SftpBrowserStatus _status = SftpBrowserStatus(); final SftpBrowserStatus _status = SftpBrowserStatus();
late S _s;
SSHClient? _client; SSHClient? _client;
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
} }
@override @override
@@ -130,7 +127,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
(_status.path?.path ?? _s.loadingFiles).omitStartStr(), (_status.path?.path ?? l10n.loadingFiles).omitStartStr(),
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: children, children: children,
@@ -150,12 +147,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
children: [ children: [
ListTile( ListTile(
leading: const Icon(Icons.open_in_new), leading: const Icon(Icons.open_in_new),
title: Text(_s.system), title: Text(l10n.system),
onTap: () => context.pop(1), onTap: () => context.pop(1),
), ),
ListTile( ListTile(
leading: const Icon(Icons.folder), leading: const Icon(Icons.folder),
title: Text(_s.inner), title: Text(l10n.inner),
onTap: () => context.pop(0), onTap: () => context.pop(0),
), ),
], ],
@@ -199,11 +196,11 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
children: [ children: [
ListTile( ListTile(
leading: const Icon(Icons.folder), leading: const Icon(Icons.folder),
title: Text(_s.createFolder), title: Text(l10n.createFolder),
onTap: () => _mkdir(context)), onTap: () => _mkdir(context)),
ListTile( ListTile(
leading: const Icon(Icons.insert_drive_file), leading: const Icon(Icons.insert_drive_file),
title: Text(_s.createFile), title: Text(l10n.createFile),
onTap: () => _newFile(context)), onTap: () => _newFile(context)),
], ],
), ),
@@ -217,7 +214,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
padding: const EdgeInsets.all(0), padding: const EdgeInsets.all(0),
onPressed: () async { onPressed: () async {
final p = await context.showRoundDialog<String>( final p = await context.showRoundDialog<String>(
title: Text(_s.goto), title: Text(l10n.goto),
child: Autocomplete<String>( child: Autocomplete<String>(
optionsBuilder: (val) { optionsBuilder: (val) {
if (!Stores.setting.recordHistory.fetch()) { if (!Stores.setting.recordHistory.fetch()) {
@@ -231,7 +228,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
return Input( return Input(
autoFocus: true, autoFocus: true,
icon: Icons.abc, icon: Icons.abc,
label: _s.path, label: l10n.path,
node: node, node: node,
controller: controller, controller: controller,
onSubmitted: (value) => context.pop(value), onSubmitted: (value) => context.pop(value),
@@ -318,12 +315,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
final children = [ final children = [
ListTile( ListTile(
leading: const Icon(Icons.delete), leading: const Icon(Icons.delete),
title: Text(_s.delete), title: Text(l10n.delete),
onTap: () => _delete(context, file), onTap: () => _delete(context, file),
), ),
ListTile( ListTile(
leading: const Icon(Icons.abc), leading: const Icon(Icons.abc),
title: Text(_s.rename), title: Text(l10n.rename),
onTap: () => _rename(context, file), onTap: () => _rename(context, file),
), ),
]; ];
@@ -331,19 +328,19 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
children.addAll([ children.addAll([
ListTile( ListTile(
leading: const Icon(Icons.edit), leading: const Icon(Icons.edit),
title: Text(_s.edit), title: Text(l10n.edit),
onTap: () => _edit(context, file), onTap: () => _edit(context, file),
), ),
ListTile( ListTile(
leading: const Icon(Icons.download), leading: const Icon(Icons.download),
title: Text(_s.download), title: Text(l10n.download),
onTap: () => _download(context, file), onTap: () => _download(context, file),
), ),
// Only show decompress option when the file is a compressed file // Only show decompress option when the file is a compressed file
if (_canDecompress(file.filename)) if (_canDecompress(file.filename))
ListTile( ListTile(
leading: const Icon(Icons.folder_zip), leading: const Icon(Icons.folder_zip),
title: Text(_s.decompress), title: Text(l10n.decompress),
onTap: () => _decompress(context, file), onTap: () => _decompress(context, file),
), ),
]); ]);
@@ -359,7 +356,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
Future<void> _edit(BuildContext context, SftpName name) async { Future<void> _edit(BuildContext context, SftpName name) async {
final size = name.attr.size; final size = name.attr.size;
if (size == null || size > Miscs.editorMaxSize) { if (size == null || size > Miscs.editorMaxSize) {
context.showSnackBar(_s.fileTooLarge( context.showSnackBar(l10n.fileTooLarge(
name.filename, name.filename,
size ?? 0, size ?? 0,
Miscs.editorMaxSize, Miscs.editorMaxSize,
@@ -386,18 +383,18 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
if (result != null && result) { if (result != null && result) {
Providers.sftp Providers.sftp
.add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload)); .add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload));
context.showSnackBar(_s.added2List); context.showSnackBar(l10n.added2List);
} }
} }
void _download(BuildContext context, SftpName name) { void _download(BuildContext context, SftpName name) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text('${_s.dl2Local(name.filename)}\n${_s.keepForeground}'), child: Text('${l10n.dl2Local(name.filename)}\n${l10n.keepForeground}'),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -415,7 +412,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
}, },
child: Text(_s.download), child: Text(l10n.download),
) )
], ],
); );
@@ -425,16 +422,16 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
final isDir = file.attr.isDirectory; final isDir = file.attr.isDirectory;
final useRmrf = Stores.setting.sftpRmrfDir.fetch(); final useRmrf = Stores.setting.sftpRmrfDir.fetch();
final dirText = (isDir && !useRmrf) ? '\n${_s.sureDirEmpty}' : ''; final dirText = (isDir && !useRmrf) ? '\n${l10n.sureDirEmpty}' : '';
final text = '${_s.sureDelete(file.filename)}$dirText'; final text = '${l10n.sureDelete(file.filename)}$dirText';
final child = Text(text); final child = Text(text);
context.showRoundDialog( context.showRoundDialog(
child: child, child: child,
title: Text(_s.attention), title: Text(l10n.attention),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
@@ -453,12 +450,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
} catch (e) { } catch (e) {
context.pop(); context.pop();
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text(e.toString()), child: Text(e.toString()),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
) )
], ],
); );
@@ -466,7 +463,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
} }
_listDir(); _listDir();
}, },
child: Text(_s.delete, style: UIs.textRed), child: Text(l10n.delete, style: UIs.textRed),
), ),
], ],
); );
@@ -476,27 +473,27 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
final textController = TextEditingController(); final textController = TextEditingController();
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.createFolder), title: Text(l10n.createFolder),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
icon: Icons.folder, icon: Icons.folder,
controller: textController, controller: textController,
label: _s.name, label: l10n.name,
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.cancel), child: Text(l10n.cancel),
), ),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
if (textController.text == '') { if (textController.text == '') {
context.showRoundDialog( context.showRoundDialog(
child: Text(_s.fieldMustNotEmpty), child: Text(l10n.fieldMustNotEmpty),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );
@@ -507,7 +504,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
_listDir(); _listDir();
}, },
child: Text(_s.ok, style: UIs.textRed), child: Text(l10n.ok, style: UIs.textRed),
), ),
], ],
); );
@@ -517,24 +514,24 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
final textController = TextEditingController(); final textController = TextEditingController();
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.createFile), title: Text(l10n.createFile),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
icon: Icons.insert_drive_file, icon: Icons.insert_drive_file,
controller: textController, controller: textController,
label: _s.name, label: l10n.name,
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
if (textController.text == '') { if (textController.text == '') {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.fieldMustNotEmpty), child: Text(l10n.fieldMustNotEmpty),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );
@@ -547,7 +544,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
_listDir(); _listDir();
}, },
child: Text(_s.ok, style: UIs.textRed), child: Text(l10n.ok, style: UIs.textRed),
), ),
], ],
); );
@@ -557,25 +554,25 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
final textController = TextEditingController(); final textController = TextEditingController();
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.rename), title: Text(l10n.rename),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
icon: Icons.abc, icon: Icons.abc,
controller: textController, controller: textController,
label: _s.name, label: l10n.name,
), ),
actions: [ actions: [
TextButton(onPressed: () => context.pop(), child: Text(_s.cancel)), TextButton(onPressed: () => context.pop(), child: Text(l10n.cancel)),
TextButton( TextButton(
onPressed: () async { onPressed: () async {
if (textController.text == '') { if (textController.text == '') {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.fieldMustNotEmpty), child: Text(l10n.fieldMustNotEmpty),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );
@@ -585,7 +582,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
context.pop(); context.pop();
_listDir(); _listDir();
}, },
child: Text(_s.rename, style: UIs.textRed), child: Text(l10n.rename, style: UIs.textRed),
), ),
], ],
); );
@@ -597,12 +594,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
final cmd = _getDecompressCmd(absPath); final cmd = _getDecompressCmd(absPath);
if (cmd == null) { if (cmd == null) {
context.showRoundDialog( context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text('Unsupport file: ${name.filename}'), child: Text('Unsupport file: ${name.filename}'),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );
@@ -664,12 +661,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
Future.delayed( Future.delayed(
const Duration(milliseconds: 177), const Duration(milliseconds: 177),
() => context.showRoundDialog( () => context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text(e.toString()), child: Text(e.toString()),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(), onPressed: () => context.pop(),
child: Text(_s.ok), child: Text(l10n.ok),
) )
], ],
), ),

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/datetime.dart'; import 'package:toolbox/core/extension/datetime.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/route.dart';
@@ -23,19 +23,11 @@ class SftpMissionPage extends StatefulWidget {
} }
class _SftpMissionPageState extends State<SftpMissionPage> { class _SftpMissionPageState extends State<SftpMissionPage> {
late S _s;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_s = S.of(context)!;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: CustomAppBar( appBar: CustomAppBar(
title: Text(_s.mission, style: UIs.textSize18), title: Text(l10n.mission, style: UIs.textSize18),
), ),
body: _buildBody(), body: _buildBody(),
); );
@@ -45,7 +37,7 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
return Consumer<SftpProvider>(builder: (__, pro, _) { return Consumer<SftpProvider>(builder: (__, pro, _) {
if (pro.status.isEmpty) { if (pro.status.isEmpty) {
return Center( return Center(
child: Text(_s.noTask), child: Text(l10n.noTask),
); );
} }
return ListView.builder( return ListView.builder(
@@ -63,8 +55,8 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
switch (status.status) { switch (status.status) {
case SftpWorkerStatus.finished: case SftpWorkerStatus.finished:
final time = status.spentTime.toString(); final time = status.spentTime.toString();
final str = '${_s.finished} ${_s.spentTime( final str = '${l10n.finished} ${l10n.spentTime(
time == 'null' ? _s.unknown : (time.substring(0, time.length - 7)), time == 'null' ? l10n.unknown : (time.substring(0, time.length - 7)),
)}'; )}';
return _wrapInCard( return _wrapInCard(
status: status, status: status,
@@ -91,29 +83,29 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
final size = (status.size ?? 0).convertBytes; final size = (status.size ?? 0).convertBytes;
return _wrapInCard( return _wrapInCard(
status: status, status: status,
subtitle: _s.percentOfSize(percentStr, size), subtitle: l10n.percentOfSize(percentStr, size),
trailing: _buildDelete(status.fileName, status.id), trailing: _buildDelete(status.fileName, status.id),
); );
case SftpWorkerStatus.preparing: case SftpWorkerStatus.preparing:
return _wrapInCard( return _wrapInCard(
status: status, status: status,
subtitle: _s.sftpDlPrepare, subtitle: l10n.sftpDlPrepare,
trailing: _buildDelete(status.fileName, status.id), trailing: _buildDelete(status.fileName, status.id),
); );
case SftpWorkerStatus.sshConnectted: case SftpWorkerStatus.sshConnectted:
return _wrapInCard( return _wrapInCard(
status: status, status: status,
subtitle: _s.sftpSSHConnected, subtitle: l10n.sftpSSHConnected,
trailing: _buildDelete(status.fileName, status.id), trailing: _buildDelete(status.fileName, status.id),
); );
default: default:
return _wrapInCard( return _wrapInCard(
status: status, status: status,
subtitle: _s.unknown, subtitle: l10n.unknown,
trailing: IconButton( trailing: IconButton(
onPressed: () => context.showRoundDialog( onPressed: () => context.showRoundDialog(
title: Text(_s.error), title: Text(l10n.error),
child: Text((status.error ?? _s.unknown).toString()), child: Text((status.error ?? l10n.unknown).toString()),
), ),
icon: const Icon(Icons.error), icon: const Icon(Icons.error),
), ),
@@ -144,15 +136,15 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
Widget _buildDelete(String name, int id) { Widget _buildDelete(String name, int id) {
return IconButton( return IconButton(
onPressed: () => context.showRoundDialog( onPressed: () => context.showRoundDialog(
title: Text(_s.attention), title: Text(l10n.attention),
child: Text(_s.sureDelete(name)), child: Text(l10n.sureDelete(name)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () { onPressed: () {
Providers.sftp.cancel(id); Providers.sftp.cancel(id);
context.pop(); context.pop();
}, },
child: Text(_s.ok), child: Text(l10n.ok),
), ),
]), ]),
icon: const Icon(Icons.delete), icon: const Icon(Icons.delete),

View File

@@ -1,9 +1,9 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/extension/context/snackbar.dart';
import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/extension/ssh_client.dart';
import 'package:toolbox/core/extension/uint8list.dart'; import 'package:toolbox/core/extension/uint8list.dart';
@@ -25,12 +25,10 @@ import 'tag.dart';
class ServerFuncBtnsTopRight extends StatelessWidget { class ServerFuncBtnsTopRight extends StatelessWidget {
final ServerPrivateInfo spi; final ServerPrivateInfo spi;
final S s;
const ServerFuncBtnsTopRight({ const ServerFuncBtnsTopRight({
super.key, super.key,
required this.spi, required this.spi,
required this.s,
}); });
@override @override
@@ -45,13 +43,13 @@ class ServerFuncBtnsTopRight extends StatelessWidget {
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
Text(e.text(s)), Text(e.toStr),
], ],
), ),
)) ))
.toList(), .toList(),
padding: const EdgeInsets.symmetric(horizontal: 10), padding: const EdgeInsets.symmetric(horizontal: 10),
onSelected: (val) => _onTapMoreBtns(val, spi, context, s), onSelected: (val) => _onTapMoreBtns(val, spi, context),
); );
} }
} }
@@ -60,12 +58,10 @@ class ServerFuncBtns extends StatelessWidget {
const ServerFuncBtns({ const ServerFuncBtns({
super.key, super.key,
required this.spi, required this.spi,
required this.s,
this.iconSize, this.iconSize,
}); });
final ServerPrivateInfo spi; final ServerPrivateInfo spi;
final S s;
final double? iconSize; final double? iconSize;
@override @override
@@ -74,7 +70,7 @@ class ServerFuncBtns extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,
children: ServerTabMenuType.values children: ServerTabMenuType.values
.map((e) => IconButton( .map((e) => IconButton(
onPressed: () => _onTapMoreBtns(e, spi, context, s), onPressed: () => _onTapMoreBtns(e, spi, context),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
tooltip: e.name, tooltip: e.name,
icon: Icon(e.icon, size: iconSize ?? 15), icon: Icon(e.icon, size: iconSize ?? 15),
@@ -88,16 +84,15 @@ void _onTapMoreBtns(
ServerTabMenuType value, ServerTabMenuType value,
ServerPrivateInfo spi, ServerPrivateInfo spi,
BuildContext context, BuildContext context,
S s,
) async { ) async {
switch (value) { switch (value) {
case ServerTabMenuType.pkg: case ServerTabMenuType.pkg:
_onPkg(context, s, spi); _onPkg(context, spi);
break; break;
case ServerTabMenuType.sftp: case ServerTabMenuType.sftp:
AppRoute.sftp(spi: spi).checkGo( AppRoute.sftp(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id, s.waitConnection), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenuType.snippet: case ServerTabMenuType.snippet:
@@ -114,12 +109,12 @@ void _onTapMoreBtns(
final result = await Providers.server.runSnippets(spi.id, snippets); final result = await Providers.server.runSnippets(spi.id, snippets);
if (result != null && result.isNotEmpty) { if (result != null && result.isNotEmpty) {
context.showRoundDialog( context.showRoundDialog(
title: Text(s.result), title: Text(l10n.result),
child: Text(result), child: Text(result),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => copy2Clipboard(result), onPressed: () => copy2Clipboard(result),
child: Text(s.copy), child: Text(l10n.copy),
) )
], ],
); );
@@ -128,13 +123,13 @@ void _onTapMoreBtns(
case ServerTabMenuType.docker: case ServerTabMenuType.docker:
AppRoute.docker(spi: spi).checkGo( AppRoute.docker(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id, s.waitConnection), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenuType.process: case ServerTabMenuType.process:
AppRoute.process(spi: spi).checkGo( AppRoute.process(spi: spi).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id, s.waitConnection), check: () => _checkClient(context, spi.id),
); );
break; break;
case ServerTabMenuType.terminal: case ServerTabMenuType.terminal:
@@ -192,19 +187,19 @@ Future<void> _gotoSSH(
} }
} }
bool _checkClient(BuildContext context, String id, String msg) { bool _checkClient(BuildContext context, String id) {
final server = Providers.server.servers[id]; final server = Providers.server.servers[id];
if (server == null || server.client == null) { if (server == null || server.client == null) {
context.showSnackBar(msg); context.showSnackBar(l10n.waitConnection);
return false; return false;
} }
return true; return true;
} }
Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async { Future<void> _onPkg(BuildContext context, ServerPrivateInfo spi) async {
final server = spi.findServer; final server = spi.findServer;
if (server == null) { if (server == null) {
context.showSnackBar(s.noClient); context.showSnackBar(l10n.noClient);
return; return;
} }
final sys = server.status.sysVer; final sys = server.status.sysVer;
@@ -232,13 +227,13 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
final result = await server.client?.run(listCmd).string; final result = await server.client?.run(listCmd).string;
context.pop(); context.pop();
if (result == null) { if (result == null) {
context.showSnackBar(s.noResult); context.showSnackBar(l10n.noResult);
return; return;
} }
final list = pkg?.updateListRemoveUnused(result.split('\n')); final list = pkg?.updateListRemoveUnused(result.split('\n'));
final upgradeable = list?.map((e) => UpgradePkgInfo(e, pkg)).toList(); final upgradeable = list?.map((e) => UpgradePkgInfo(e, pkg)).toList();
if (upgradeable == null || upgradeable.isEmpty) { if (upgradeable == null || upgradeable.isEmpty) {
context.showSnackBar(s.noUpdateAvailable); context.showSnackBar(l10n.noUpdateAvailable);
return; return;
} }
final args = upgradeable.map((e) => e.package).join(' '); final args = upgradeable.map((e) => e.package).join(' ');
@@ -247,14 +242,14 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
// Confirm upgrade // Confirm upgrade
final gotoUpgrade = await context.showRoundDialog<bool>( final gotoUpgrade = await context.showRoundDialog<bool>(
title: Text(s.attention), title: Text(l10n.attention),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Text('${s.foundNUpdate(upgradeable.length)}\n\n$upgradeCmd'), child: Text('${l10n.foundNUpdate(upgradeable.length)}\n\n$upgradeCmd'),
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(true), onPressed: () => context.pop(true),
child: Text(s.update), child: Text(l10n.update),
), ),
], ],
); );
@@ -263,6 +258,6 @@ Future<void> _onPkg(BuildContext context, S s, ServerPrivateInfo spi) async {
AppRoute.ssh(spi: spi, initCmd: upgradeCmd).checkGo( AppRoute.ssh(spi: spi, initCmd: upgradeCmd).checkGo(
context: context, context: context,
check: () => _checkClient(context, spi.id, s.waitConnection), check: () => _checkClient(context, spi.id),
); );
} }

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:toolbox/core/extension/context/common.dart'; import 'package:toolbox/core/extension/context/common.dart';
import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/extension/context/dialog.dart';
import 'package:toolbox/core/extension/context/locale.dart';
import 'package:toolbox/data/res/ui.dart'; import 'package:toolbox/data/res/ui.dart';
import 'package:toolbox/view/widget/input_field.dart'; import 'package:toolbox/view/widget/input_field.dart';
import 'package:toolbox/view/widget/round_rect_card.dart'; import 'package:toolbox/view/widget/round_rect_card.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import '../../data/model/app/tag_pickable.dart'; import '../../data/model/app/tag_pickable.dart';
import '../../data/res/color.dart'; import '../../data/res/color.dart';
@@ -39,7 +39,6 @@ class TagBtn extends StatelessWidget {
class TagEditor extends StatefulWidget { class TagEditor extends StatefulWidget {
final List<String> tags; final List<String> tags;
final S s;
final void Function(List<String>)? onChanged; final void Function(List<String>)? onChanged;
final void Function(String old, String new_)? onRenameTag; final void Function(String old, String new_)? onRenameTag;
final List<String> allTags; final List<String> allTags;
@@ -47,7 +46,6 @@ class TagEditor extends StatefulWidget {
const TagEditor({ const TagEditor({
super.key, super.key,
required this.tags, required this.tags,
required this.s,
this.onChanged, this.onChanged,
this.onRenameTag, this.onRenameTag,
this.allTags = const <String>[], this.allTags = const <String>[],
@@ -78,7 +76,7 @@ class _TagEditorState extends State<TagEditor> {
/// Add vertical divider if suggestions.length > 0 /// Add vertical divider if suggestions.length > 0
final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1); final counts = tags.length + suggestionLen + (suggestionLen == 0 ? 0 : 1);
if (counts == 0) return Text(widget.s.tag); if (counts == 0) return Text(l10n.tag);
return ConstrainedBox( return ConstrainedBox(
constraints: const BoxConstraints(maxHeight: _kTagBtnHeight), constraints: const BoxConstraints(maxHeight: _kTagBtnHeight),
child: ListView.builder( child: ListView.builder(
@@ -134,12 +132,12 @@ class _TagEditorState extends State<TagEditor> {
void _showAddTagDialog() { void _showAddTagDialog() {
final textEditingController = TextEditingController(); final textEditingController = TextEditingController();
context.showRoundDialog( context.showRoundDialog(
title: Text(widget.s.add), title: Text(l10n.add),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
icon: Icons.tag, icon: Icons.tag,
controller: textEditingController, controller: textEditingController,
hint: widget.s.tag, hint: l10n.tag,
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -149,7 +147,7 @@ class _TagEditorState extends State<TagEditor> {
widget.onChanged?.call(widget.tags); widget.onChanged?.call(widget.tags);
context.pop(); context.pop();
}, },
child: Text(widget.s.add), child: Text(l10n.add),
), ),
], ],
); );
@@ -158,12 +156,12 @@ class _TagEditorState extends State<TagEditor> {
void _showRenameDialog(String tag) { void _showRenameDialog(String tag) {
final textEditingController = TextEditingController(text: tag); final textEditingController = TextEditingController(text: tag);
context.showRoundDialog( context.showRoundDialog(
title: Text(widget.s.rename), title: Text(l10n.rename),
child: Input( child: Input(
autoFocus: true, autoFocus: true,
icon: Icons.abc, icon: Icons.abc,
controller: textEditingController, controller: textEditingController,
hint: widget.s.tag, hint: l10n.tag,
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -174,7 +172,7 @@ class _TagEditorState extends State<TagEditor> {
context.pop(); context.pop();
setState(() {}); setState(() {});
}, },
child: Text(widget.s.rename), child: Text(l10n.rename),
), ),
], ],
); );
@@ -196,14 +194,12 @@ class TagPicker<T extends TagPickable> extends StatefulWidget {
} }
class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> { class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
late S _s;
late MediaQueryData _media; late MediaQueryData _media;
final List<T> _selected = []; final List<T> _selected = [];
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_s = S.of(context)!;
_media = MediaQuery.of(context); _media = MediaQuery.of(context);
} }
@@ -211,7 +207,7 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final children = <Widget>[]; final children = <Widget>[];
if (widget.tags.isNotEmpty) { if (widget.tags.isNotEmpty) {
children.add(Text(_s.tag)); children.add(Text(l10n.tag));
children.add(UIs.height13); children.add(UIs.height13);
children.add(SizedBox( children.add(SizedBox(
height: _kTagBtnHeight, height: _kTagBtnHeight,
@@ -220,7 +216,7 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
)); ));
} }
if (widget.items.isNotEmpty) { if (widget.items.isNotEmpty) {
children.add(Text(_s.all)); children.add(Text(l10n.all));
children.add(UIs.height13); children.add(UIs.height13);
children.add(SizedBox( children.add(SizedBox(
height: _kTagBtnHeight, height: _kTagBtnHeight,
@@ -229,15 +225,15 @@ class _TagPickerState<T extends TagPickable> extends State<TagPicker<T>> {
)); ));
} }
final child = widget.tags.isEmpty && widget.items.isEmpty final child = widget.tags.isEmpty && widget.items.isEmpty
? Text(_s.noOptions) ? Text(l10n.noOptions)
: Column(mainAxisSize: MainAxisSize.min, children: children); : Column(mainAxisSize: MainAxisSize.min, children: children);
return AlertDialog( return AlertDialog(
title: Text(_s.choose), title: Text(l10n.choose),
content: child, content: child,
actions: [ actions: [
TextButton( TextButton(
onPressed: () => context.pop(_selected), onPressed: () => context.pop(_selected),
child: Text(_s.ok), child: Text(l10n.ok),
), ),
], ],
); );