diff --git a/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt
index 23d6b3a5f..4f425ada7 100644
--- a/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt
+++ b/android/app/src/main/kotlin/tech/lolli/toolbox/widget/HomeWidget.kt
@@ -28,8 +28,11 @@ class HomeWidget : AppWidgetProvider() {
         val views = RemoteViews(context.packageName, R.layout.home_widget)
         val sp = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
         var url = sp.getString("widget_$appWidgetId", null)
-        val gUrl = sp.getString("widget_*", null)
         if (url.isNullOrEmpty()) {
+            url = sp.getString("$appWidgetId", null)
+        }
+        if (url.isNullOrEmpty()) {
+            val gUrl = sp.getString("widget_*", null)
             url = gUrl
         }
 
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 1bac63697..41a323b33 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -690,7 +690,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -700,7 +700,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -826,7 +826,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -836,7 +836,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -854,7 +854,7 @@
 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -864,7 +864,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -885,7 +885,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -898,7 +898,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
@@ -924,7 +924,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -937,7 +937,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -960,7 +960,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				GCC_C_LANGUAGE_STANDARD = gnu11;
 				GENERATE_INFOPLIST_FILE = YES;
@@ -973,7 +973,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.StatusWidget;
 				PRODUCT_NAME = "$(TARGET_NAME)";
@@ -996,7 +996,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_ASSET_PATHS = "";
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_PREVIEWS = YES;
@@ -1008,7 +1008,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
@@ -1037,7 +1037,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_ASSET_PATHS = "";
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_PREVIEWS = YES;
@@ -1049,7 +1049,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
 				PRODUCT_NAME = ServerBox;
@@ -1075,7 +1075,7 @@
 				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
 				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_ASSET_PATHS = "";
 				DEVELOPMENT_TEAM = BA88US33G6;
 				ENABLE_PREVIEWS = YES;
@@ -1087,7 +1087,7 @@
 					"$(inherited)",
 					"@executable_path/Frameworks",
 				);
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				MTL_FAST_MATH = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox.WatchEnd;
 				PRODUCT_NAME = ServerBox;
