diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index edce4046..bd2385b3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -359,7 +359,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -367,7 +367,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.287; + MARKETING_VERSION = 1.0.288; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -490,7 +490,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -498,7 +498,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.287; + MARKETING_VERSION = 1.0.288; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -515,7 +515,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; - CURRENT_PROJECT_VERSION = 287; + CURRENT_PROJECT_VERSION = 288; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; @@ -523,7 +523,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.287; + MARKETING_VERSION = 1.0.288; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/core/utils/ui.dart b/lib/core/utils/ui.dart index eb05bbd8..16ed056e 100644 --- a/lib/core/utils/ui.dart +++ b/lib/core/utils/ui.dart @@ -166,9 +166,9 @@ void showSnippetDialog( showRoundDialog( context: context, title: Text(s.chooseDestination), - child: buildPicker( - provider.snippets.map((e) => Text(e.name)).toList(), - (idx) => snippet = provider.snippets[idx], + child: Picker( + items: provider.snippets.map((e) => Text(e.name)).toList(), + onSelected: (idx) => snippet = provider.snippets[idx], ), actions: [ TextButton( diff --git a/lib/data/provider/private_key.dart b/lib/data/provider/private_key.dart index eb792edd..43272c85 100644 --- a/lib/data/provider/private_key.dart +++ b/lib/data/provider/private_key.dart @@ -5,28 +5,29 @@ import 'package:toolbox/locator.dart'; class PrivateKeyProvider extends BusyProvider { List get infos => _infos; + final _store = locator(); late List _infos; void loadData() { - _infos = locator().fetch(); + _infos = _store.fetch(); } void addInfo(PrivateKeyInfo info) { _infos.add(info); - locator().put(info); + _store.put(info); notifyListeners(); } void delInfo(PrivateKeyInfo info) { _infos.removeWhere((e) => e.id == info.id); - locator().delete(info); + _store.delete(info); notifyListeners(); } void updateInfo(PrivateKeyInfo old, PrivateKeyInfo newInfo) { final idx = _infos.indexWhere((e) => e.id == old.id); _infos[idx] = newInfo; - locator().put(newInfo); + _store.put(newInfo); notifyListeners(); } } diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart index 8703d494..d3dd4af8 100644 --- a/lib/data/provider/server.dart +++ b/lib/data/provider/server.dart @@ -22,15 +22,18 @@ typedef ServersMap = Map; class ServerProvider extends BusyProvider { final ServersMap _servers = {}; ServersMap get servers => _servers; + final _limiter = TryLimiter(); Timer? _timer; final _logger = Logger('SERVER'); + final _store = locator(); + Future loadLocalData() async { setBusyState(true); - final infos = locator().fetch(); + final infos = _store.fetch(); for (final info in infos) { _servers[info.id] = genServer(info); } @@ -103,20 +106,20 @@ class ServerProvider extends BusyProvider { void addServer(ServerPrivateInfo spi) { _servers[spi.id] = genServer(spi); notifyListeners(); - locator().put(spi); + _store.put(spi); refreshData(spi: spi); } void delServer(String id) { _servers.remove(id); notifyListeners(); - locator().delete(id); + _store.delete(id); } Future updateServer( ServerPrivateInfo old, ServerPrivateInfo newSpi) async { _servers.remove(old.id); - locator().update(old, newSpi); + _store.update(old, newSpi); _servers[newSpi.id] = genServer(newSpi); _servers[newSpi.id]?.client = await genClient(newSpi); notifyListeners(); diff --git a/lib/data/provider/snippet.dart b/lib/data/provider/snippet.dart index 248a9a6d..e6e32289 100644 --- a/lib/data/provider/snippet.dart +++ b/lib/data/provider/snippet.dart @@ -7,23 +7,24 @@ import 'package:toolbox/locator.dart'; class SnippetProvider extends BusyProvider { List get snippets => _snippets; + final _store = locator(); late List _snippets; void loadData() { - _snippets = locator().fetch(); + _snippets = _store.fetch(); } void add(Snippet snippet) { if (have(snippet)) return; _snippets.add(snippet); - locator().put(snippet); + _store.put(snippet); notifyListeners(); } void del(Snippet snippet) { if (!have(snippet)) return; _snippets.removeAt(index(snippet)); - locator().delete(snippet); + _store.delete(snippet); notifyListeners(); } @@ -38,7 +39,7 @@ class SnippetProvider extends BusyProvider { void update(Snippet old, Snippet newOne) { if (!have(old)) return; _snippets[index(old)] = newOne; - locator().put(newOne); + _store.put(newOne); notifyListeners(); } diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index e38c075f..81fc95b5 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,8 +2,8 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 287; + static const int build = 288; static const String engine = "3.7.11"; - static const String buildAt = "2023-05-07 18:25:45.312302"; - static const int modifications = 2; + static const String buildAt = "2023-05-07 20:47:03.124092"; + static const int modifications = 1; } diff --git a/lib/data/res/ui.dart b/lib/data/res/ui.dart index dde53279..eaf40c8c 100644 --- a/lib/data/res/ui.dart +++ b/lib/data/res/ui.dart @@ -33,3 +33,15 @@ const popMenuChild = Padding( size: 21, ), ); + +const centerLoading = Center(child: CircularProgressIndicator()); + +const centerSizedLoading = SizedBox( + width: 77, + height: 77, + child: Center( + child: CircularProgressIndicator(), + ), +); + +const loadingIcon = IconButton(onPressed: null, icon: centerLoading); diff --git a/lib/data/res/url.dart b/lib/data/res/url.dart index 7509ab42..e640d065 100644 --- a/lib/data/res/url.dart +++ b/lib/data/res/url.dart @@ -6,6 +6,7 @@ const issueUrl = '$myGithub/flutter_server_box/issues'; // Thanks const thanksMap = { + 'its-tom': 'https://github.com/its-tom', 'RainSunMe': 'https://github.com/RainSunMe', 'fecture': 'https://github.com/fecture', 'Tao173': 'https://github.com/Tao173', diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart index eddab4c2..6fb1d209 100644 --- a/lib/view/page/backup.dart +++ b/lib/view/page/backup.dart @@ -32,74 +32,78 @@ class BackupPage extends StatelessWidget { @override Widget build(BuildContext context) { - final media = MediaQuery.of(context); final s = S.of(context)!; return Scaffold( appBar: AppBar( title: Text(s.backupAndRestore, style: textSize18), ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.all(37), - child: Text( - s.backupTip, - textAlign: TextAlign.center, - ), - ), - const SizedBox( - height: 107, - ), - _buildCard(s.restore, Icons.download, media, () async { - final path = await pickOneFile(); - if (path == null) { - showSnackBar(context, Text(s.notSelected)); - return; - } - final file = File(path); - if (!file.existsSync()) { - showSnackBar(context, Text(s.fileNotExist(path))); - return; - } - final text = await file.readAsString(); - _import(text, context, s); - }), - const SizedBox(height: 17), - const SizedBox( - width: 37, - child: Divider(), - ), - const SizedBox(height: 17), - _buildCard( - s.backup, - Icons.file_upload, - media, - () async { - final result = _diyEncrtpt( - json.encode( - Backup( - backupFormatVersion, - DateTime.now().toString().split('.').first, - _server.fetch(), - _snippet.fetch(), - _privateKey.fetch(), - _dockerHosts.fetch(), - ), - ), - ); - final path = '${(await docDir).path}/srvbox_bak.json'; - await File(path).writeAsString(result); - await shareFiles(context, [path]); - }, - ) - ], - )), + body: _buildBody(context, s), ); } + Widget _buildBody(BuildContext context, S s) { + final media = MediaQuery.of(context); + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.all(37), + child: Text( + s.backupTip, + textAlign: TextAlign.center, + ), + ), + const SizedBox( + height: 107, + ), + _buildCard(s.restore, Icons.download, media, () async { + final path = await pickOneFile(); + if (path == null) { + showSnackBar(context, Text(s.notSelected)); + return; + } + final file = File(path); + if (!file.existsSync()) { + showSnackBar(context, Text(s.fileNotExist(path))); + return; + } + final text = await file.readAsString(); + _import(text, context, s); + }), + const SizedBox(height: 17), + const SizedBox( + width: 37, + child: Divider(), + ), + const SizedBox(height: 17), + _buildCard( + s.backup, + Icons.file_upload, + media, + () async { + final result = _diyEncrtpt( + json.encode( + Backup( + backupFormatVersion, + DateTime.now().toString().split('.').first, + _server.fetch(), + _snippet.fetch(), + _privateKey.fetch(), + _dockerHosts.fetch(), + ), + ), + ); + final path = '${(await docDir).path}/srvbox_bak.json'; + await File(path).writeAsString(result); + await shareFiles(context, [path]); + }, + ) + ], + )); + } + Widget _buildCard(String text, IconData icon, MediaQueryData media, FutureOr Function() onTap) { final textColor = primaryColor.isBrightColor ? Colors.black : Colors.white; diff --git a/lib/view/page/convert.dart b/lib/view/page/convert.dart index aab3207d..45a37812 100644 --- a/lib/view/page/convert.dart +++ b/lib/view/page/convert.dart @@ -89,7 +89,7 @@ class _ConvertPageState extends State Widget _buildInputTop() { return SizedBox( height: _media.size.height * 0.33, - child: buildInput(controller: _textEditingController), + child: Input(controller: _textEditingController), ); } @@ -163,7 +163,7 @@ class _ConvertPageState extends State Widget _buildResult() { return SizedBox( height: _media.size.height * 0.33, - child: buildInput(controller: _textEditingControllerResult), + child: Input(controller: _textEditingControllerResult), ); } diff --git a/lib/view/page/docker.dart b/lib/view/page/docker.dart index f9d7da7c..22840fd4 100644 --- a/lib/view/page/docker.dart +++ b/lib/view/page/docker.dart @@ -15,7 +15,6 @@ import '../../data/res/ui.dart'; import '../../data/res/url.dart'; import '../../data/store/docker.dart'; import '../../locator.dart'; -import '../widget/center_loading.dart'; import '../widget/dropdown_menu.dart'; import '../widget/round_rect_card.dart'; import '../widget/two_line_text.dart'; @@ -95,26 +94,23 @@ class _DockerManagePageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - buildInput( + Input( type: TextInputType.text, label: _s.dockerImage, hint: 'xxx:1.1', controller: imageCtrl, - autoCorrect: false, ), - buildInput( + Input( type: TextInputType.text, controller: nameCtrl, label: _s.dockerContainerName, hint: 'xxx', - autoCorrect: false, ), - buildInput( + Input( type: TextInputType.text, controller: argsCtrl, label: _s.extraArgs, hint: '-p 2222:22 -v ~/.xxx/:/xxx', - autoCorrect: false, ), ], ), @@ -206,7 +202,7 @@ class _DockerManagePageState extends State { await showRoundDialog( context: context, title: Text(widget.spi.user), - child: buildInput( + child: Input( controller: _textController, type: TextInputType.visiblePassword, obscureText: true, @@ -379,9 +375,8 @@ class _DockerManagePageState extends State { await showRoundDialog( context: context, title: Text(_s.dockerEditHost), - child: buildInput( + child: Input( maxLines: 1, - autoCorrect: false, controller: TextEditingController(text: 'unix:///run/user/1000/docker.sock'), onSubmitted: (value) { diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart index 26bc4fde..1ba754ba 100644 --- a/lib/view/page/ping.dart +++ b/lib/view/page/ping.dart @@ -57,7 +57,7 @@ class _PingPageState extends State child: Column( children: [ const SizedBox(height: 13), - buildInput( + Input( controller: _textEditingController, hint: s.inputDomainHere, maxLines: 1, diff --git a/lib/view/page/pkg.dart b/lib/view/page/pkg.dart index 94aa2a02..d1ac6d4b 100644 --- a/lib/view/page/pkg.dart +++ b/lib/view/page/pkg.dart @@ -12,7 +12,6 @@ import '../../data/provider/pkg.dart'; import '../../data/provider/server.dart'; import '../../data/res/ui.dart'; import '../../locator.dart'; -import '../widget/center_loading.dart'; import '../widget/round_rect_card.dart'; import '../widget/two_line_text.dart'; @@ -31,7 +30,7 @@ class _PkgManagePageState extends State final _scrollController = ScrollController(); final _scrollControllerUpdate = ScrollController(); final _textController = TextEditingController(); - final _aptProvider = locator(); + final _pkgProvider = locator(); late S _s; @override @@ -44,7 +43,7 @@ class _PkgManagePageState extends State @override void dispose() { super.dispose(); - locator().clear(); + _pkgProvider.clear(); } @override @@ -57,7 +56,7 @@ class _PkgManagePageState extends State return; } - _aptProvider.init( + _pkgProvider.init( si.client!, si.status.sysVer.dist, () => @@ -67,7 +66,21 @@ class _PkgManagePageState extends State onPwdRequest, widget.spi.user, ); - _aptProvider.refresh(); + _pkgProvider.refresh(); + } + + @override + Widget build(BuildContext context) { + return Consumer(builder: (_, pkg, __) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: TwoLineText(up: _s.pkg, down: widget.spi.name), + ), + body: _buildBody(pkg), + floatingActionButton: _buildFAB(pkg), + ); + }); } void onSubmitted() { @@ -92,7 +105,7 @@ class _PkgManagePageState extends State await showRoundDialog( context: context, title: Text(widget.spi.user), - child: buildInput( + child: Input( controller: _textController, type: TextInputType.visiblePassword, obscureText: true, @@ -118,20 +131,6 @@ class _PkgManagePageState extends State return _textController.text.trim(); } - @override - Widget build(BuildContext context) { - return Consumer(builder: (_, pkg, __) { - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: TwoLineText(up: _s.pkg, down: widget.spi.name), - ), - body: _buildBody(pkg), - floatingActionButton: _buildFAB(pkg), - ); - }); - } - Widget _buildFAB(PkgProvider pkg) { if (pkg.isBusy || (pkg.upgradeable?.isEmpty ?? true)) { return const SizedBox(); diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart index dcc36ade..8059a93b 100644 --- a/lib/view/page/private_key/edit.dart +++ b/lib/view/page/private_key/edit.dart @@ -61,128 +61,138 @@ class _PrivateKeyEditPageState extends State @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - title: Text(_s.edit, style: textSize18), - actions: [ - widget.info != null - ? IconButton( - tooltip: _s.delete, - onPressed: () { - _provider.delInfo(widget.info!); - context.pop(); - }, - icon: const Icon(Icons.delete)) - : const SizedBox() - ], - ), - body: ListView( - padding: const EdgeInsets.all(13), - children: [ - buildInput( - controller: _nameController, - type: TextInputType.text, - node: _nameNode, - onSubmitted: (_) => _focusScope.requestFocus(_keyNode), - label: _s.name, - icon: Icons.info, - ), - buildInput( - controller: _keyController, - autoCorrect: false, - minLines: 3, - maxLines: 10, - type: TextInputType.text, - node: _keyNode, - onSubmitted: (_) => _focusScope.requestFocus(_pwdNode), - label: _s.privateKey, - icon: Icons.vpn_key, - ), - TextButton( - onPressed: () async { - final path = await pickOneFile(); - if (path == null) { - showSnackBar(context, const Text('path is null')); - return; - } + appBar: _buildAppBar(), + body: _buildBody(), + floatingActionButton: _buildFAB(), + ); + } - final file = File(path); - if (!file.existsSync()) { - showSnackBar(context, Text(_s.fileNotExist(path))); - return; - } - final size = (await file.stat()).size; - if (size > privateKeyMaxSize) { - showSnackBar( - context, - Text( - _s.fileTooLarge( - path, - size.convertBytes, - privateKeyMaxSize.convertBytes, - ), - ), - ); - return; - } + PreferredSizeWidget _buildAppBar() { + return AppBar( + title: Text(_s.edit, style: textSize18), + actions: [ + widget.info != null + ? IconButton( + tooltip: _s.delete, + onPressed: () { + _provider.delInfo(widget.info!); + context.pop(); + }, + icon: const Icon(Icons.delete)) + : const SizedBox() + ], + ); + } - _keyController.text = await file.readAsString(); - }, - child: Text(_s.pickFile), - ), - buildInput( - controller: _pwdController, - autoCorrect: false, - type: TextInputType.text, - node: _pwdNode, - obscureText: true, - label: _s.pwd, - icon: Icons.password, - ), - SizedBox(height: MediaQuery.of(context).size.height * 0.1), - _loading - ], - ), - floatingActionButton: FloatingActionButton( - tooltip: _s.save, - onPressed: () async { - final name = _nameController.text; - final key = _keyController.text.trim(); - final pwd = _pwdController.text; - if (name.isEmpty || key.isEmpty) { - showSnackBar(context, Text(_s.fieldMustNotEmpty)); - return; - } - FocusScope.of(context).unfocus(); + Widget _buildFAB() { + return FloatingActionButton( + tooltip: _s.save, + onPressed: () async { + final name = _nameController.text; + final key = _keyController.text.trim(); + final pwd = _pwdController.text; + if (name.isEmpty || key.isEmpty) { + showSnackBar(context, Text(_s.fieldMustNotEmpty)); + return; + } + FocusScope.of(context).unfocus(); + setState(() { + _loading = const SizedBox( + height: 50, + child: Center( + child: CircularProgressIndicator(), + ), + ); + }); + final info = PrivateKeyInfo(name, key, ''); + bool haveErr = false; + try { + info.privateKey = await compute(decyptPem, [key, pwd]); + } catch (e) { + showSnackBar(context, Text(e.toString())); + haveErr = true; + } finally { setState(() { - _loading = const SizedBox( - height: 50, - child: Center( - child: CircularProgressIndicator(), - ), - ); + _loading = const SizedBox(); }); - final info = PrivateKeyInfo(name, key, ''); - bool haveErr = false; - try { - info.privateKey = await compute(decyptPem, [key, pwd]); - } catch (e) { - showSnackBar(context, Text(e.toString())); - haveErr = true; - } finally { - setState(() { - _loading = const SizedBox(); - }); - } - if (haveErr) return; - if (widget.info != null) { - _provider.updateInfo(widget.info!, info); - } else { - _provider.addInfo(info); - } - context.pop(); - }, - child: const Icon(Icons.save), - ), + } + if (haveErr) return; + if (widget.info != null) { + _provider.updateInfo(widget.info!, info); + } else { + _provider.addInfo(info); + } + context.pop(); + }, + child: const Icon(Icons.save), + ); + } + + Widget _buildBody() { + return ListView( + padding: const EdgeInsets.all(13), + children: [ + Input( + controller: _nameController, + type: TextInputType.text, + node: _nameNode, + onSubmitted: (_) => _focusScope.requestFocus(_keyNode), + label: _s.name, + icon: Icons.info, + ), + Input( + controller: _keyController, + minLines: 3, + maxLines: 10, + type: TextInputType.text, + node: _keyNode, + onSubmitted: (_) => _focusScope.requestFocus(_pwdNode), + label: _s.privateKey, + icon: Icons.vpn_key, + ), + TextButton( + onPressed: () async { + final path = await pickOneFile(); + if (path == null) { + showSnackBar(context, const Text('path is null')); + return; + } + + final file = File(path); + if (!file.existsSync()) { + showSnackBar(context, Text(_s.fileNotExist(path))); + return; + } + final size = (await file.stat()).size; + if (size > privateKeyMaxSize) { + showSnackBar( + context, + Text( + _s.fileTooLarge( + path, + size.convertBytes, + privateKeyMaxSize.convertBytes, + ), + ), + ); + return; + } + + _keyController.text = await file.readAsString(); + }, + child: Text(_s.pickFile), + ), + Input( + controller: _pwdController, + type: TextInputType.text, + node: _pwdNode, + obscureText: true, + label: _s.pwd, + icon: Icons.password, + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.1), + _loading + ], ); } diff --git a/lib/view/page/private_key/list.dart b/lib/view/page/private_key/list.dart index debb993e..4a0b3f4e 100644 --- a/lib/view/page/private_key/list.dart +++ b/lib/view/page/private_key/list.dart @@ -30,41 +30,44 @@ class _PrivateKeyListState extends State { appBar: AppBar( title: Text(_s.privateKey, style: textSize18), ), - body: Consumer( - builder: (_, key, __) { - if (key.infos.isEmpty) { - return Center( - child: Text(_s.noSavedPrivateKey), - ); - } - return ListView.builder( - padding: const EdgeInsets.all(13), - itemCount: key.infos.length, - itemBuilder: (context, idx) { - return RoundRectCard( - ListTile( - title: Text( - key.infos[idx].id, - ), - trailing: TextButton( - onPressed: () => AppRoute( - PrivateKeyEditPage(info: key.infos[idx]), - 'private key edit page', - ).go(context), - child: Text(_s.edit), - ), - ), - ); - }, - ); - }, - ), + body: _buildBody(), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), - onPressed: () => - AppRoute(const PrivateKeyEditPage(), 'private key edit page') - .go(context), + onPressed: () => AppRoute( + const PrivateKeyEditPage(), + 'private key edit page', + ).go(context), ), ); } + + Widget _buildBody() { + return Consumer( + builder: (_, key, __) { + if (key.infos.isEmpty) { + return Center( + child: Text(_s.noSavedPrivateKey), + ); + } + return ListView.builder( + padding: const EdgeInsets.all(13), + itemCount: key.infos.length, + itemBuilder: (context, idx) { + return RoundRectCard( + ListTile( + title: Text(key.infos[idx].id), + trailing: TextButton( + onPressed: () => AppRoute( + PrivateKeyEditPage(info: key.infos[idx]), + 'private key edit page', + ).go(context), + child: Text(_s.edit), + ), + ), + ); + }, + ); + }, + ); + } } diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart index fd11698b..daf9a68c 100644 --- a/lib/view/page/server/edit.dart +++ b/lib/view/page/server/edit.dart @@ -108,7 +108,7 @@ class _ServerEditPageState extends State with AfterLayoutMixin { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - buildInput( + Input( controller: _nameController, type: TextInputType.text, node: _nameFocus, @@ -117,17 +117,16 @@ class _ServerEditPageState extends State with AfterLayoutMixin { label: _s.name, icon: Icons.info, ), - buildInput( + Input( controller: _ipController, type: TextInputType.text, onSubmitted: (_) => _focusScope.requestFocus(_portFocus), node: _ipFocus, - autoCorrect: false, label: _s.host, icon: Icons.storage, hint: 'example.com', ), - buildInput( + Input( controller: _portController, type: TextInputType.number, node: _portFocus, @@ -136,11 +135,10 @@ class _ServerEditPageState extends State with AfterLayoutMixin { icon: Icons.format_list_numbered, hint: '22', ), - buildInput( + Input( controller: _usernameController, type: TextInputType.text, node: _usernameFocus, - autoCorrect: false, label: _s.user, icon: Icons.account_box, hint: 'root', @@ -158,7 +156,7 @@ class _ServerEditPageState extends State with AfterLayoutMixin { ], ), !usePublicKey - ? buildInput( + ? Input( controller: _passwordController, obscureText: true, type: TextInputType.text, diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart index 4a17f5b1..a2c2ef08 100644 --- a/lib/view/page/server/tab.dart +++ b/lib/view/page/server/tab.dart @@ -62,38 +62,7 @@ class _ServerPageState extends State Widget build(BuildContext context) { super.build(context); return Scaffold( - body: RefreshIndicator( - onRefresh: () async => - await _serverProvider.refreshData(onlyFailed: true), - child: Consumer( - builder: (_, pro, __) { - if (pro.servers.isEmpty) { - return Center( - child: Text( - _s.serverTabEmpty, - textAlign: TextAlign.center, - ), - ); - } - final keys = pro.servers.keys.toList(); - return ListView.separated( - padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), - controller: ScrollController(), - physics: const AlwaysScrollableScrollPhysics(), - itemBuilder: (ctx, idx) { - if (idx == pro.servers.length) { - return SizedBox(height: _media.padding.bottom); - } - return _buildEachServerCard(pro.servers[keys[idx]]); - }, - itemCount: pro.servers.length, - separatorBuilder: (_, __) => const SizedBox( - height: 3, - ), - ); - }, - ), - ), + body: _buildBody(), floatingActionButton: FloatingActionButton( onPressed: () => AppRoute( const ServerEditPage(), @@ -106,6 +75,41 @@ class _ServerPageState extends State ); } + Widget _buildBody() { + return RefreshIndicator( + onRefresh: () async => + await _serverProvider.refreshData(onlyFailed: true), + child: Consumer( + builder: (_, pro, __) { + if (pro.servers.isEmpty) { + return Center( + child: Text( + _s.serverTabEmpty, + textAlign: TextAlign.center, + ), + ); + } + final keys = pro.servers.keys.toList(); + return ListView.separated( + padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), + controller: ScrollController(), + physics: const AlwaysScrollableScrollPhysics(), + itemBuilder: (ctx, idx) { + if (idx == pro.servers.length) { + return SizedBox(height: _media.padding.bottom); + } + return _buildEachServerCard(pro.servers[keys[idx]]); + }, + itemCount: pro.servers.length, + separatorBuilder: (_, __) => const SizedBox( + height: 3, + ), + ); + }, + ), + ); + } + Widget _buildEachServerCard(Server? si) { if (si == null) { return const SizedBox(); diff --git a/lib/view/page/sftp/downloading.dart b/lib/view/page/sftp/downloading.dart index 34de5bc7..d8067473 100644 --- a/lib/view/page/sftp/downloading.dart +++ b/lib/view/page/sftp/downloading.dart @@ -8,7 +8,6 @@ import '../../../core/utils/ui.dart'; import '../../../data/model/sftp/download_status.dart'; import '../../../data/provider/sftp_download.dart'; import '../../../data/res/ui.dart'; -import '../../widget/center_loading.dart'; import '../../widget/round_rect_card.dart'; class SFTPDownloadingPage extends StatefulWidget { diff --git a/lib/view/page/sftp/view.dart b/lib/view/page/sftp/view.dart index 072b0fb0..3335ef85 100644 --- a/lib/view/page/sftp/view.dart +++ b/lib/view/page/sftp/view.dart @@ -18,9 +18,9 @@ import '../../../data/model/sftp/download_item.dart'; import '../../../data/provider/server.dart'; import '../../../data/provider/sftp_download.dart'; import '../../../data/res/path.dart'; +import '../../../data/res/ui.dart'; import '../../../data/store/private_key.dart'; import '../../../locator.dart'; -import '../../widget/center_loading.dart'; import '../../widget/fade_in.dart'; import '../../widget/two_line_text.dart'; import 'downloading.dart'; @@ -144,7 +144,7 @@ class _SFTPPageState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - buildInput( + Input( label: _s.path, hint: '/', onSubmitted: (value) => context.pop(value), @@ -378,7 +378,7 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.createFolder), - child: buildInput( + child: Input( controller: textController, label: _s.name, ), @@ -422,7 +422,7 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.createFile), - child: buildInput( + child: Input( controller: textController, label: _s.name, ), @@ -467,7 +467,7 @@ class _SFTPPageState extends State { showRoundDialog( context: context, title: Text(_s.rename), - child: buildInput( + child: Input( controller: textController, label: _s.name, ), diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart index db791bc4..e5356fa4 100644 --- a/lib/view/page/snippet/edit.dart +++ b/lib/view/page/snippet/edit.dart @@ -57,47 +57,53 @@ class _SnippetEditPageState extends State : const SizedBox() ], ), - body: ListView( - padding: const EdgeInsets.all(13), - children: [ - buildInput( - controller: _nameController, - type: TextInputType.text, - onSubmitted: (_) => - FocusScope.of(context).requestFocus(_scriptNode), - label: _s.name, - icon: Icons.info, - ), - buildInput( - controller: _scriptController, - autoCorrect: false, - node: _scriptNode, - minLines: 3, - maxLines: 10, - type: TextInputType.text, - label: _s.snippet, - icon: Icons.code, - ), - ], - ), - floatingActionButton: FloatingActionButton( - child: const Icon(Icons.send), - onPressed: () { - final name = _nameController.text; - final script = _scriptController.text; - if (name.isEmpty || script.isEmpty) { - showSnackBar(context, Text(_s.fieldMustNotEmpty)); - return; - } - final snippet = Snippet(name, script); - if (widget.snippet != null) { - _provider.update(widget.snippet!, snippet); - } else { - _provider.add(snippet); - } - context.pop(); - }, - ), + body: _buildBody(), + floatingActionButton: _buildFAB(), + ); + } + + Widget _buildFAB() { + return FloatingActionButton( + child: const Icon(Icons.send), + onPressed: () { + final name = _nameController.text; + final script = _scriptController.text; + if (name.isEmpty || script.isEmpty) { + showSnackBar(context, Text(_s.fieldMustNotEmpty)); + return; + } + final snippet = Snippet(name, script); + if (widget.snippet != null) { + _provider.update(widget.snippet!, snippet); + } else { + _provider.add(snippet); + } + context.pop(); + }, + ); + } + + Widget _buildBody() { + return ListView( + padding: const EdgeInsets.all(13), + children: [ + Input( + controller: _nameController, + type: TextInputType.text, + onSubmitted: (_) => FocusScope.of(context).requestFocus(_scriptNode), + label: _s.name, + icon: Icons.info, + ), + Input( + controller: _scriptController, + node: _scriptNode, + minLines: 3, + maxLines: 10, + type: TextInputType.text, + label: _s.snippet, + icon: Icons.code, + ), + ], ); } diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 25b0fc52..5cc1ea37 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -76,61 +76,6 @@ class _SSHPageState extends State { super.dispose(); } - void _write(String p0) { - _terminal.write('$p0\r\n'); - } - - Future initTerminal() async { - _write('Connecting...\r\n'); - - _client = await genClient( - widget.spi, - onStatus: (p0) { - switch (p0) { - case GenSSHClientStatus.socket: - _write('Destination: ${widget.spi.id}'); - return _write('Establishing socket...'); - case GenSSHClientStatus.key: - return _write('Using private key to connect...'); - case GenSSHClientStatus.pwd: - return _write('Sending password to auth...'); - } - }, - ); - _write('Connected\r\n'); - _write('Terminal size: ${_terminal.viewWidth}x${_terminal.viewHeight}\r\n'); - _write('Starting shell...\r\n'); - - final session = await _client!.shell( - pty: SSHPtyConfig( - width: _terminal.viewWidth, - height: _terminal.viewHeight, - ), - ); - - _terminal.buffer.clear(); - _terminal.buffer.setCursor(0, 0); - - _terminal.onOutput = (data) { - session.write(utf8.encode(data) as Uint8List); - }; - - _listen(session.stdout); - _listen(session.stderr); - - await session.done; - if (mounted) { - context.pop(); - } - } - - void _listen(Stream stream) { - stream - .cast>() - .transform(const Utf8Decoder()) - .listen(_terminal.write); - } - @override Widget build(BuildContext context) { Widget child = Scaffold( @@ -357,4 +302,59 @@ class _SSHPageState extends State { }, ); } + + void _write(String p0) { + _terminal.write('$p0\r\n'); + } + + Future initTerminal() async { + _write('Connecting...\r\n'); + + _client = await genClient( + widget.spi, + onStatus: (p0) { + switch (p0) { + case GenSSHClientStatus.socket: + _write('Destination: ${widget.spi.id}'); + return _write('Establishing socket...'); + case GenSSHClientStatus.key: + return _write('Using private key to connect...'); + case GenSSHClientStatus.pwd: + return _write('Sending password to auth...'); + } + }, + ); + _write('Connected\r\n'); + _write('Terminal size: ${_terminal.viewWidth}x${_terminal.viewHeight}\r\n'); + _write('Starting shell...\r\n'); + + final session = await _client!.shell( + pty: SSHPtyConfig( + width: _terminal.viewWidth, + height: _terminal.viewHeight, + ), + ); + + _terminal.buffer.clear(); + _terminal.buffer.setCursor(0, 0); + + _terminal.onOutput = (data) { + session.write(utf8.encode(data) as Uint8List); + }; + + _listen(session.stdout); + _listen(session.stderr); + + await session.done; + if (mounted) { + context.pop(); + } + } + + void _listen(Stream stream) { + stream + .cast>() + .transform(const Utf8Decoder()) + .listen(_terminal.write); + } } diff --git a/lib/view/widget/center_loading.dart b/lib/view/widget/center_loading.dart deleted file mode 100644 index c7599cea..00000000 --- a/lib/view/widget/center_loading.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:flutter/material.dart'; - -const centerLoading = Center(child: CircularProgressIndicator()); - -const centerSizedLoading = SizedBox( - width: 77, - height: 77, - child: Center( - child: CircularProgressIndicator(), - ), -); - -final loadingIcon = IconButton(onPressed: () {}, icon: centerLoading); diff --git a/lib/view/widget/input_field.dart b/lib/view/widget/input_field.dart index 082aad97..5bdd57f5 100644 --- a/lib/view/widget/input_field.dart +++ b/lib/view/widget/input_field.dart @@ -1,38 +1,59 @@ import 'package:flutter/material.dart'; -import 'package:toolbox/view/widget/round_rect_card.dart'; -Widget buildInput({ - TextEditingController? controller, - int maxLines = 1, - int? minLines, - String? hint, - String? label, - Function(String)? onSubmitted, - bool obscureText = false, - IconData? icon, - TextInputType? type, - FocusNode? node, - bool autoCorrect = true, -}) { - return RoundRectCard( - Padding( - padding: const EdgeInsets.symmetric(horizontal: 17), - child: TextField( - maxLines: maxLines, - minLines: minLines, - onSubmitted: onSubmitted, - keyboardType: type, - focusNode: node, - autocorrect: autoCorrect, - decoration: InputDecoration( - label: label != null ? Text(label) : null, - hintText: hint, - icon: icon != null ? Icon(icon) : null, - border: InputBorder.none, +import 'round_rect_card.dart'; + +class Input extends StatelessWidget { + final TextEditingController? controller; + final int maxLines; + final int? minLines; + final String? hint; + final String? label; + final Function(String)? onSubmitted; + final bool obscureText; + final IconData? icon; + final TextInputType? type; + final FocusNode? node; + final bool autoCorrect; + final bool suggestiion; + + const Input({ + super.key, + this.controller, + this.maxLines = 1, + this.minLines, + this.hint, + this.label, + this.onSubmitted, + this.obscureText = false, + this.icon, + this.type, + this.node, + this.autoCorrect = false, + this.suggestiion = false, + }); + @override + Widget build(BuildContext context) { + return RoundRectCard( + Padding( + padding: const EdgeInsets.symmetric(horizontal: 17), + child: TextField( + maxLines: maxLines, + minLines: minLines, + onSubmitted: onSubmitted, + keyboardType: type, + focusNode: node, + autocorrect: autoCorrect, + enableSuggestions: suggestiion, + decoration: InputDecoration( + label: label != null ? Text(label!) : null, + hintText: hint, + icon: icon != null ? Icon(icon) : null, + border: InputBorder.none, + ), + controller: controller, + obscureText: obscureText, ), - controller: controller, - obscureText: obscureText, ), - ), - ); + ); + } } diff --git a/lib/view/widget/picker.dart b/lib/view/widget/picker.dart index 9163b33d..10c110c7 100644 --- a/lib/view/widget/picker.dart +++ b/lib/view/widget/picker.dart @@ -1,42 +1,52 @@ import 'package:flutter/material.dart'; -Widget buildPicker( - List items, - Function(int idx) onSelected, { - double height = 157, -}) { - final pad = (height - 37) / 2; - return SizedBox( - height: height, - child: Stack( - children: [ - Positioned( - top: pad, - bottom: pad, - left: 0, - right: 0, - child: Container( - height: 37, - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(7)), - color: Colors.black12, +class Picker extends StatelessWidget { + final List items; + final Function(int idx) onSelected; + final double height; + + const Picker({ + super.key, + required this.items, + required this.onSelected, + this.height = 157, + }); + + @override + Widget build(BuildContext context) { + final pad = (height - 37) / 2; + return SizedBox( + height: height, + child: Stack( + children: [ + Positioned( + top: pad, + bottom: pad, + left: 0, + right: 0, + child: Container( + height: 37, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(7)), + color: Colors.black12, + ), ), ), - ), - ListWheelScrollView.useDelegate( - itemExtent: 37, - diameterRatio: 2.7, - controller: FixedExtentScrollController(initialItem: 0), - onSelectedItemChanged: (idx) => onSelected(idx), - physics: const FixedExtentScrollPhysics(), - childDelegate: ListWheelChildBuilderDelegate( - builder: (context, index) => Center( - child: items[index], + ListWheelScrollView.useDelegate( + itemExtent: 37, + diameterRatio: 2.7, + controller: FixedExtentScrollController(initialItem: 0), + onSelectedItemChanged: (idx) => onSelected(idx), + physics: const FixedExtentScrollPhysics(), + childDelegate: ListWheelChildBuilderDelegate( + builder: (context, index) => Center( + child: items[index], + ), + childCount: items.length, ), - childCount: items.length, - ), - ) - ], - ), - ); + ) + ], + ), + ); + } } diff --git a/pubspec.lock b/pubspec.lock index 9083888b..b5a1b54a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: e440ac42679dfc04bbbefb58ed225c994bc7e07fccc8a68ec7d3631a127e5da9 + sha256: "8880b4cfe7b5b17d57c052a5a3a8cc1d4f546261c7cc8fbd717bd53f48db0568" url: "https://pub.dev" source: hosted - version: "54.0.0" + version: "59.0.0" after_layout: dependency: "direct main" description: @@ -21,26 +21,26 @@ packages: dependency: transitive description: name: analyzer - sha256: "2c2e3721ee9fb36de92faa060f3480c81b23e904352b087e5c64224b1a044427" + sha256: a89627f49b0e70e068130a36571409726b04dab12da7e5625941d2c8ec278b96 url: "https://pub.dev" source: hosted - version: "5.6.0" + version: "5.11.1" archive: dependency: transitive description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a" url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.3.7" args: dependency: transitive description: name: args - sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" asn1lib: dependency: transitive description: @@ -125,10 +125,10 @@ packages: dependency: transitive description: name: built_value - sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" + sha256: "2f17434bd5d52a26762043d6b43bb53b3acd029b4d9071a329f46d67ef297e6d" url: "https://pub.dev" source: hosted - version: "8.4.3" + version: "8.5.0" characters: dependency: transitive description: @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" circle_chart: dependency: "direct main" description: @@ -206,10 +206,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" csslib: dependency: transitive description: @@ -222,10 +222,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4" + sha256: f4f1f73ab3fd2afcbcca165ee601fe980d966af6a21b5970c6c9376955c528ad url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.3.1" dartssh2: dependency: "direct main" description: @@ -270,10 +270,10 @@ packages: dependency: transitive description: name: extended_image_library - sha256: b1de389378589e4dffb3564d782373238f19064037458092c49b3043b2791b2b + sha256: "550743b43ab093aed35ef234500fcc7a304cbac1eca47b0cc991e07e88750758" url: "https://pub.dev" source: hosted - version: "3.4.1" + version: "3.4.2" fake_async: dependency: transitive description: @@ -302,10 +302,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: d090ae03df98b0247b82e5928f44d1b959867049d18d73635e2e0bc3f49542b9 + sha256: b85eb92b175767fdaa0c543bf3b0d1f610fe966412ea72845fe5ba7801e763ff url: "https://pub.dev" source: hosted - version: "5.2.5" + version: "5.2.10" fixnum: dependency: transitive description: @@ -344,18 +344,18 @@ packages: dependency: "direct dev" description: name: flutter_native_splash - sha256: e301ae206ff0fb09b67d3716009c6c28c2da57a0ad164827b178421bb9d601f7 + sha256: af665ef80a213a9ed502845a3d7a61b9acca4100ee7e9f067a7440bc3acd6730 url: "https://pub.dev" source: hosted - version: "2.2.18" + version: "2.2.19" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: "4bef634684b2c7f3468c77c766c831229af829a0cd2d4ee6c1b99558bd14e5d2" + sha256: "96af49aa6b57c10a312106ad6f71deed5a754029c24789bbf620ba784f0bd0b0" url: "https://pub.dev" source: hosted - version: "2.0.8" + version: "2.0.14" flutter_test: dependency: "direct dev" description: flutter @@ -378,10 +378,10 @@ packages: dependency: "direct main" description: name: get_it - sha256: "290fde3a86072e4b37dbb03c07bec6126f0ecc28dad403c12ffe2e5a2d751ab7" + sha256: "43133b45f32f1d96bbaeb43ea35a50ce854981baa80f47c3e26ee2ad23bef113" url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "7.5.0" glob: dependency: transitive description: @@ -426,26 +426,26 @@ packages: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.3" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "0.13.6" http_client_helper: dependency: transitive description: name: http_client_helper - sha256: "1f32359bd07a064ad256d1f84ae5f973f69bc972e7287223fa198abe1d969c28" + sha256: "14c6e756644339f561321dab021215475ba4779aa962466f59ccb3ecf66b36c3" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" http_multi_server: dependency: transitive description: @@ -466,10 +466,10 @@ packages: dependency: transitive description: name: image - sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227" + sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf url: "https://pub.dev" source: hosted - version: "4.0.15" + version: "4.0.17" intl: dependency: "direct main" description: @@ -498,10 +498,10 @@ packages: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.8.1" lints: dependency: transitive description: @@ -578,34 +578,34 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9" + sha256: c7edf82217d4b2952b2129a61d3ad60f1075b9299e629e149a8d2e39c2e6aad4 url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.0.14" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "7623b7d4be0f0f7d9a8b5ee6879fc13e4522d4c875ab86801dee4af32b54b83e" + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.23" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: eec003594f19fe2456ea965ae36b3fc967bc5005f508890aafe31fa75e41d972 + sha256: ad4c4d011830462633f03eb34445a45345673dfd4faf1ab0b4735fbd93b19183 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.2.2" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: "525ad5e07622d19447ad740b1ed5070031f7a5437f44355ae915ff56e986429a" + sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" url: "https://pub.dev" source: hosted - version: "2.1.9" + version: "2.1.10" path_provider_platform_interface: dependency: transitive description: @@ -618,10 +618,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "642ddf65fde5404f83267e8459ddb4556316d3ee6d511ed193357e25caa3632d" + sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.6" pedantic: dependency: transitive description: @@ -682,10 +682,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dev" source: hosted - version: "3.6.2" + version: "3.7.3" pool: dependency: transitive description: @@ -714,18 +714,18 @@ packages: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.3" quiver: dependency: transitive description: @@ -746,18 +746,18 @@ packages: dependency: "direct main" description: name: share_plus - sha256: "692261968a494e47323dcc8bc66d8d52e81bc27cb4b808e4e8d7e8079d4cc01a" + sha256: b1f15232d41e9701ab2f04181f21610c36c83a12ae426b79b4bd011c567934b1 url: "https://pub.dev" source: hosted - version: "6.3.2" + version: "6.3.4" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "82ddd4ab9260c295e6e39612d4ff00390b9a7a21f1bb1da771e2f232d80ab8a1" + sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.2.1" share_plus_web: dependency: "direct main" description: @@ -770,18 +770,18 @@ packages: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" sky_engine: dependency: transitive description: flutter @@ -791,10 +791,10 @@ packages: dependency: transitive description: name: source_gen - sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 + sha256: b20e191de6964e98032573cecb1d2b169d96ba63fdb586d24dcd1003ba7e94f6 url: "https://pub.dev" source: hosted - version: "1.2.7" + version: "1.3.0" source_helper: dependency: transitive description: @@ -895,34 +895,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "1f4d9ebe86f333c15d318f81dcdc08b01d45da44af74552608455ebdc08d9732" + sha256: "22f8db4a72be26e9e3a4aa3f194b1f7afbc76d20ec141f84be1d787db2155cbd" url: "https://pub.dev" source: hosted - version: "6.0.24" + version: "6.0.31" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: c9cd648d2f7ab56968e049d4e9116f96a85517f1dd806b96a86ea1018a3a82e5 + sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2" url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.4" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: e29039160ab3730e42f3d811dc2a6d5f2864b90a70fb765ea60144b03307f682 + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "2dddb3291a57b074dade66b5e07e64401dd2487caefd4e9e2f467138d8c7eb06" + sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" url_launcher_platform_interface: dependency: transitive description: @@ -935,18 +935,18 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "574cfbe2390666003c3a1d129bdc4574aaa6728f0c00a4829a81c316de69dd9b" + sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.0.16" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "97c9067950a0d09cbd93e2e3f0383d1403989362b97102fbf446473a48079a4b" + sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.6" uuid: dependency: transitive description: @@ -975,18 +975,18 @@ packages: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" win32: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" xdg_directories: dependency: transitive description: @@ -1008,18 +1008,26 @@ packages: description: path: "." ref: master - resolved-ref: "8039a582d855428cec49b23641bcfcafd6682574" + resolved-ref: e945750b97a2f875befa37e0c483bc3f51e215b2 url: "https://github.com/lollipopkit/xterm.dart" source: git - version: "3.4.1" + version: "3.6.1-pre" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" + zmodem: + dependency: transitive + description: + name: zmodem + sha256: "3b7e5b29f3a7d8aee472029b05165a68438eff2f3f7766edf13daba1e297adbf" + url: "https://pub.dev" + source: hosted + version: "0.0.6" sdks: dart: ">=2.19.0 <3.0.0" flutter: ">=3.3.0"