diff --git a/README.md b/README.md index 2c86887d9..853b30d4c 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ Platform | Support | Sign - In order to push server status to your portable device without opening ServerBox app (Such as **message push** and **home widget**), you need to install [ServerBoxMonitor](https://github.com/lollipopkit/server_box_monitor) on your servers, and config it correctly. See [wiki](https://github.com/lollipopkit/server_box_monitor/wiki) for more details. - **Common issues** can be found in [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki). - If you have **any question or feature request**, please open a [discussion](https://github.com/lollipopkit/flutter_server_box/discussions/new/choose). -- If ServerBox app has **any bug**, please open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new). +- If ServerBox app has **any bug**, please open an [issue](https://github.com/lollipopkit/flutter_server_box/issues/new) with **screenshots of ENTIRE LOG page** (at top right of home page). ## 🧱 Contribution diff --git a/README_zh.md b/README_zh.md index 48fd5357d..72d540519 100644 --- a/README_zh.md +++ b/README_zh.md @@ -80,7 +80,7 @@ - 为了可以在不使用 ServerBox app 时获取服务器状态(例如:桌面小部件、推送服务),你需要在你的服务器上安装 [ServerBoxMonitor](https://github.com/lollipopkit/server_box_monitor),并且正确配置,详情可见 [wiki](https://github.com/lollipopkit/server_box_monitor/wiki/%E4%B8%BB%E9%A1%B5)。 - **常见问题**可以在 [app wiki](https://github.com/lollipopkit/flutter_server_box/wiki/主页) 查看。 - 如果你有**任何问题或者功能请求**,请在 [讨论](https://github.com/lollipopkit/flutter_server_box/discussions/new/choose) 中交流。 -- 如果 ServerBox app 有**任何 bug**,请在 [问题](https://github.com/lollipopkit/flutter_server_box/issues/new) 中反馈。 +- 如果 ServerBox app 有**任何 bug**,请在 [问题](https://github.com/lollipopkit/flutter_server_box/issues/new) 中反馈,并且附带**完整的 Log 页截图**(点主界面右上角按钮进入)。 ## 🧱 贡献 diff --git a/lib/core/utils/misc.dart b/lib/core/utils/misc.dart index b5d803195..f8246e44a 100644 --- a/lib/core/utils/misc.dart +++ b/lib/core/utils/misc.dart @@ -1,34 +1,8 @@ -import 'dart:io'; import 'package:file_picker/file_picker.dart'; -import 'package:flutter/services.dart'; import 'package:plain_notification_token/plain_notification_token.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/data/res/provider.dart'; -Future shareFiles(List filePaths) async { - for (final filePath in filePaths) { - if (!await File(filePath).exists()) { - return false; - } - } - var text = ''; - if (filePaths.length == 1) { - text = filePaths.first.split('/').last; - } else { - text = '${filePaths.length} ${l10n.files}'; - } - Pros.app.moveBg = false; - // ignore: deprecated_member_use - await Share.shareFiles(filePaths, subject: text); - Pros.app.moveBg = true; - return filePaths.isNotEmpty; -} - -void copy2Clipboard(String text) { - Clipboard.setData(ClipboardData(text: text)); -} Future pickOneFile() async { Pros.app.moveBg = false; diff --git a/lib/core/utils/share.dart b/lib/core/utils/share.dart new file mode 100644 index 000000000..63225253c --- /dev/null +++ b/lib/core/utils/share.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flutter/services.dart'; +import 'package:share_plus/share_plus.dart'; +import 'package:toolbox/core/extension/context/locale.dart'; +import 'package:toolbox/data/res/provider.dart'; + +class Shares { + const Shares._(); + + static Future files(List filePaths) async { + for (final filePath in filePaths) { + if (!await File(filePath).exists()) { + return false; + } + } + var text = ''; + if (filePaths.length == 1) { + text = filePaths.first.split('/').last; + } else { + text = '${filePaths.length} ${l10n.files}'; + } + Pros.app.moveBg = false; + // ignore: deprecated_member_use + await Share.shareFiles(filePaths, subject: text); + Pros.app.moveBg = true; + return filePaths.isNotEmpty; + } + + static Future text(String text) async { + Pros.app.moveBg = false; + await Share.share(text); + Pros.app.moveBg = true; + return true; + } + + static void copy(String text) { + Clipboard.setData(ClipboardData(text: text)); + } + + static Future paste([String type = 'text/plain']) async { + final data = await Clipboard.getData(type); + return data?.text; + } +} diff --git a/lib/data/model/app/backup.dart b/lib/data/model/app/backup.dart index 1bb3ce29f..4ae89a6ea 100644 --- a/lib/data/model/app/backup.dart +++ b/lib/data/model/app/backup.dart @@ -63,9 +63,11 @@ class Backup { dockerHosts = Stores.docker.fetchAll(), settings = Stores.setting.toJson(); - static Future backup() async { + static Future backup() async { final result = _diyEncrtpt(json.encode(Backup.loadFromStore())); - await File(await Paths.bak).writeAsString(result); + final path = await Paths.bak; + await File(path).writeAsString(result); + return path; } Future restore() async { diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 99e3b44d5..ab2dca8a3 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -308,14 +308,13 @@ class ServerProvider extends ChangeNotifier { try { Loggers.app.warning('Using SFTP to write script to ${spi.name}'); file.writeAsString(ShellFunc.allScript); - final sftp = Pros.sftp; final completer = Completer(); - final reqId = sftp.add( + final reqId = Pros.sftp.add( SftpReq(spi, installShellPath, localPath, SftpReqType.upload), completer: completer, ); await completer.future; - final err = sftp.get(reqId)?.error; + final err = Pros.sftp.get(reqId)?.error; if (err != null) { throw err; } diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index 007ee4f11..5dcc69438 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -10,9 +10,9 @@ import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/persistant_store.dart'; import 'package:toolbox/core/utils/icloud.dart'; import 'package:toolbox/core/utils/platform/base.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/app/backup.dart'; import 'package:toolbox/data/res/logger.dart'; -import 'package:toolbox/data/res/path.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/rebuild.dart'; import 'package:toolbox/data/res/store.dart'; @@ -20,7 +20,6 @@ import 'package:toolbox/view/widget/expand_tile.dart'; import 'package:toolbox/view/widget/cardx.dart'; import 'package:toolbox/view/widget/store_switch.dart'; import 'package:toolbox/view/widget/value_notifier.dart'; -import 'package:url_launcher/url_launcher.dart'; import '../../core/utils/misc.dart'; import '../../data/res/ui.dart'; @@ -149,17 +148,14 @@ class BackupPage extends StatelessWidget { } Future _onBackup() async { - await Backup.backup(); - final path = await Paths.bak; + final path = await Backup.backup(); /// Issue #188 if (isWindows) { - await launchUrl( - File(path).uri, - mode: LaunchMode.externalNonBrowserApplication, - ); + await Shares.text(await File(path).readAsString()); + } else { - await shareFiles([path]); + await Shares.files([path]); } } diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index bad0511b2..5834b2fec 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -6,7 +6,7 @@ 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/uint8list.dart'; -import 'package:toolbox/core/utils/misc.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/view/widget/value_notifier.dart'; @@ -89,7 +89,7 @@ class _PingPageState extends State child: Text(e.toString()), actions: [ TextButton( - onPressed: () => copy2Clipboard(e.toString()), + onPressed: () => Shares.copy(e.toString()), child: Text(l10n.copy), ), ], diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart index af95915e9..8d222c078 100644 --- a/lib/view/page/process.dart +++ b/lib/view/page/process.dart @@ -7,7 +7,7 @@ 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/uint8list.dart'; -import 'package:toolbox/core/utils/misc.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/res/store.dart'; import '../../data/model/app/shell_func.dart'; @@ -111,7 +111,7 @@ class _ProcessPageState extends State { child: SingleChildScrollView(child: Text(_result.error!)), actions: [ TextButton( - onPressed: () => copy2Clipboard(_result.error!), + onPressed: () => Shares.copy(_result.error!), child: Text(l10n.copy), ), ], diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index c749d175c..bdded850e 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -9,12 +9,12 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/media_queryx.dart'; import 'package:toolbox/core/extension/ssh_client.dart'; import 'package:toolbox/core/utils/platform/base.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/app/shell_func.dart'; import 'package:toolbox/data/res/provider.dart'; import 'package:toolbox/data/res/store.dart'; import '../../../core/route.dart'; -import '../../../core/utils/misc.dart'; import '../../../data/model/app/net_view.dart'; import '../../../data/model/server/disk.dart'; import '../../../data/model/server/server.dart'; @@ -412,7 +412,7 @@ class _ServerPageState extends State ), actions: [ TextButton( - onPressed: () => copy2Clipboard(ss.failedInfo!), + onPressed: () => Shares.copy(ss.failedInfo!), child: Text(l10n.copy), ) ], diff --git a/lib/view/page/setting/ios.dart b/lib/view/page/setting/ios.dart index 3502e8627..e04ee6d85 100644 --- a/lib/view/page/setting/ios.dart +++ b/lib/view/page/setting/ios.dart @@ -7,6 +7,7 @@ import 'package:toolbox/core/extension/context/snackbar.dart'; import 'package:toolbox/core/route.dart'; import 'package:toolbox/core/utils/misc.dart'; import 'package:toolbox/core/utils/platform/auth.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/res/logger.dart'; import 'package:toolbox/data/res/misc.dart'; import 'package:toolbox/data/res/store.dart'; @@ -58,7 +59,7 @@ class _IOSSettingsPageState extends State { padding: EdgeInsets.zero, onPressed: () { if (_pushToken.value != null) { - copy2Clipboard(_pushToken.value!); + Shares.copy(_pushToken.value!); context.showSnackBar(l10n.success); } else { context.showSnackBar(l10n.getPushTokenFailed); diff --git a/lib/view/page/ssh_term.dart b/lib/view/page/ssh_term.dart index a0e62bdbe..082b70cda 100644 --- a/lib/view/page/ssh_term.dart +++ b/lib/view/page/ssh_term.dart @@ -11,6 +11,7 @@ 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/utils/platform/base.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/model/server/snippet.dart'; import 'package:toolbox/data/provider/virtual_keyboard.dart'; import 'package:toolbox/data/res/provider.dart'; @@ -249,7 +250,7 @@ class _SSHPageState extends State { case VirtualKeyFunc.clipboard: final selected = terminalSelected; if (selected != null) { - copy2Clipboard(selected); + Shares.copy(selected); } else { _paste(); } diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart index dd9931c60..465f44293 100644 --- a/lib/view/page/storage/local.dart +++ b/lib/view/page/storage/local.dart @@ -5,6 +5,7 @@ import 'package:toolbox/core/extension/context/common.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/utils/share.dart'; import 'package:toolbox/data/model/server/server_private_info.dart'; import 'package:toolbox/data/model/sftp/req.dart'; import 'package:toolbox/data/res/misc.dart'; @@ -303,7 +304,7 @@ class _LocalStoragePageState extends State { leading: const Icon(Icons.open_in_new), title: Text(l10n.open), onTap: () { - shareFiles([file.absolute.path]); + Shares.files([file.absolute.path]); }, ), ], diff --git a/lib/view/page/storage/sftp_mission.dart b/lib/view/page/storage/sftp_mission.dart index e03058c7c..8e7e5ff46 100644 --- a/lib/view/page/storage/sftp_mission.dart +++ b/lib/view/page/storage/sftp_mission.dart @@ -5,10 +5,10 @@ import 'package:toolbox/core/extension/context/locale.dart'; import 'package:toolbox/core/extension/datetime.dart'; import 'package:toolbox/core/extension/context/dialog.dart'; import 'package:toolbox/core/route.dart'; +import 'package:toolbox/core/utils/share.dart'; import 'package:toolbox/data/res/provider.dart'; import '../../../core/extension/numx.dart'; -import '../../../core/utils/misc.dart'; import '../../../data/model/sftp/req.dart'; import '../../../data/provider/sftp.dart'; import '../../../data/res/ui.dart'; @@ -72,7 +72,7 @@ class _SftpMissionPageState extends State { }, icon: const Icon(Icons.file_open)), IconButton( - onPressed: () => shareFiles([status.req.localPath]), + onPressed: () => Shares.files([status.req.localPath]), icon: const Icon(Icons.open_in_new), ) ],