diff --git a/external/keyring-manager b/external/keyring-manager index b127b2d3..c153eb30 160000 --- a/external/keyring-manager +++ b/external/keyring-manager @@ -1 +1 @@ -Subproject commit b127b2d3c653fea163a776dd58b3798f28aeeee3 +Subproject commit c153eb3015d6d118e5d467865510d053ddd84533 diff --git a/veilid-core/src/network_manager/native/mod.rs b/veilid-core/src/network_manager/native/mod.rs index 0ea3563b..de848990 100644 --- a/veilid-core/src/network_manager/native/mod.rs +++ b/veilid-core/src/network_manager/native/mod.rs @@ -832,10 +832,12 @@ impl Network { let mut editor = routing_table.edit_routing_domain(RoutingDomain::PublicInternet); editor.clear_dial_info_details(); + editor.set_network_class(None); editor.commit().await; let mut editor = routing_table.edit_routing_domain(RoutingDomain::LocalNetwork); editor.clear_dial_info_details(); + editor.set_network_class(None); editor.commit().await; // Reset state including network class diff --git a/veilid-core/src/network_manager/wasm/mod.rs b/veilid-core/src/network_manager/wasm/mod.rs index b71aee14..8bdc2ec6 100644 --- a/veilid-core/src/network_manager/wasm/mod.rs +++ b/veilid-core/src/network_manager/wasm/mod.rs @@ -290,6 +290,7 @@ impl Network { protocol_config.inbound, protocol_config.family_global, ); + editor_public_internet.set_network_class(Some(NetworkClass::WebApp)); // commit routing table edits editor_public_internet.commit().await; @@ -319,6 +320,7 @@ impl Network { // Drop all dial info let mut editor = routing_table.edit_routing_domain(RoutingDomain::PublicInternet); editor.clear_dial_info_details(); + editor.set_network_class(None); editor.commit().await; // Cancels all async background tasks by dropping join handles @@ -348,15 +350,6 @@ impl Network { false } - pub fn get_network_class(&self, _routing_domain: RoutingDomain) -> Option { - // xxx eventually detect tor browser? - return if self.inner.lock().network_started { - Some(NetworkClass::WebApp) - } else { - None - }; - } - pub fn get_protocol_config(&self) -> ProtocolConfig { self.inner.lock().protocol_config.clone() } diff --git a/veilid-flutter/example/fonts/CascadiaMonoPL.ttf b/veilid-flutter/example/fonts/CascadiaMonoPL.ttf new file mode 100644 index 00000000..801448e7 Binary files /dev/null and b/veilid-flutter/example/fonts/CascadiaMonoPL.ttf differ diff --git a/veilid-flutter/example/ios/Flutter/AppFrameworkInfo.plist b/veilid-flutter/example/ios/Flutter/AppFrameworkInfo.plist index 8d4492f9..9625e105 100644 --- a/veilid-flutter/example/ios/Flutter/AppFrameworkInfo.plist +++ b/veilid-flutter/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 9.0 + 11.0 diff --git a/veilid-flutter/example/ios/Podfile b/veilid-flutter/example/ios/Podfile index 1e8c3c90..88359b22 100644 --- a/veilid-flutter/example/ios/Podfile +++ b/veilid-flutter/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +# platform :ios, '11.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/veilid-flutter/example/ios/Podfile.lock b/veilid-flutter/example/ios/Podfile.lock index b736a024..e4487a88 100644 --- a/veilid-flutter/example/ios/Podfile.lock +++ b/veilid-flutter/example/ios/Podfile.lock @@ -21,8 +21,8 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 - veilid: 41ea3fb86dbe06d0ff436d5002234dac45ccf1ea + veilid: f5c2e662f91907b30cf95762619526ac3e4512fd -PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d +PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 COCOAPODS: 1.11.3 diff --git a/veilid-flutter/example/ios/Runner.xcodeproj/project.pbxproj b/veilid-flutter/example/ios/Runner.xcodeproj/project.pbxproj index 94d69de5..5a156bd7 100644 --- a/veilid-flutter/example/ios/Runner.xcodeproj/project.pbxproj +++ b/veilid-flutter/example/ios/Runner.xcodeproj/project.pbxproj @@ -342,7 +342,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -420,7 +420,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -470,7 +470,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/veilid-flutter/example/lib/home.dart b/veilid-flutter/example/lib/home.dart new file mode 100644 index 00000000..e2cfc248 --- /dev/null +++ b/veilid-flutter/example/lib/home.dart @@ -0,0 +1,102 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_pty/flutter_pty.dart'; +import 'package:xterm/xterm.dart'; + +class Home extends StatefulWidget { + Home({Key? key}) : super(key: key); + + @override + // ignore: library_private_types_in_public_api + _HomeState createState() => _HomeState(); +} + +class _HomeState extends State { + final terminal = Terminal( + maxLines: 10000, + ); + + final terminalController = TerminalController(); + + late final Pty pty; + + @override + void initState() { + super.initState(); + + WidgetsBinding.instance.endOfFrame.then( + (_) { + if (mounted) _startPty(); + }, + ); + } + + void _startPty() { + pty = Pty.start( + shell, + columns: terminal.viewWidth, + rows: terminal.viewHeight, + ); + + pty.output + .cast>() + .transform(Utf8Decoder()) + .listen(terminal.write); + + pty.exitCode.then((code) { + terminal.write('the process exited with exit code $code'); + }); + + terminal.onOutput = (data) { + pty.write(const Utf8Encoder().convert(data)); + }; + + terminal.onResize = (w, h, pw, ph) { + pty.resize(h, w); + }; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.transparent, + body: SafeArea( + child: TerminalView( + terminal, + controller: terminalController, + autofocus: true, + backgroundOpacity: 0.7, + onSecondaryTapDown: (details, offset) async { + final selection = terminalController.selection; + if (selection != null) { + final text = terminal.buffer.getText(selection); + terminalController.clearSelection(); + await Clipboard.setData(ClipboardData(text: text)); + } else { + final data = await Clipboard.getData('text/plain'); + final text = data?.text; + if (text != null) { + terminal.paste(text); + } + } + }, + ), + ), + ); + } +} + +String get shell { + if (Platform.isMacOS || Platform.isLinux) { + return Platform.environment['SHELL'] ?? 'bash'; + } + + if (Platform.isWindows) { + return 'cmd.exe'; + } + + return 'sh'; +} diff --git a/veilid-flutter/example/lib/main.dart b/veilid-flutter/example/lib/main.dart index 568b67e5..2ea8cb67 100644 --- a/veilid-flutter/example/lib/main.dart +++ b/veilid-flutter/example/lib/main.dart @@ -1,12 +1,20 @@ import 'dart:async'; import 'dart:typed_data'; import 'dart:convert'; +import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/foundation.dart'; import 'package:veilid/veilid.dart'; -import 'package:flutter_loggy/flutter_loggy.dart'; +//import 'package:flutter_loggy/flutter_loggy.dart'; import 'package:loggy/loggy.dart'; +import 'platform_menu.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_acrylic/flutter_acrylic.dart'; +import 'package:xterm/xterm.dart'; +import 'home.dart'; import 'config.dart'; @@ -62,15 +70,33 @@ void setRootLogLevel(LogLevel? level) { } void initLoggy() { - Loggy.initLoggy( - logPrinter: StreamPrinter(ConsolePrinter( - const PrettyDeveloperPrinter(), - )), - logOptions: getLogOptions(null), - ); + // Loggy.initLoggy( + // logPrinter: StreamPrinter(ConsolePrinter( + // const PrettyDeveloperPrinter(), + // )), + // logOptions: getLogOptions(null), + // ); } -// Entrypoint +/////////////////////////////// Acrylic + +bool get isDesktop { + if (kIsWeb) return false; + return [ + TargetPlatform.windows, + TargetPlatform.linux, + TargetPlatform.macOS, + ].contains(defaultTargetPlatform); +} + +Future setupAcrylic() async { + await Window.initialize(); + await Window.makeTitlebarTransparent(); + await Window.setEffect(effect: WindowEffect.aero, color: Color(0xFFFFFFFF)); + await Window.setBlurViewState(MacOSBlurViewState.active); +} + +/////////////////////////////// Entrypoint void main() { WidgetsFlutterBinding.ensureInitialized(); @@ -106,7 +132,7 @@ void main() { runApp(MaterialApp( title: 'Veilid Plugin Demo', theme: ThemeData( - primarySwatch: Colors.blue, + primarySwatch: '#6667AB', visualDensity: VisualDensity.adaptivePlatformDensity, ), home: const MyApp())); @@ -220,7 +246,28 @@ class _MyAppState extends State with UiLoggy { child: Container( color: ThemeData.dark().scaffoldBackgroundColor, height: MediaQuery.of(context).size.height * 0.4, - child: LoggyStreamWidget(logLevel: loggy.level.logLevel), + child: SafeArea( + child: TerminalView( + terminal, + controller: terminalController, + autofocus: true, + backgroundOpacity: 0.7, + onSecondaryTapDown: (details, offset) async { + final selection = terminalController.selection; + if (selection != null) { + final text = terminal.buffer.getText(selection); + terminalController.clearSelection(); + await Clipboard.setData(ClipboardData(text: text)); + } else { + final data = await Clipboard.getData('text/plain'); + final text = data?.text; + if (text != null) { + terminal.paste(text); + } + } + }, + ), + ), )), Container( padding: const EdgeInsets.fromLTRB(8, 8, 8, 12), diff --git a/veilid-flutter/example/lib/platform_menu.dart b/veilid-flutter/example/lib/platform_menu.dart new file mode 100644 index 00000000..db55916a --- /dev/null +++ b/veilid-flutter/example/lib/platform_menu.dart @@ -0,0 +1,149 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +class AppPlatformMenu extends StatefulWidget { + const AppPlatformMenu({super.key, required this.child}); + + final Widget child; + + @override + State createState() => _AppPlatformMenuState(); +} + +class _AppPlatformMenuState extends State { + @override + Widget build(BuildContext context) { + if (defaultTargetPlatform != TargetPlatform.macOS) { + return widget.child; + } + + return PlatformMenuBar( + menus: [ + PlatformMenu( + label: 'TerminalStudio', + menus: [ + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.about, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.about, + ), + PlatformMenuItemGroup( + members: [ + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.servicesSubmenu, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.servicesSubmenu, + ), + ], + ), + PlatformMenuItemGroup( + members: [ + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.hide, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.hide, + ), + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.hideOtherApplications, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.hideOtherApplications, + ), + ], + ), + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.quit, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.quit, + ), + ], + ), + PlatformMenu( + label: 'Edit', + menus: [ + PlatformMenuItemGroup( + members: [ + PlatformMenuItem( + label: 'Copy', + shortcut: const SingleActivator( + LogicalKeyboardKey.keyC, + meta: true, + ), + onSelected: () { + final primaryContext = primaryFocus?.context; + if (primaryContext == null) { + return; + } + Actions.invoke( + primaryContext, + CopySelectionTextIntent.copy, + ); + }, + ), + PlatformMenuItem( + label: 'Paste', + shortcut: const SingleActivator( + LogicalKeyboardKey.keyV, + meta: true, + ), + onSelected: () { + final primaryContext = primaryFocus?.context; + if (primaryContext == null) { + return; + } + Actions.invoke( + primaryContext, + const PasteTextIntent(SelectionChangedCause.keyboard), + ); + }, + ), + PlatformMenuItem( + label: 'Select All', + shortcut: const SingleActivator( + LogicalKeyboardKey.keyA, + meta: true, + ), + onSelected: () { + final primaryContext = primaryFocus?.context; + if (primaryContext == null) { + return; + } + print(primaryContext); + try { + final action = Actions.maybeFind( + primaryContext, + intent: const SelectAllTextIntent( + SelectionChangedCause.keyboard, + ), + ); + print('action: $action'); + } catch (e) { + print(e); + } + Actions.invoke( + primaryContext, + const SelectAllTextIntent(SelectionChangedCause.keyboard), + ); + }, + ), + ], + ), + if (PlatformProvidedMenuItem.hasMenu( + PlatformProvidedMenuItemType.quit, + )) + const PlatformProvidedMenuItem( + type: PlatformProvidedMenuItemType.quit, + ), + ], + ), + ], + child: widget.child, + ); + } +} diff --git a/veilid-flutter/example/lib/veilid_color.dart b/veilid-flutter/example/lib/veilid_color.dart new file mode 100644 index 00000000..808fef7b --- /dev/null +++ b/veilid-flutter/example/lib/veilid_color.dart @@ -0,0 +1,234 @@ +// Veilid Colors +// ------------- +// +// Base is origin color as annotated +// +// Shades from material color tool at: +// https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colors +// + +import 'package:flutter/material.dart'; + +const Map primaryColorSwatch = { + 50: Color(0xffe9e9f3), + 100: Color(0xffc7c8e2), + 200: Color(0xffa2a5ce), + 300: Color(0xff7f82ba), + 400: Color(0xff6667ab), // Base (6667ab) + 500: Color(0xff4f4d9d), + 600: Color(0xff484594), + 700: Color(0xff403b88), + 800: Color(0xff39327c), + 900: Color(0xff2b2068), +}; + +const MaterialColor materialPrimaryColor = + MaterialColor(0xff6667ab, primaryColorSwatch); + +const Map primaryComplementaryColorSwatch = { + 50: Color(0xfffafdee), + 100: Color(0xfff4f9d3), + 200: Color(0xffedf6b8), + 300: Color(0xffe7f29f), + 400: Color(0xffe2ed8d), + 500: Color(0xffdde97d), + 600: Color(0xffd0d776), + 700: Color(0xffbdc16d), + 800: Color(0xffabaa66), // Base (#abaa66) + 900: Color(0xff8b845c), +}; + +const MaterialColor materialPrimaryComplementaryColor = + MaterialColor(0xffabaa66, primaryComplementaryColorSwatch); + +const Map primaryTriadicColorASwatch = { + 50: Color(0xfff0e4f0), + 100: Color(0xffdabcdb), + 200: Color(0xffc290c3), + 300: Color(0xffaa66ab), // Base (#aa66ab) + 400: Color(0xff98489a), + 500: Color(0xff892a8c), + 600: Color(0xff7d2786), + 700: Color(0xff6d217e), + 800: Color(0xff5e1b76), + 900: Color(0xff441168), +}; + +const MaterialColor materialPrimaryTriadicColorA = + MaterialColor(0xffaa66ab, primaryTriadicColorASwatch); + +const Map primaryTriadicColorBSwatch = { + 50: Color(0xffffe3dc), + 100: Color(0xfff7c4c2), + 200: Color(0xffdba2a2), + 300: Color(0xffc08180), + 400: Color(0xffab6667), // Base (#ab6667) + 500: Color(0xff964c4f), + 600: Color(0xff894347), + 700: Color(0xff78373d), + 800: Color(0xff672b35), + 900: Color(0xff551e2a), +}; + +const MaterialColor materialPrimaryTriadicColorB = + MaterialColor(0xffab6667, primaryTriadicColorBSwatch); + +const Map secondaryColorSwatch = { + 50: Color(0xffe3e8f7), + 100: Color(0xffb8c6eb), + 200: Color(0xff87a1dd), // Base (#87a1dd) + 300: Color(0xff527dce), + 400: Color(0xff1a61c1), + 500: Color(0xff0048b5), + 600: Color(0xff0040ab), + 700: Color(0xff0037a0), + 800: Color(0xff002e94), + 900: Color(0xff001d7f), +}; + +const MaterialColor materialSecondaryColor = + MaterialColor(0xff87a1dd, secondaryColorSwatch); + +const Map secondaryComplementaryColorSwatch = { + 50: Color(0xfff6f1e2), + 100: Color(0xffeadbb6), + 200: Color(0xffddc387), // Base (#ddc387) + 300: Color(0xffd2ac55), + 400: Color(0xffcd9c2d), + 500: Color(0xffc88c05), + 600: Color(0xffc58200), + 700: Color(0xffbf7400), + 800: Color(0xffb96700), + 900: Color(0xffb15000), +}; + +const MaterialColor materialSecondaryComplementaryColor = + MaterialColor(0xffddc387, secondaryComplementaryColorSwatch); + +const Map backgroundColorSwatch = { + 50: Color(0xffe3e5eb), + 100: Color(0xffb9bdce), + 200: Color(0xff8c93ac), + 300: Color(0xff626a8c), + 400: Color(0xff454d76), + 500: Color(0xff273263), + 600: Color(0xff222c5b), + 700: Color(0xff1a2451), + 800: Color(0xff131c45), + 900: Color(0xff0b0b2f), // Base (#0b0b2f) +}; + +const MaterialColor materialBackgroundColor = + MaterialColor(0xff0b0b2f, backgroundColorSwatch); + +const Map backgroundComplementaryColorSwatch = { + 50: Color(0xfffffed2), + 100: Color(0xfffdf9cd), + 200: Color(0xfff8f5c8), + 300: Color(0xfff3efc3), + 400: Color(0xffd1cea3), + 500: Color(0xffb4b187), + 600: Color(0xff89865e), + 700: Color(0xff73714a), + 800: Color(0xff53512c), + 900: Color(0xff2f2f0b), // Base (#2f2f0b) +}; + +const MaterialColor materialBackgroundComplementaryColor = + MaterialColor(0xff2f2f0b, backgroundComplementaryColorSwatch); + +const Map desaturatedColorSwatch = { + 50: Color(0xfff7fbff), + 100: Color(0xfff2f6ff), + 200: Color(0xffedf1fd), + 300: Color(0xffe3e7f2), + 400: Color(0xffc1c5d0), // Base (#c1c5d0) + 500: Color(0xffa3a7b2), + 600: Color(0xff797d87), + 700: Color(0xff656973), + 800: Color(0xff464952), + 900: Color(0xff242830), +}; + +const MaterialColor materialDesaturatedColor = + MaterialColor(0xffc1c5d0, desaturatedColorSwatch); + +const Map desaturatedComplementaryColorSwatch = { + 50: Color(0xffecebe5), + 100: Color(0xffd0ccc1), // Base (#d0ccc1) + 200: Color(0xffb0aa9a), + 300: Color(0xff908972), + 400: Color(0xff796f54), + 500: Color(0xff615837), + 600: Color(0xff584e31), + 700: Color(0xff4a4128), + 800: Color(0xff3e341f), + 900: Color(0xff312715), +}; + +const MaterialColor materialDesaturatedComplementaryColor = + MaterialColor(0xffd0ccc1, desaturatedComplementaryColorSwatch); + +const Map auxiliaryColorSwatch = { + 50: Color(0xffe7e4da), // Base (#e7e4da) + 100: Color(0xffc2bbac), + 200: Color(0xff988e7b), + 300: Color(0xff6f634c), + 400: Color(0xff53472b), + 500: Color(0xff372c0a), + 600: Color(0xff302403), + 700: Color(0xff261a00), + 800: Color(0xff1e0c00), + 900: Color(0xff160000), +}; + +const MaterialColor materialAuxiliaryColor = + MaterialColor(0xffe7e4da, auxiliaryColorSwatch); + +const Map auxiliaryComplementaryColorSwatch = { + 50: Color(0xffdadde7), // Base (#dadde7) + 100: Color(0xffa2abc6), + 200: Color(0xff6575a2), + 300: Color(0xff224580), + 400: Color(0xff00266c), + 500: Color(0xff000357), + 600: Color(0xff000051), + 700: Color(0xff000051), + 800: Color(0xff000050), + 900: Color(0xff00004f), +}; + +const MaterialColor materialAuxiliaryComplementaryColor = + MaterialColor(0xffdadde7, auxiliaryComplementaryColorSwatch); + +const Map popColorSwatch = { + 50: Color(0xfffee5f5), + 100: Color(0xfffbbde7), + 200: Color(0xfff88fd9), + 300: Color(0xfff259c9), // Base (#f259c9) + 400: Color(0xffec15bd), + 500: Color(0xffe100b0), + 600: Color(0xffd200ac), + 700: Color(0xffbe00a7), + 800: Color(0xffad00a1), + 900: Color(0xff8e0097), +}; + +const MaterialColor materialPopColor = + MaterialColor(0xfff259c9, popColorSwatch); + +const Map popComplentaryColorSwatch = { + 50: Color(0xffe6fdea), + 100: Color(0xffc2f9cb), + 200: Color(0xff96f6a9), + 300: Color(0xff59f282), // Base (#59f282) + 400: Color(0xff00ec60), + 500: Color(0xff00e446), + 600: Color(0xff00d33b), + 700: Color(0xff00bf2d), + 800: Color(0xff00ad21), + 900: Color(0xff008b05), +}; + +const MaterialColor materialPopComplementaryColor = + MaterialColor(0xff59f282, popComplentaryColorSwatch); diff --git a/veilid-flutter/example/lib/virtual_keyboard.dart b/veilid-flutter/example/lib/virtual_keyboard.dart new file mode 100644 index 00000000..b59bb847 --- /dev/null +++ b/veilid-flutter/example/lib/virtual_keyboard.dart @@ -0,0 +1,80 @@ +import 'package:flutter/material.dart'; +import 'package:xterm/xterm.dart'; + +class VirtualKeyboardView extends StatelessWidget { + const VirtualKeyboardView(this.keyboard, {super.key}); + + final VirtualKeyboard keyboard; + + @override + Widget build(BuildContext context) { + return AnimatedBuilder( + animation: keyboard, + builder: (context, child) => ToggleButtons( + children: [Text('Ctrl'), Text('Alt'), Text('Shift')], + isSelected: [keyboard.ctrl, keyboard.alt, keyboard.shift], + onPressed: (index) { + switch (index) { + case 0: + keyboard.ctrl = !keyboard.ctrl; + break; + case 1: + keyboard.alt = !keyboard.alt; + break; + case 2: + keyboard.shift = !keyboard.shift; + break; + } + }, + ), + ); + } +} + +class VirtualKeyboard extends TerminalInputHandler with ChangeNotifier { + final TerminalInputHandler _inputHandler; + + VirtualKeyboard(this._inputHandler); + + bool _ctrl = false; + + bool get ctrl => _ctrl; + + set ctrl(bool value) { + if (_ctrl != value) { + _ctrl = value; + notifyListeners(); + } + } + + bool _shift = false; + + bool get shift => _shift; + + set shift(bool value) { + if (_shift != value) { + _shift = value; + notifyListeners(); + } + } + + bool _alt = false; + + bool get alt => _alt; + + set alt(bool value) { + if (_alt != value) { + _alt = value; + notifyListeners(); + } + } + + @override + String? call(TerminalKeyboardEvent event) { + return _inputHandler.call(event.copyWith( + ctrl: event.ctrl || _ctrl, + shift: event.shift || _shift, + alt: event.alt || _alt, + )); + } +} diff --git a/veilid-flutter/example/linux/flutter/generated_plugin_registrant.cc b/veilid-flutter/example/linux/flutter/generated_plugin_registrant.cc index cebc32de..3a10c1bf 100644 --- a/veilid-flutter/example/linux/flutter/generated_plugin_registrant.cc +++ b/veilid-flutter/example/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) flutter_acrylic_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterAcrylicPlugin"); + flutter_acrylic_plugin_register_with_registrar(flutter_acrylic_registrar); g_autoptr(FlPluginRegistrar) veilid_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "VeilidPlugin"); veilid_plugin_register_with_registrar(veilid_registrar); diff --git a/veilid-flutter/example/linux/flutter/generated_plugins.cmake b/veilid-flutter/example/linux/flutter/generated_plugins.cmake index 003d7b50..ec1406bc 100644 --- a/veilid-flutter/example/linux/flutter/generated_plugins.cmake +++ b/veilid-flutter/example/linux/flutter/generated_plugins.cmake @@ -3,10 +3,12 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_acrylic veilid ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_pty ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/veilid-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift b/veilid-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift index 5c63c74b..298c79e7 100644 --- a/veilid-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/veilid-flutter/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,10 +5,12 @@ import FlutterMacOS import Foundation +import flutter_acrylic import path_provider_macos import veilid func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FlutterAcrylicPlugin.register(with: registry.registrar(forPlugin: "FlutterAcrylicPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) VeilidPlugin.register(with: registry.registrar(forPlugin: "VeilidPlugin")) } diff --git a/veilid-flutter/example/pubspec.lock b/veilid-flutter/example/pubspec.lock index 52c42eef..f59dfc44 100644 --- a/veilid-flutter/example/pubspec.lock +++ b/veilid-flutter/example/pubspec.lock @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.16.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" cupertino_icons: dependency: "direct main" description: @@ -50,6 +57,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.5" + equatable: + dependency: transitive + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -76,6 +90,13 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_acrylic: + dependency: "direct main" + description: + name: flutter_acrylic + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0+2" flutter_lints: dependency: "direct dev" description: @@ -90,6 +111,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + flutter_pty: + dependency: "direct main" + description: + name: flutter_pty + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.1" flutter_test: dependency: "direct dev" description: flutter @@ -205,6 +233,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.0" + platform_info: + dependency: transitive + description: + name: platform_info + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.0" plugin_platform_interface: dependency: transitive description: @@ -219,6 +254,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.2.4" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" rxdart: dependency: transitive description: @@ -273,6 +315,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.12" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" vector_math: dependency: transitive description: @@ -301,6 +350,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.0+2" + xterm: + dependency: "direct main" + description: + name: xterm + url: "https://pub.dartlang.org" + source: hosted + version: "3.4.0" sdks: - dart: ">=2.17.0 <3.0.0" + dart: ">=2.18.0 <3.0.0" flutter: ">=3.0.0" diff --git a/veilid-flutter/example/pubspec.yaml b/veilid-flutter/example/pubspec.yaml index 73ee637f..e603fd76 100644 --- a/veilid-flutter/example/pubspec.yaml +++ b/veilid-flutter/example/pubspec.yaml @@ -7,7 +7,7 @@ version: 1.0.0+1 publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: - sdk: ">=2.16.1 <3.0.0" + sdk: ">=2.17.0 <3.0.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions @@ -36,6 +36,9 @@ dependencies: flutter_loggy: ^2.0.1 path_provider: ^2.0.11 path: ^1.8.1 + xterm: ^3.4.0 + flutter_pty: ^0.3.1 + flutter_acrylic: ^1.0.0+2 dev_dependencies: flutter_test: @@ -88,3 +91,7 @@ flutter: # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages + fonts: + - family: Cascadia Mono + fonts: + - asset: fonts/CascadiaMonoPL.ttf diff --git a/veilid-flutter/example/windows/flutter/generated_plugin_registrant.cc b/veilid-flutter/example/windows/flutter/generated_plugin_registrant.cc index 72dbdef2..df015a29 100644 --- a/veilid-flutter/example/windows/flutter/generated_plugin_registrant.cc +++ b/veilid-flutter/example/windows/flutter/generated_plugin_registrant.cc @@ -6,9 +6,12 @@ #include "generated_plugin_registrant.h" +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { + FlutterAcrylicPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterAcrylicPlugin")); VeilidPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("VeilidPlugin")); } diff --git a/veilid-flutter/example/windows/flutter/generated_plugins.cmake b/veilid-flutter/example/windows/flutter/generated_plugins.cmake index 658ec856..4ba079ee 100644 --- a/veilid-flutter/example/windows/flutter/generated_plugins.cmake +++ b/veilid-flutter/example/windows/flutter/generated_plugins.cmake @@ -3,10 +3,12 @@ # list(APPEND FLUTTER_PLUGIN_LIST + flutter_acrylic veilid ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + flutter_pty ) set(PLUGIN_BUNDLED_LIBRARIES)