example work
This commit is contained in:
102
veilid-flutter/example/lib/home.dart
Normal file
102
veilid-flutter/example/lib/home.dart
Normal file
@@ -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<Home> {
|
||||
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<List<int>>()
|
||||
.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';
|
||||
}
|
@@ -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<void> 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<MyApp> 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),
|
||||
|
149
veilid-flutter/example/lib/platform_menu.dart
Normal file
149
veilid-flutter/example/lib/platform_menu.dart
Normal file
@@ -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<AppPlatformMenu> createState() => _AppPlatformMenuState();
|
||||
}
|
||||
|
||||
class _AppPlatformMenuState extends State<AppPlatformMenu> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (defaultTargetPlatform != TargetPlatform.macOS) {
|
||||
return widget.child;
|
||||
}
|
||||
|
||||
return PlatformMenuBar(
|
||||
menus: <MenuItem>[
|
||||
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<Intent>(
|
||||
primaryContext,
|
||||
intent: const SelectAllTextIntent(
|
||||
SelectionChangedCause.keyboard,
|
||||
),
|
||||
);
|
||||
print('action: $action');
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
Actions.invoke<Intent>(
|
||||
primaryContext,
|
||||
const SelectAllTextIntent(SelectionChangedCause.keyboard),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
if (PlatformProvidedMenuItem.hasMenu(
|
||||
PlatformProvidedMenuItemType.quit,
|
||||
))
|
||||
const PlatformProvidedMenuItem(
|
||||
type: PlatformProvidedMenuItemType.quit,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
}
|
234
veilid-flutter/example/lib/veilid_color.dart
Normal file
234
veilid-flutter/example/lib/veilid_color.dart
Normal file
@@ -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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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<int, Color> 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);
|
80
veilid-flutter/example/lib/virtual_keyboard.dart
Normal file
80
veilid-flutter/example/lib/virtual_keyboard.dart
Normal file
@@ -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,
|
||||
));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user