main.dart 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:example/src/platform_menu.dart';
  4. import 'package:flutter/foundation.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:flutter_acrylic/flutter_acrylic.dart';
  8. import 'package:flutter_pty/flutter_pty.dart';
  9. import 'package:xterm/xterm.dart';
  10. void main() {
  11. WidgetsFlutterBinding.ensureInitialized();
  12. if (isDesktop) {
  13. setupAcrylic();
  14. }
  15. runApp(MyApp());
  16. }
  17. bool get isDesktop {
  18. if (kIsWeb) return false;
  19. return [
  20. TargetPlatform.windows,
  21. TargetPlatform.linux,
  22. TargetPlatform.macOS,
  23. ].contains(defaultTargetPlatform);
  24. }
  25. Future<void> setupAcrylic() async {
  26. await Window.initialize();
  27. await Window.makeTitlebarTransparent();
  28. await Window.setEffect(effect: WindowEffect.aero, color: Color(0xFFFFFFFF));
  29. await Window.setBlurViewState(MacOSBlurViewState.active);
  30. }
  31. class MyApp extends StatelessWidget {
  32. @override
  33. Widget build(BuildContext context) {
  34. return MaterialApp(
  35. title: 'xterm.dart demo',
  36. debugShowCheckedModeBanner: false,
  37. home: AppPlatformMenu(child: Home()),
  38. // shortcuts: ,
  39. );
  40. }
  41. }
  42. class Home extends StatefulWidget {
  43. Home({Key? key}) : super(key: key);
  44. @override
  45. // ignore: library_private_types_in_public_api
  46. _HomeState createState() => _HomeState();
  47. }
  48. class _HomeState extends State<Home> {
  49. final terminal = Terminal(
  50. maxLines: 10000,
  51. );
  52. final terminalController = TerminalController();
  53. late final Pty pty;
  54. @override
  55. void initState() {
  56. super.initState();
  57. WidgetsBinding.instance.endOfFrame.then(
  58. (_) {
  59. if (mounted) _startPty();
  60. },
  61. );
  62. }
  63. void _startPty() {
  64. pty = Pty.start(
  65. shell,
  66. columns: terminal.viewWidth,
  67. rows: terminal.viewHeight,
  68. );
  69. pty.output
  70. .cast<List<int>>()
  71. .transform(Utf8Decoder())
  72. .listen(terminal.write);
  73. pty.exitCode.then((code) {
  74. terminal.write('the process exited with exit code $code');
  75. });
  76. terminal.onOutput = (data) {
  77. pty.write(const Utf8Encoder().convert(data));
  78. };
  79. terminal.onResize = (w, h, pw, ph) {
  80. pty.resize(h, w);
  81. };
  82. }
  83. @override
  84. Widget build(BuildContext context) {
  85. return Scaffold(
  86. backgroundColor: Colors.transparent,
  87. body: SafeArea(
  88. child: TerminalView(
  89. terminal,
  90. controller: terminalController,
  91. autofocus: true,
  92. backgroundOpacity: 0.7,
  93. onSecondaryTapDown: (details, offset) async {
  94. final selection = terminalController.selection;
  95. if (selection != null) {
  96. final text = terminal.buffer.getText(selection);
  97. terminalController.clearSelection();
  98. await Clipboard.setData(ClipboardData(text: text));
  99. } else {
  100. final data = await Clipboard.getData('text/plain');
  101. final text = data?.text;
  102. if (text != null) {
  103. terminal.paste(text);
  104. }
  105. }
  106. },
  107. ),
  108. ),
  109. );
  110. }
  111. }
  112. String get shell {
  113. if (Platform.isMacOS || Platform.isLinux) {
  114. return Platform.environment['SHELL'] ?? 'bash';
  115. }
  116. if (Platform.isWindows) {
  117. return 'cmd.exe';
  118. }
  119. return 'sh';
  120. }