diff --git a/lib/app.dart b/lib/app.dart
index 800ea56f8..27c3f4bf4 100644
--- a/lib/app.dart
+++ b/lib/app.dart
@@ -22,7 +22,10 @@ class MyApp extends StatelessWidget {
       listenable: RNodes.app,
       builder: (context, _) {
         if (!Stores.setting.useSystemPrimaryColor.fetch()) {
-          UIs.colorSeed = Color(Stores.setting.colorSeed.fetch());
+          final colorSeed = Color(Stores.setting.colorSeed.fetch());
+          UIs.colorSeed = colorSeed;
+          // Past code uses [UIs.primaryColor] as the primary color
+          UIs.primaryColor = colorSeed;
           return _buildApp(
             context,
             light: ThemeData(
@@ -88,7 +91,6 @@ class MyApp extends StatelessWidget {
           context.setLibL10n();
           final appL10n = AppLocalizations.of(context);
           if (appL10n != null) l10n = appL10n;
-          UIs.primaryColor = Theme.of(context).colorScheme.primary;
 
           final intros = _IntroPage.builders;
           if (intros.isNotEmpty) {
diff --git a/lib/data/provider/server.dart b/lib/data/provider/server.dart
index 4063d5d4f..5d410229d 100644
--- a/lib/data/provider/server.dart
+++ b/lib/data/provider/server.dart
@@ -327,7 +327,8 @@ class ServerProvider extends ChangeNotifier {
         _setServerState(s, ServerConn.failed);
         return;
       } catch (e) {
-        TryLimiter.inc(sid);
+        // If max try times < 2 and can't write script, this will stop the status getting and etc.
+        // TryLimiter.inc(sid);
         final err = SSHErr(type: SSHErrType.writeScript, message: e.toString());
         s.status.err = err;
         Loggers.app.warning(err);
diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart
index a40a8783d..d1cc188d3 100644
--- a/lib/data/res/build_data.dart
+++ b/lib/data/res/build_data.dart
@@ -2,6 +2,6 @@
 
 class BuildData {
   static const String name = "ServerBox";
-  static const int build = 1047;
-  static const int script = 55;
+  static const int build = 1048;
+  static const int script = 56;
 }
diff --git a/lib/intro.dart b/lib/intro.dart
index 72274ac34..e61e7aeba 100644
--- a/lib/intro.dart
+++ b/lib/intro.dart
@@ -7,8 +7,6 @@ final class _IntroPage extends StatelessWidget {
 
   static const _builders = {
     1: _buildAppSettings,
-    2: _buildRecommended,
-    1006: _buildTermLetterCache,
   };
 
   @override
@@ -32,52 +30,6 @@ final class _IntroPage extends StatelessWidget {
     );
   }
 
-  static Widget _buildTermLetterCache(BuildContext context, double padTop) {
-    return ListView(
-      padding: _introListPad,
-      children: [
-        SizedBox(height: padTop),
-        IntroPage.title(icon: BoxIcons.bxs_terminal, big: true),
-        SizedBox(height: padTop),
-        ListTile(
-          leading: const Icon(Bootstrap.alphabet),
-          title: Text(l10n.letterCache),
-          subtitle: Text(l10n.letterCacheTip, style: UIs.textGrey),
-          trailing: StoreSwitch(prop: _setting.letterCache),
-        ).cardx,
-      ],
-    );
-  }
-
-  static Widget _buildRecommended(BuildContext context, double padTop) {
-    return ListView(
-      padding: _introListPad,
-      children: [
-        SizedBox(height: padTop),
-        IntroPage.title(icon: Bootstrap.stars, big: true),
-        SizedBox(height: padTop),
-        ListTile(
-          leading: const Icon(MingCute.delete_2_fill),
-          title: const Text('rm -r'),
-          subtitle: Text(l10n.sftpRmrDirSummary, style: UIs.textGrey),
-          trailing: StoreSwitch(prop: _setting.sftpRmrDir),
-        ).cardx,
-        ListTile(
-          leading: const Icon(MingCute.chart_line_line, size: _kIconSize),
-          title: Text(l10n.stat),
-          subtitle: Text(l10n.parseContainerStatsTip, style: UIs.textGrey),
-          trailing: StoreSwitch(prop: _setting.containerParseStat),
-        ).cardx,
-        ListTile(
-          leading: const Icon(OctIcons.cpu),
-          title: Text(l10n.noLineChartForCpu),
-          subtitle: Text(l10n.cpuViewAsProgressTip, style: UIs.textGrey),
-          trailing: StoreSwitch(prop: _setting.cpuViewAsProgress),
-        ).cardx,
-      ],
-    );
-  }
-
   static Widget _buildAppSettings(BuildContext ctx, double padTop) {
     return ListView(
       padding: _introListPad,
@@ -111,6 +63,30 @@ final class _IntroPage extends StatelessWidget {
           subtitle: Text(l10n.fdroidReleaseTip, style: UIs.textGrey),
           trailing: StoreSwitch(prop: _setting.autoCheckAppUpdate),
         ).cardx,
+        ListTile(
+          leading: const Icon(MingCute.delete_2_fill),
+          title: const Text('rm -r'),
+          subtitle: Text(l10n.sftpRmrDirSummary, style: UIs.textGrey),
+          trailing: StoreSwitch(prop: _setting.sftpRmrDir),
+        ).cardx,
+        ListTile(
+          leading: const Icon(MingCute.chart_line_line, size: _kIconSize),
+          title: Text(l10n.stat),
+          subtitle: Text(l10n.parseContainerStatsTip, style: UIs.textGrey),
+          trailing: StoreSwitch(prop: _setting.containerParseStat),
+        ).cardx,
+        ListTile(
+          leading: const Icon(OctIcons.cpu),
+          title: Text(l10n.noLineChartForCpu),
+          subtitle: Text(l10n.cpuViewAsProgressTip, style: UIs.textGrey),
+          trailing: StoreSwitch(prop: _setting.cpuViewAsProgress),
+        ).cardx,
+        ListTile(
+          leading: const Icon(Bootstrap.alphabet),
+          title: Text(l10n.letterCache),
+          subtitle: Text(l10n.letterCacheTip, style: UIs.textGrey),
+          trailing: StoreSwitch(prop: _setting.letterCache),
+        ).cardx,
       ],
     );
   }
diff --git a/lib/view/page/backup.dart b/lib/view/page/backup.dart
index 38426c655..7d06c0e6a 100644
--- a/lib/view/page/backup.dart
+++ b/lib/view/page/backup.dart
@@ -61,7 +61,7 @@ class BackupPage extends StatelessWidget {
       child: ExpandTile(
         leading: const Icon(Icons.file_open),
         title: Text(libL10n.file),
-        initiallyExpanded: true,
+        initiallyExpanded: false,
         children: [
           ListTile(
             title: Text(libL10n.backup),
@@ -112,7 +112,7 @@ class BackupPage extends StatelessWidget {
       child: ExpandTile(
         leading: const Icon(Icons.storage),
         title: const Text('WebDAV'),
-        initiallyExpanded: true,
+        initiallyExpanded: false,
         children: [
           ListTile(
             title: Text(l10n.setting),
@@ -261,11 +261,11 @@ class BackupPage extends StatelessWidget {
             ),
           ),
           actions: Btn.ok(
-            onTap: (c) {
+            onTap: () {
               for (final snippet in snippets) {
                 Pros.snippet.add(snippet);
               }
-              c.pop();
+              context.pop();
               context.pop();
             },
           ).toList,
@@ -294,7 +294,7 @@ class BackupPage extends StatelessWidget {
           '${libL10n.restore} ${libL10n.backup}(${backup.date})',
         )),
         actions: Btn.ok(
-          onTap: (c) async {
+          onTap: () async {
             await backup.restore(force: true);
             context.pop();
           },
@@ -386,7 +386,7 @@ class BackupPage extends StatelessWidget {
           ),
         ],
       ),
-      actions: Btn.ok(onTap: (c) => context.pop(true)).toList,
+      actions: Btnx.oks,
     );
     if (result == true) {
       final result = await Webdav.test(url.text, user.text, pwd.text);
@@ -423,7 +423,7 @@ class BackupPage extends StatelessWidget {
           '${libL10n.restore} ${libL10n.backup}(${backup.date})',
         )),
         actions: Btn.ok(
-          onTap: (c) async {
+          onTap: () async {
             await backup.restore(force: true);
             context.pop();
           },
@@ -454,7 +454,7 @@ class BackupPage extends StatelessWidget {
       final sure = await context.showRoundDialog<bool>(
         title: libL10n.import,
         child: Text(libL10n.askContinue('${spis.length} ${l10n.server}')),
-        actions: Btn.ok(onTap: (c) => context.pop(true)).toList,
+        actions: Btnx.oks,
       );
       if (sure == true) {
         final (suc, err) = await context.showLoadingDialog(
diff --git a/lib/view/page/container.dart b/lib/view/page/container.dart
index bdec423e0..75eec3b8a 100644
--- a/lib/view/page/container.dart
+++ b/lib/view/page/container.dart
@@ -353,7 +353,7 @@ class _ContainerPageState extends State<ContainerPage> {
             ),
           ],
         ),
-        actions: Btn.ok(onTap: (c) async {
+        actions: Btn.ok(onTap: () async {
           context.pop();
           await _showAddCmdPreview(
             _buildAddCmd(
@@ -421,7 +421,7 @@ class _ContainerPageState extends State<ContainerPage> {
         hint: 'unix:///run/user/1000/docker.sock',
         suggestion: false,
       ),
-      actions: Btn.ok(onTap: (c) => _onSaveDockerHost(ctrl.text)).toList,
+      actions: Btn.ok(onTap: () => _onSaveDockerHost(ctrl.text)).toList,
     );
   }
 
@@ -438,7 +438,7 @@ class _ContainerPageState extends State<ContainerPage> {
         libL10n.askContinue('${libL10n.delete} Image(${e.repository})'),
       ),
       actions: Btn.ok(
-        onTap: (c) async {
+        onTap: () async {
           context.pop();
           final result = await _container.run('rmi ${e.id} -f');
           if (result != null) {
@@ -483,7 +483,7 @@ class _ContainerPageState extends State<ContainerPage> {
               )
             ],
           ),
-          actions: Btn.ok(onTap: (c) async {
+          actions: Btn.ok(onTap: () async {
             context.pop();
 
             final (result, err) = await context.showLoadingDialog(
diff --git a/lib/view/page/ping.dart b/lib/view/page/ping.dart
index f4d42ec16..129a7e393 100644
--- a/lib/view/page/ping.dart
+++ b/lib/view/page/ping.dart
@@ -62,7 +62,7 @@ class _PingPageState extends State<PingPage>
             minLines: 1,
             onSubmitted: (_) => _doPing(),
           ),
-          actions: Btn.ok(onTap: (c) => _doPing()).toList,
+          actions: Btn.ok(onTap: _doPing).toList,
         );
       },
       child: const Icon(Icons.search),
diff --git a/lib/view/page/private_key/edit.dart b/lib/view/page/private_key/edit.dart
index 50261dc17..1f70cd536 100644
--- a/lib/view/page/private_key/edit.dart
+++ b/lib/view/page/private_key/edit.dart
@@ -88,7 +88,7 @@ class _PrivateKeyEditPageState extends State<PrivateKeyEditPage> {
               '${libL10n.delete} ${l10n.privateKey}(${widget.pki!.id})',
             )),
             actions: Btn.ok(
-              onTap: (c) {
+              onTap: () {
                 Pros.key.delete(widget.pki!);
                 context.pop();
                 context.pop();
diff --git a/lib/view/page/private_key/list.dart b/lib/view/page/private_key/list.dart
index ad44594c5..afc708ac2 100644
--- a/lib/view/page/private_key/list.dart
+++ b/lib/view/page/private_key/list.dart
@@ -80,7 +80,7 @@ class _PrivateKeyListState extends State<PrivateKeysListPage>
       context.showRoundDialog(
         title: libL10n.attention,
         child: Text(l10n.addSystemPrivateKeyTip),
-        actions: Btn.ok(onTap: (c) {
+        actions: Btn.ok(onTap: () {
           context.pop();
           AppRoutes.keyEdit(pki: sysPk).go(context);
         }).toList,
diff --git a/lib/view/page/process.dart b/lib/view/page/process.dart
index 958ce67ee..988675a3e 100644
--- a/lib/view/page/process.dart
+++ b/lib/view/page/process.dart
@@ -158,7 +158,7 @@ class _ProcessPageState extends State<ProcessPage> {
             child: Text(libL10n.askContinue(
               '${l10n.stop} ${l10n.process}(${proc.pid})',
             )),
-            actions: Btn.ok(onTap: (c) async {
+            actions: Btn.ok(onTap: () async {
               context.pop();
               await context.showLoadingDialog(fn: () async {
                 await _client?.run('kill ${proc.pid}');
diff --git a/lib/view/page/pve.dart b/lib/view/page/pve.dart
index 2b7bb3866..1858451bb 100644
--- a/lib/view/page/pve.dart
+++ b/lib/view/page/pve.dart
@@ -61,7 +61,7 @@ final class _PvePageState extends State<PvePage> {
                 ? UIs.placeholder
                 : Btn.icon(
                     icon: const Icon(Icons.refresh),
-                    onTap: (_) {
+                    onTap: () {
                       _pve.err.value = null;
                       _pve.list();
                       _initRefreshTimer();
@@ -397,22 +397,22 @@ final class _PvePageState extends State<PvePage> {
     if (!item.available) {
       return Btn.icon(
           icon: const Icon(Icons.play_arrow, color: Colors.grey),
-          onTap: (_) => _onCtrl(_pve.start, l10n.start, item));
+          onTap: () => _onCtrl(_pve.start, l10n.start, item));
     }
     return Row(
       children: [
         Btn.icon(
             icon: const Icon(Icons.stop, color: Colors.grey, size: 20),
             padding: pad,
-            onTap: (_) => _onCtrl(_pve.stop, l10n.stop, item)),
+            onTap: () => _onCtrl(_pve.stop, l10n.stop, item)),
         Btn.icon(
             icon: const Icon(Icons.refresh, color: Colors.grey, size: 20),
             padding: pad,
-            onTap: (_) => _onCtrl(_pve.reboot, l10n.reboot, item)),
+            onTap: () => _onCtrl(_pve.reboot, l10n.reboot, item)),
         Btn.icon(
             icon: const Icon(Icons.power_off, color: Colors.grey, size: 20),
             padding: pad,
-            onTap: (_) => _onCtrl(_pve.shutdown, l10n.shutdown, item)),
+            onTap: () => _onCtrl(_pve.shutdown, l10n.shutdown, item)),
       ],
     );
   }
@@ -421,10 +421,7 @@ final class _PvePageState extends State<PvePage> {
     final sure = await context.showRoundDialog<bool>(
       title: libL10n.attention,
       child: Text(libL10n.askContinue('$action ${item.id}')),
-      actions: Btn.ok(
-        onTap: (c) => context.pop(true),
-        red: true,
-      ).toList,
+      actions: Btnx.okReds,
     );
     if (sure != true) return;
 
diff --git a/lib/view/page/server/edit.dart b/lib/view/page/server/edit.dart
index ab14bf340..ffd784705 100644
--- a/lib/view/page/server/edit.dart
+++ b/lib/view/page/server/edit.dart
@@ -108,7 +108,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
             ));
           }),
           actions: Btn.ok(
-            onTap: (c) async {
+            onTap: () async {
               context.pop();
               Pros.server.delServer(widget.spi!.id);
               context.pop(true);
diff --git a/lib/view/page/server/tab.dart b/lib/view/page/server/tab.dart
index c877aa46c..cb0d3687f 100644
--- a/lib/view/page/server/tab.dart
+++ b/lib/view/page/server/tab.dart
@@ -345,7 +345,7 @@ class _ServerPageState extends State<ServerPage>
     const textStyle = TextStyle(color: Colors.grey);
     final children = [
       Btn.column(
-        onTap: (_) => _askFor(
+        onTap: () => _askFor(
           func: () async {
             if (Stores.setting.showSuspendTip.fetch()) {
               await context.showRoundDialog(
@@ -368,7 +368,7 @@ class _ServerPageState extends State<ServerPage>
         textStyle: textStyle,
       ),
       Btn.column(
-        onTap: (_) => _askFor(
+        onTap: () => _askFor(
           func: () => srv.client?.execWithPwd(
             ShellFunc.shutdown.exec(srv.spi.id),
             context: context,
@@ -382,7 +382,7 @@ class _ServerPageState extends State<ServerPage>
         textStyle: textStyle,
       ),
       Btn.column(
-        onTap: (_) => _askFor(
+        onTap: () => _askFor(
           func: () => srv.client?.execWithPwd(
             ShellFunc.reboot.exec(srv.spi.id),
             context: context,
@@ -396,7 +396,7 @@ class _ServerPageState extends State<ServerPage>
         textStyle: textStyle,
       ),
       Btn.column(
-        onTap: (_) => AppRoutes.serverEdit(spi: srv.spi).go(context),
+        onTap: () => AppRoutes.serverEdit(spi: srv.spi).go(context),
         icon: const Icon(Icons.edit, color: Colors.grey),
         text: libL10n.edit,
         textStyle: textStyle,
@@ -693,7 +693,7 @@ ${ss.err?.message ?? 'null'}
       title: libL10n.attention,
       child: Text(libL10n.askContinue('$typ ${l10n.server}($name)')),
       actions: Btn.ok(
-        onTap: (c) {
+        onTap: () {
           context.pop();
           func();
         },
diff --git a/lib/view/page/setting/entry.dart b/lib/view/page/setting/entry.dart
index f150950df..e5b19958d 100644
--- a/lib/view/page/setting/entry.dart
+++ b/lib/view/page/setting/entry.dart
@@ -43,7 +43,7 @@ class _SettingPageState extends State<SettingPage> {
                 ),
               ),
               actions: Btn.ok(
-                onTap: (c) {
+                onTap: () {
                   context.pop();
                   _setting.box.deleteAll(_setting.box.keys);
                   context.showSnackBar(l10n.success);
@@ -266,7 +266,7 @@ class _SettingPageState extends State<SettingPage> {
               children: children,
             );
           }),
-          actions: Btn.ok(onTap: (c) => _onSaveColor(ctrl.text)).toList,
+          actions: Btn.ok(onTap: () => _onSaveColor(ctrl.text)).toList,
         );
       },
     );
@@ -765,7 +765,7 @@ class _SettingPageState extends State<SettingPage> {
           onSubmitted: _onSaveTextScaler,
           suggestion: false,
         ),
-        actions: Btn.ok(onTap: (c) => _onSaveTextScaler(ctrl.text)).toList,
+        actions: Btn.ok(onTap: () => _onSaveTextScaler(ctrl.text)).toList,
       ),
     );
   }
@@ -870,7 +870,7 @@ class _SettingPageState extends State<SettingPage> {
         suggestion: false,
         onSubmitted: (_) => onSave(),
       ),
-      actions: Btn.ok(onTap: (c) => onSave()).toList,
+      actions: Btn.ok(onTap: onSave).toList,
     );
   }
 
@@ -1111,7 +1111,7 @@ class _SettingPageState extends State<SettingPage> {
         context.showRoundDialog(
           title: libL10n.fail,
           child: Text('${l10n.invalid} URL'),
-          actions: Btn.ok(onTap: (c) => context.pop()).toList,
+          actions: Btnx.oks,
         );
         return;
       }
@@ -1147,7 +1147,7 @@ class _SettingPageState extends State<SettingPage> {
               ),
             ],
           ),
-          actions: Btn.ok(onTap: (c) => onSave(ctrl.text)).toList,
+          actions: Btn.ok(onTap: () => onSave(ctrl.text)).toList,
         );
       },
     );
@@ -1205,7 +1205,7 @@ class _SettingPageState extends State<SettingPage> {
                 suggestion: false,
                 onSubmitted: (_) => onSave(),
               ),
-              actions: [Btn.ok(onTap: (_) => onSave())],
+              actions: Btn.ok(onTap: onSave).toList,
             );
           },
         );
diff --git a/lib/view/page/snippet/edit.dart b/lib/view/page/snippet/edit.dart
index 4676af637..c4c4c6280 100644
--- a/lib/view/page/snippet/edit.dart
+++ b/lib/view/page/snippet/edit.dart
@@ -54,7 +54,7 @@ class _SnippetEditPageState extends State<SnippetEditPage>
               '${libL10n.delete} ${l10n.snippet}(${widget.snippet!.name})',
             )),
             actions: Btn.ok(
-              onTap: (c) {
+              onTap: () {
                 Pros.snippet.del(widget.snippet!);
                 context.pop();
                 context.pop();
diff --git a/lib/view/page/ssh/tab.dart b/lib/view/page/ssh/tab.dart
index 179a0d4db..4054a2ccb 100644
--- a/lib/view/page/ssh/tab.dart
+++ b/lib/view/page/ssh/tab.dart
@@ -73,10 +73,7 @@ class _SSHTabPageState extends State<SSHTabPage>
         return AlertDialog(
           title: Text(libL10n.attention),
           content: Text('${libL10n.close} SSH ${l10n.conn}($name) ?'),
-          actions: Btn.ok(
-            onTap: (c) => context.pop(true),
-            red: true,
-          ).toList,
+          actions: Btnx.okReds,
         );
       },
     );
@@ -274,7 +271,7 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
                         color: color,
                         size: 17,
                       ),
-                      onTap: (_) => onClose(name),
+                      onTap: () => onClose(name),
                     ),
                   ),
                 const Spacer(),
diff --git a/lib/view/page/storage/local.dart b/lib/view/page/storage/local.dart
index 441e1e734..6872f6717 100644
--- a/lib/view/page/storage/local.dart
+++ b/lib/view/page/storage/local.dart
@@ -226,7 +226,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
         title: libL10n.file,
         child: Text(fileName),
         actions: [
-          Btn.ok(onTap: (c) {
+          Btn.ok(onTap: () {
             context.pop();
             context.pop(file.path);
           }),
@@ -350,7 +350,7 @@ class _LocalStoragePageState extends State<LocalStoragePage> {
       title: libL10n.delete,
       child: Text(libL10n.askContinue('${libL10n.delete} $fileName')),
       actions: Btn.ok(
-        onTap: (c) async {
+        onTap: () async {
           context.pop();
           try {
             await file.delete(recursive: true);
diff --git a/lib/view/page/storage/sftp.dart b/lib/view/page/storage/sftp.dart
index 6762115de..a03bcffe9 100644
--- a/lib/view/page/storage/sftp.dart
+++ b/lib/view/page/storage/sftp.dart
@@ -396,7 +396,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
           var newPerm = perm.copyWith();
           final ok = await context.showRoundDialog(
             child: UnixPermEditor(perm: perm, onChanged: (p) => newPerm = p),
-            actions: [Btn.ok(onTap: (context) => context.pop(true))],
+            actions: Btnx.okReds,
           );
 
           final permStr = newPerm.perm;
@@ -594,7 +594,8 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
     final textController = TextEditingController();
 
     void onSubmitted() async {
-      if (textController.text.isEmpty) {
+      final text = textController.text.trim();
+      if (text.isEmpty) {
         context.showRoundDialog(
           child: Text(libL10n.empty),
           actions: Btnx.oks,
@@ -605,7 +606,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
 
       final (suc, err) = await context.showLoadingDialog(
         fn: () async {
-          final dir = '${_status.path!.path}/${textController.text}';
+          final dir = '${_status.path!.path}/$text';
           await _status.client!.mkdir(dir);
           return true;
         },
@@ -626,7 +627,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
         onSubmitted: (_) => onSubmitted(),
       ),
       actions: Btn.ok(
-        onTap: (c) => onSubmitted(),
+        onTap: onSubmitted,
         red: true,
       ).toList,
     );
@@ -637,13 +638,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
     final textController = TextEditingController();
 
     void onSubmitted() async {
-      if (textController.text.isEmpty) {
+      final text = textController.text.trim();
+      if (text.isEmpty) {
         context.showRoundDialog(
           title: libL10n.attention,
           child: Text(libL10n.empty),
-          actions: Btn.ok(
-            onTap: (c) => context.pop(),
-          ).toList,
+          actions: Btnx.oks,
         );
         return;
       }
@@ -651,7 +651,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
 
       final (suc, err) = await context.showLoadingDialog(
         fn: () async {
-          final path = '${_status.path!.path}/${textController.text}';
+          final path = '${_status.path!.path}/$text';
           await _client!.run('touch "$path"');
           return true;
         },
@@ -671,10 +671,7 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
         suggestion: true,
         onSubmitted: (_) => onSubmitted(),
       ),
-      actions: Btn.ok(
-        onTap: (c) => onSubmitted(),
-        red: true,
-      ).toList,
+      actions: Btn.ok(onTap: onSubmitted, red: true).toList,
     );
   }
 
@@ -683,13 +680,12 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
     final textController = TextEditingController(text: file.filename);
 
     void onSubmitted() async {
-      if (textController.text.isEmpty) {
+      final text = textController.text.trim();
+      if (text.isEmpty) {
         context.showRoundDialog(
           title: libL10n.attention,
           child: Text(libL10n.empty),
-          actions: Btn.ok(
-            onTap: (c) => context.pop(),
-          ).toList,
+          actions: Btnx.oks,
         );
         return;
       }
@@ -743,17 +739,11 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
     final confirm = await context.showRoundDialog(
       title: libL10n.attention,
       child: SimpleMarkdown(data: '```sh\n$cmd\n```'),
-      actions: [
-        Btn.cancel(onTap: (c) => c.pop(false)),
-        Btn.ok(onTap: (c) => c.pop(true), red: true),
-      ],
+      actions: Btnx.cancelRedOk,
     );
     if (confirm != true) return;
 
-    final (suc, err) = await context.showLoadingDialog(
-      fn: () => _client?.run(cmd) ?? Future.value(false),
-    );
-    if (suc == null || err != null) return;
+    await AppRoutes.ssh(spi: widget.spi, initCmd: cmd).go(context);
     _listDir();
   }
 
diff --git a/lib/view/page/storage/sftp_mission.dart b/lib/view/page/storage/sftp_mission.dart
index b91cbfb6f..360ed25d1 100644
--- a/lib/view/page/storage/sftp_mission.dart
+++ b/lib/view/page/storage/sftp_mission.dart
@@ -164,7 +164,7 @@ class _SftpMissionPageState extends State<SftpMissionPage> {
           '${libL10n.delete} ${l10n.mission}($name)',
         )),
         actions: Btn.ok(
-          onTap: (c) {
+          onTap: () {
             Pros.sftp.cancel(id);
             context.pop();
           },
diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj
index ccbe8e668..e3b12b8f0 100644
--- a/macos/Runner.xcodeproj/project.pbxproj
+++ b/macos/Runner.xcodeproj/project.pbxproj
@@ -471,7 +471,7 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				INFOPLIST_FILE = Runner/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
@@ -481,7 +481,7 @@
 					"@executable_path/../Frameworks",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.15;
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "Server Box";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -608,7 +608,7 @@
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = BA88US33G6;
 				INFOPLIST_FILE = Runner/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = "Server Box";
@@ -618,7 +618,7 @@
 					"@executable_path/../Frameworks",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.15;
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "Server Box";
 				PROVISIONING_PROFILE_SPECIFIER = "";
@@ -638,7 +638,7 @@
 				"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
 				CODE_SIGN_STYLE = Manual;
 				COMBINE_HIDPI_IMAGES = YES;
-				CURRENT_PROJECT_VERSION = 1047;
+				CURRENT_PROJECT_VERSION = 1048;
 				DEVELOPMENT_TEAM = "";
 				"DEVELOPMENT_TEAM[sdk=macosx*]" = BA88US33G6;
 				INFOPLIST_FILE = Runner/Info.plist;
@@ -649,7 +649,7 @@
 					"@executable_path/../Frameworks",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.15;
-				MARKETING_VERSION = 1.0.1047;
+				MARKETING_VERSION = 1.0.1048;
 				PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
 				PRODUCT_NAME = "Server Box";
 				PROVISIONING_PROFILE_SPECIFIER = "";
diff --git a/pubspec.lock b/pubspec.lock
index 3cc8c3b0a..0af98d0fe 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -385,8 +385,8 @@ packages:
     dependency: "direct main"
     description:
       path: "."
-      ref: "v1.0.111"
-      resolved-ref: c220f27ce606e0a342cf9add6a90ce4c11844972
+      ref: "v1.0.114"
+      resolved-ref: "01f4588bf8b9da701c1b808aa542dd4a05533244"
       url: "https://github.com/lppcg/fl_lib"
     source: git
     version: "0.0.1"
diff --git a/pubspec.yaml b/pubspec.yaml
index 6392ad1e6..eaab3212b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
 name: server_box
 description: server status & toolbox app.
 publish_to: 'none'
-version: 1.0.1047+1047
+version: 1.0.1048+1048
 
 environment:
   sdk: ">=3.0.0"
@@ -61,7 +61,7 @@ dependencies:
   fl_lib:
     git:
       url: https://github.com/lppcg/fl_lib
-      ref: v1.0.111
+      ref: v1.0.114
 
 dependency_overrides:
   # dartssh2: