diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index dafb7253..4ff34f58 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -356,7 +356,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 208; + CURRENT_PROJECT_VERSION = 209; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -364,7 +364,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.208; + MARKETING_VERSION = 1.0.209; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -486,7 +486,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 208; + CURRENT_PROJECT_VERSION = 209; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -494,7 +494,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.208; + MARKETING_VERSION = 1.0.209; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -510,7 +510,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = 208; + CURRENT_PROJECT_VERSION = 209; DEVELOPMENT_TEAM = BA88US33G6; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; @@ -518,7 +518,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.208; + MARKETING_VERSION = 1.0.209; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/lib/data/res/build_data.dart b/lib/data/res/build_data.dart index 04cdaccd..34b593d9 100644 --- a/lib/data/res/build_data.dart +++ b/lib/data/res/build_data.dart @@ -2,9 +2,9 @@ class BuildData { static const String name = "ServerBox"; - static const int build = 208; + static const int build = 209; static const String engine = - "Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (8 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n"; - static const String buildAt = "2023-02-01 18:33:57.761096"; - static const int modifications = 4; + "Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git\nFramework • revision b06b8b2710 (9 days ago) • 2023-01-23 16:55:55 -0800\nEngine • revision b24591ed32\nTools • Dart 2.19.0 • DevTools 2.20.1\n"; + static const String buildAt = "2023-02-01 23:33:10.191128"; + static const int modifications = 2; } diff --git a/lib/data/res/virtual_key.dart b/lib/data/res/virtual_key.dart index 8b15f93f..fe326444 100644 --- a/lib/data/res/virtual_key.dart +++ b/lib/data/res/virtual_key.dart @@ -3,27 +3,25 @@ import 'package:xterm/core.dart'; import '../model/ssh/virtual_key.dart'; -final virtualKeys = [ +var virtualKeys = [ VirtualKey('Esc', key: TerminalKey.escape), VirtualKey('Alt', key: TerminalKey.alt, toggleable: true), VirtualKey('Home', key: TerminalKey.home), VirtualKey('Up', key: TerminalKey.arrowUp, icon: Icons.arrow_upward), VirtualKey('End', key: TerminalKey.end), - VirtualKey( - 'Copy', - func: VirtualKeyFunc.copy, - icon: Icons.copy, - ), - VirtualKey('Backspace', func: VirtualKeyFunc.backspace, icon: Icons.backspace,), + // VirtualKey( + // 'Del', + // key: TerminalKey.delete, + // ), + VirtualKey('Paste', func: VirtualKeyFunc.paste, icon: Icons.paste), VirtualKey('Tab', key: TerminalKey.tab), VirtualKey('Ctrl', key: TerminalKey.control, toggleable: true), VirtualKey('Left', key: TerminalKey.arrowLeft, icon: Icons.arrow_back), VirtualKey('Down', key: TerminalKey.arrowDown, icon: Icons.arrow_downward), VirtualKey('Right', key: TerminalKey.arrowRight, icon: Icons.arrow_forward), VirtualKey( - 'Paste', - func: VirtualKeyFunc.paste, - icon: Icons.paste, + 'IME', + func: VirtualKeyFunc.toggleIME, + icon: Icons.keyboard_hide, ), - VirtualKey('IME', func: VirtualKeyFunc.toggleIME, icon: Icons.keyboard_hide,), ]; diff --git a/lib/view/page/ssh.dart b/lib/view/page/ssh.dart index 63e1d5e0..a03c8dd5 100644 --- a/lib/view/page/ssh.dart +++ b/lib/view/page/ssh.dart @@ -33,6 +33,8 @@ class _SSHPageState extends State { late MediaQueryData _media; final _virtualKeyboardHeight = 57.0; final TerminalController _terminalController = TerminalController(); + final ContextMenuController _menuController = ContextMenuController(); + late TextStyle _menuTextStyle; var isDark = false; @@ -47,6 +49,7 @@ class _SSHPageState extends State { super.didChangeDependencies(); isDark = isDarkMode(context); _media = MediaQuery.of(context); + _menuTextStyle = TextStyle(color: contentColor.resolve(context)); } @override @@ -96,30 +99,39 @@ class _SSHPageState extends State { final termTheme = isDark ? termDarkTheme : termLightTheme; return Scaffold( backgroundColor: termTheme.background, - body: SizedBox( - height: _media.size.height - - _virtualKeyboardHeight - - _media.padding.bottom - - _media.padding.top, - child: TerminalView( - _terminal, - controller: _terminalController, - keyboardType: TextInputType.visiblePassword, - theme: termTheme, - deleteDetection: Platform.isIOS, - autofocus: true, - keyboardAppearance: isDark ? Brightness.dark : Brightness.light, - ), + body: _buildBody(termTheme), + bottomNavigationBar: _buildBottom(), + ); + } + + Widget _buildBody(TerminalTheme termTheme) { + return SizedBox( + height: _media.size.height - + _virtualKeyboardHeight - + _media.padding.bottom - + _media.padding.top, + child: TerminalView( + _terminal, + controller: _terminalController, + keyboardType: TextInputType.visiblePassword, + theme: termTheme, + deleteDetection: Platform.isIOS, + onTapUp: _onTapUp, + autofocus: true, + keyboardAppearance: isDark ? Brightness.dark : Brightness.light, ), - bottomNavigationBar: AnimatedPadding( - padding: _media.viewInsets, - duration: const Duration(milliseconds: 23), - curve: Curves.fastOutSlowIn, - child: SizedBox( - height: _virtualKeyboardHeight, - child: Consumer( - builder: (_, __, ___) => _buildVirtualKey(), - ), + ); + } + + Widget _buildBottom() { + return AnimatedPadding( + padding: _media.viewInsets, + duration: const Duration(milliseconds: 23), + curve: Curves.fastOutSlowIn, + child: SizedBox( + height: _virtualKeyboardHeight, + child: Consumer( + builder: (_, __, ___) => _buildVirtualKey(), ), ), ); @@ -216,17 +228,87 @@ class _SSHPageState extends State { _terminal.keyInput(TerminalKey.backspace); break; case VirtualKeyFunc.paste: - Clipboard.getData(Clipboard.kTextPlain).then((value) { - if (value != null) { - _terminal.textInput(value.text!); - } - }); + _paste(); break; case VirtualKeyFunc.copy: - final range = _terminalController.selection; - final text = _terminal.buffer.getText(range); - Clipboard.setData(ClipboardData(text: text)); + _copy(terminalSelected); break; } } + + void _paste() { + Clipboard.getData(Clipboard.kTextPlain).then((value) { + if (value != null) { + _terminal.textInput(value.text!); + } + }); + } + + String get terminalSelected { + final range = _terminalController.selection; + if (range == null) { + return ''; + } + return _terminal.buffer.getText(range); + } + + void _copy(String text) { + Clipboard.setData(ClipboardData(text: text)); + } + + void _onTapUp(TapUpDetails details, CellOffset offset) { + { + if (_menuController.isShown) { + _menuController.remove(); + return; + } + final selected = terminalSelected; + if (selected.trim().isEmpty) { + // _menuController.show( + // context: context, + // contextMenuBuilder: (context) { + // return TextSelectionToolbar( + // anchorAbove: detail.globalPosition, + // anchorBelow: detail.globalPosition, + // children: [ + // TextButton( + // child: Text( + // 'Paste', + // style: _menuTextStyle, + // ), + // onPressed: () async { + // _paste(); + // _menuController.remove(); + // }, + // ) + // ], + // ); + // }, + // ); + return; + } + _menuController.show( + context: context, + contextMenuBuilder: (context) { + return TextSelectionToolbar( + anchorAbove: details.globalPosition, + anchorBelow: details.globalPosition, + children: [ + TextButton( + child: Text( + 'Copy', + style: _menuTextStyle, + ), + onPressed: () { + _terminalController.setSelection(null); + _copy(selected); + _menuController.remove(); + }, + ), + ], + ); + }, + ); + } + } } diff --git a/pubspec.lock b/pubspec.lock index b14b2d45..87c42de8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -998,10 +998,9 @@ packages: xterm: dependency: "direct main" description: - name: xterm - sha256: f65619cb24d03507812e346ddb8386cad9e16a01a481a8f5c8a2eba55b4edada - url: "https://pub.dev" - source: hosted + path: "../xterm.dart" + relative: true + source: path version: "3.4.1" yaml: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index 7e3f9b3a..d84ceeac 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,7 +53,9 @@ dependencies: share_plus: ^6.3.0 intl: ^0.17.0 share_plus_web: ^3.1.0 - xterm: ^3.4.1 + # xterm: ^3.4.1 + xterm: + path: ../xterm.dart dev_dependencies: flutter_native_splash: ^2.1.6