Kaynağa Gözat

Update example

xuty 2 yıl önce
ebeveyn
işleme
a296a3e51e
29 değiştirilmiş dosya ile 1002 ekleme ve 182 silme
  1. 3 1
      .gitignore
  2. 16 16
      example/.metadata
  3. 3 1
      example/README.md
  4. BIN
      example/assets/specs_v1.json.gz
  5. 12 0
      example/ios/RunnerTests/RunnerTests.swift
  6. 386 0
      example/lib/completion.dart
  7. 95 0
      example/lib/overlay.dart
  8. 270 0
      example/lib/src/suggestion.dart
  9. 0 4
      example/linux/flutter/generated_plugin_registrant.cc
  10. 0 1
      example/linux/flutter/generated_plugins.cmake
  11. 0 2
      example/macos/Flutter/GeneratedPluginRegistrant.swift
  12. 1 1
      example/macos/Podfile
  13. 2 8
      example/macos/Podfile.lock
  14. 39 38
      example/macos/Runner.xcodeproj/project.pbxproj
  15. 1 1
      example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
  16. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
  17. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
  18. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
  19. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
  20. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
  21. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
  22. BIN
      example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
  23. 1 1
      example/macos/Runner/Configs/AppInfo.xcconfig
  24. 6 10
      example/macos/Runner/MainFlutterWindow.swift
  25. 12 0
      example/macos/RunnerTests/RunnerTests.swift
  26. 152 92
      example/pubspec.lock
  27. 3 2
      example/pubspec.yaml
  28. 0 3
      example/windows/flutter/generated_plugin_registrant.cc
  29. 0 1
      example/windows/flutter/generated_plugins.cmake

+ 3 - 1
.gitignore

@@ -77,4 +77,6 @@ build/
 .vscode/
 example/lib/debug.dart
 
-coverage/
+coverage/
+
+example2/

+ 16 - 16
example/.metadata

@@ -4,8 +4,8 @@
 # This file should be version controlled.
 
 version:
-  revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-  channel: stable
+  revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+  channel: master
 
 project_type: app
 
@@ -13,26 +13,26 @@ project_type: app
 migration:
   platforms:
     - platform: root
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: android
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: ios
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: linux
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: macos
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: web
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
     - platform: windows
-      create_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
-      base_revision: f1875d570e39de09040c8f79aa13cc56baab8db1
+      create_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
+      base_revision: 845c12fb1091fe02f336cb06b60b09fa6f389481
 
   # User provided section
 

+ 3 - 1
example/README.md

@@ -1 +1,3 @@
-# xterm.dart demo
+# xterm.dart demo
+
+This package contains minimalistic xterm.dart examples.

BIN
example/assets/specs_v1.json.gz


+ 12 - 0
example/ios/RunnerTests/RunnerTests.swift

@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+  func testExample() {
+    // If you add code to the Runner application, consider adding tests here.
+    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+  }
+
+}

+ 386 - 0
example/lib/completion.dart

@@ -0,0 +1,386 @@
+import 'dart:convert';
+import 'dart:io';
+import 'dart:math';
+
+import 'package:example/src/platform_menu.dart';
+import 'package:example/src/suggestion.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_pty/flutter_pty.dart';
+import 'package:xterm/xterm.dart';
+
+final engine = SuggestionEngine();
+
+Future<Map<String, dynamic>> loadSuggestion() async {
+  final data = await rootBundle.load('assets/specs_v1.json.gz');
+  return await Stream.value(data.buffer.asUint8List())
+      .cast<List<int>>()
+      .transform(gzip.decoder)
+      .transform(utf8.decoder)
+      .transform(json.decoder)
+      .first as Map<String, dynamic>;
+}
+
+void main() async {
+  WidgetsFlutterBinding.ensureInitialized();
+  engine.load(await loadSuggestion());
+  runApp(MyApp());
+}
+
+class MyApp extends StatelessWidget {
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'xterm.dart demo',
+      debugShowCheckedModeBanner: false,
+      home: AppPlatformMenu(child: Home()),
+    );
+  }
+}
+
+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> {
+  late final terminal = Terminal(
+    maxLines: 10000,
+    onPrivateOSC: _handlePrivateOSC,
+  );
+
+  final terminalController = TerminalController();
+
+  final terminalKey = GlobalKey<TerminalViewState>();
+
+  final suggestionOverlay = OverlayPortalController();
+
+  late final Pty pty;
+
+  @override
+  void initState() {
+    super.initState();
+    terminal.addListener(_handleTerminalChanged);
+
+    WidgetsBinding.instance.endOfFrame.then(
+      (_) {
+        if (mounted) _startPty();
+      },
+    );
+  }
+
+  @override
+  void dispose() {
+    super.dispose();
+    terminal.removeListener(_handleTerminalChanged);
+  }
+
+  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);
+    };
+  }
+
+  CellAnchor? _promptStart;
+  CellAnchor? _commandStart;
+  CellAnchor? _commandEnd;
+  CellAnchor? _commandFinished;
+
+  void _handlePrivateOSC(String code, List<String> args) {
+    switch (code) {
+      case '133':
+        _handleFinalTermOSC(args);
+    }
+  }
+
+  void _handleFinalTermOSC(List<String> args) {
+    switch (args) {
+      case ['A']:
+        _promptStart?.dispose();
+        _promptStart = terminal.buffer.createAnchorFromCursor();
+        _commandStart?.dispose();
+        _commandStart = null;
+        _commandEnd?.dispose();
+        _commandEnd = null;
+        _commandFinished?.dispose();
+        _commandFinished = null;
+      case ['B']:
+        _commandStart?.dispose();
+        _commandStart = terminal.buffer.createAnchorFromCursor();
+        break;
+      case ['C', ..._]:
+        _commandEnd?.dispose();
+        _commandEnd = terminal.buffer.createAnchorFromCursor();
+        // _handleCommandEnd();
+        break;
+      case ['D', String exitCode]:
+        _commandFinished?.dispose();
+        _commandFinished = terminal.buffer.createAnchorFromCursor();
+        // _handleCommandFinished(int.tryParse(exitCode));
+        break;
+    }
+  }
+
+  // void _handleCommandEnd() {
+  //   if (_commandStart == null || _commandEnd == null) return;
+  //   final command = terminal.buffer
+  //       .getText(BufferRangeLine(_commandStart!.offset, _commandEnd!.offset))
+  //       .trim();
+  //   print('command: $command');
+  // }
+
+  // void _handleCommandFinished(int? exitCode) {
+  //   if (_commandEnd == null || _commandFinished == null) return;
+  //   final result = terminal.buffer
+  //       .getText(BufferRangeLine(_commandEnd!.offset, _commandFinished!.offset))
+  //       .trim();
+  //   print('result: $result');
+  //   print('exit code $exitCode');
+  // }
+
+  final suggestions = ValueNotifier<List<FigSuggestion>>([]);
+
+  void _handleTerminalChanged() {
+    final commandStart = _commandStart;
+    if (commandStart == null || _commandEnd != null) {
+      suggestionOverlay.hide();
+      return;
+    }
+
+    var commandRange = BufferRangeLine(
+      commandStart.offset,
+      CellOffset(
+        terminal.buffer.cursorX,
+        terminal.buffer.absoluteCursorY,
+      ),
+    );
+    final command = terminal.buffer.getText(commandRange).trim();
+
+    if (command.isEmpty) {
+      suggestionOverlay.hide();
+      return;
+    }
+
+    print('command: $command');
+
+    suggestions.value = engine.getSuggestions(command).toList();
+
+    print(suggestions.value);
+
+    if (suggestions.value.isNotEmpty) {
+      suggestionOverlay.show();
+    } else {
+      suggestionOverlay.hide();
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      backgroundColor: Colors.transparent,
+      body: OverlayPortal(
+        controller: suggestionOverlay,
+        overlayChildBuilder: (context) {
+          return ValueListenableBuilder<List<FigSuggestion>>(
+            valueListenable: suggestions,
+            builder: (context, suggestions, _) {
+              return SuggestionOverlay(
+                suggestions,
+                cursorRect: terminalKey.currentState!.cursorRect,
+              );
+            },
+          );
+        },
+        child: TerminalView(
+          terminal,
+          key: terminalKey,
+          controller: terminalController,
+          autofocus: true,
+          backgroundOpacity: 0.7,
+        ),
+      ),
+    );
+  }
+}
+
+class SuggestionOverlay extends StatelessWidget {
+  const SuggestionOverlay(
+    this.suggestions, {
+    super.key,
+    required this.cursorRect,
+  });
+
+  final Rect cursorRect;
+
+  final List<FigSuggestion> suggestions;
+
+  @override
+  Widget build(BuildContext context) {
+    print('build suggestions');
+
+    const kScreenPadding = 8.0;
+    const kPanelContentDistance = 8.0;
+    const kPanelWidth = 300.0;
+    const kPanelHeight = 300.0;
+    final paddingAbove = MediaQuery.paddingOf(context).top + kScreenPadding;
+    final availableHeight =
+        cursorRect.top - kPanelContentDistance - paddingAbove;
+    final fitsAbove = kPanelHeight <= availableHeight;
+
+    return CustomSingleChildLayout(
+      delegate: _SuggestionOverlayDelegate(cursorRect, fitsAbove),
+      child: ConstrainedBox(
+        constraints: BoxConstraints(
+          maxWidth: kPanelWidth,
+          maxHeight: kPanelHeight,
+        ),
+        child: _buildSuggestions(context),
+      ),
+    );
+  }
+
+  Widget _buildSuggestions(BuildContext context) {
+    final list = ListView.builder(
+      itemCount: suggestions.length,
+      itemBuilder: (context, index) {
+        final suggestion = suggestions[index];
+        final (icon, color, content) = _suggestionContent(suggestion);
+        return SuggestionTile(icon: icon, color: color, content: content ?? '');
+      },
+    );
+
+    return Container(
+      decoration: BoxDecoration(
+        color: Colors.grey[800],
+        borderRadius: BorderRadius.circular(4),
+        // border: Border.all(color: Colors.grey[900]!),
+      ),
+      child: DefaultTextStyle(
+        style: TerminalStyle().toTextStyle().copyWith(height: 1.5),
+        child: Column(
+          children: [
+            Expanded(
+              child: list,
+            ),
+          ],
+        ),
+      ),
+    );
+  }
+
+  static (IconData, Color, String?) _suggestionContent(
+      FigSuggestion suggestion) {
+    return switch (suggestion) {
+      FigSubCommand(:final names) => (
+          Icons.subdirectory_arrow_right,
+          Colors.blue,
+          names.join(', '),
+        ),
+      FigOption(:final name) => (
+          Icons.settings,
+          Colors.green,
+          name.join(', '),
+        ),
+      FigArgument(:final name) => (
+          Icons.text_fields,
+          Colors.yellow,
+          name,
+        ),
+    };
+  }
+}
+
+class _SuggestionOverlayDelegate extends SingleChildLayoutDelegate {
+  _SuggestionOverlayDelegate(this.cursorRect, this.fitsAbove);
+
+  final Rect cursorRect;
+
+  final bool fitsAbove;
+
+  @override
+  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
+    return constraints.loosen();
+  }
+
+  @override
+  Offset getPositionForChild(Size size, Size childSize) {
+    TextSelectionToolbarLayoutDelegate;
+
+    const kPanelContentDistance = 8.0;
+    final dx = min(cursorRect.left, size.width - childSize.width);
+    final dy = fitsAbove
+        ? cursorRect.top - childSize.height
+        : cursorRect.bottom + kPanelContentDistance;
+    return Offset(dx, dy);
+  }
+
+  @override
+  bool shouldRelayout(_SuggestionOverlayDelegate oldDelegate) {
+    return cursorRect != oldDelegate.cursorRect;
+  }
+}
+
+class SuggestionTile extends StatelessWidget {
+  const SuggestionTile({
+    super.key,
+    required this.icon,
+    required this.content,
+    required this.color,
+  });
+
+  final IconData icon;
+  final Color color;
+
+  final String content;
+
+  @override
+  Widget build(BuildContext context) {
+    return Row(
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        SizedBox(width: 4),
+        Icon(
+          icon,
+          size: 14,
+          color: color,
+        ),
+        SizedBox(width: 4),
+        Text(content),
+      ],
+    );
+  }
+}
+
+String get shell {
+  if (Platform.isMacOS || Platform.isLinux) {
+    return Platform.environment['SHELL'] ?? 'bash';
+  }
+
+  if (Platform.isWindows) {
+    return 'cmd.exe';
+  }
+
+  return 'sh';
+}

+ 95 - 0
example/lib/overlay.dart

@@ -0,0 +1,95 @@
+import 'package:flutter/material.dart';
+
+void main() {
+  runApp(App());
+}
+
+class App extends StatelessWidget {
+  const App({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      home: Home(),
+    );
+  }
+}
+
+class Home extends StatelessWidget {
+  const Home({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      body: ListView(
+        children: [
+          SizedBox(
+            height: 500,
+          ),
+          OverlayDemo(),
+          SizedBox(
+            height: 2500,
+          ),
+        ],
+      ),
+    );
+  }
+}
+
+class OverlayDemo extends StatefulWidget {
+  const OverlayDemo({super.key});
+
+  @override
+  State<OverlayDemo> createState() => OverlayDemoState();
+}
+
+class OverlayDemoState extends State<OverlayDemo> {
+  final overlay = OverlayPortalController();
+  final link = LayerLink();
+
+  @override
+  Widget build(BuildContext context) {
+    return OverlayPortal(
+      controller: overlay,
+      overlayChildBuilder: (context) {
+        return CompositedTransformFollower(
+          link: link,
+          child: Stack(
+            children: [
+              Container(
+                color: Colors.yellow,
+                width: 100,
+                height: 100,
+              ),
+            ],
+          ),
+        );
+      },
+      child: MouseRegion(
+        onHover: (event) {
+          setState(() {
+            overlay.show();
+          });
+        },
+        onExit: (event) {
+          setState(() {
+            overlay.hide();
+          });
+        },
+        child: CompositedTransformTarget(
+          link: link,
+          child: GestureDetector(
+            onTap: () {
+              debugDumpLayerTree();
+            },
+            child: Container(
+              color: Colors.red,
+              width: 100,
+              height: 100,
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 270 - 0
example/lib/src/suggestion.dart

@@ -0,0 +1,270 @@
+class SuggestionEngine {
+  final _specs = <String, FigSubCommand>{};
+
+  void load(Map<String, dynamic> specs) {
+    for (var spec in specs.entries) {
+      addSpec(spec.key, FigSubCommand.fromJson(spec.value));
+    }
+  }
+
+  void addSpec(String name, FigSubCommand spec) {
+    _specs[name] = spec;
+  }
+
+  Iterable<FigSuggestion> getSuggestions(String command) {
+    final args = command.split(' ').where((e) => e.isNotEmpty).toList();
+
+    if (args.isEmpty) {
+      return [];
+    }
+
+    return _getSuggestions(args, _specs);
+  }
+
+  Iterable<FigSuggestion> _getSuggestions(
+    List<String> input,
+    Map<String, FigSubCommand> specs,
+  ) sync* {
+    assert(input.isNotEmpty);
+
+    // The subcommand scope we are currently in.
+    FigSubCommand? currentCommand;
+
+    // The last suggestion we recongnized. This is used to determine what to
+    // suggest next. Valid values are:
+    // - null: We are at the root of the command.
+    // - currentCommand
+    // - option of currentCommand
+    FigSuggestion? last;
+
+    for (final part in input) {
+      if (currentCommand == null) {
+        currentCommand = specs[part];
+        if (currentCommand == null) {
+          if (part.length >= 4) {
+            yield* specs.values.matchPrefix(input.last);
+          }
+          return;
+        }
+        last = currentCommand;
+        continue;
+      }
+
+      final option = currentCommand.options.match(part);
+      if (option != null) {
+        last = option;
+        continue;
+      }
+
+      final subCommand = currentCommand.subCommands.match(part);
+      if (subCommand != null) {
+        currentCommand = subCommand;
+        last = currentCommand;
+        continue;
+      }
+
+      last = null;
+    }
+
+    if (currentCommand == null) {
+      return;
+    }
+
+    if (last is FigSubCommand) {
+      yield* last.args;
+      yield* last.subCommands;
+      yield* last.options;
+    } else if (last is FigOption) {
+      if (last.args.isEmpty) {
+        yield* currentCommand.args;
+        yield* currentCommand.options;
+      } else {
+        yield* last.args;
+      }
+    } else {
+      yield* currentCommand.subCommands.matchPrefix(input.last);
+      yield* currentCommand.options.matchPrefix(input.last);
+      yield* currentCommand.args;
+    }
+  }
+}
+
+extension on Iterable<FigSubCommand> {
+  FigSubCommand? match(String name) {
+    for (final command in this) {
+      if (command.names.contains(name)) {
+        return command;
+      }
+    }
+    return null;
+  }
+
+  Iterable<FigSubCommand> matchPrefix(String name) sync* {
+    for (final command in this) {
+      if (command.names.any((e) => e.startsWith(name))) {
+        yield command;
+      }
+    }
+  }
+}
+
+extension on Iterable<FigOption> {
+  FigOption? match(String name) {
+    for (final option in this) {
+      if (option.name.contains(name)) {
+        return option;
+      }
+    }
+    return null;
+  }
+
+  Iterable<FigOption> matchPrefix(String name) sync* {
+    for (final option in this) {
+      if (option.name.any((e) => e.startsWith(name))) {
+        yield option;
+      }
+    }
+  }
+}
+
+sealed class FigSuggestion {
+  final String? description;
+
+  FigSuggestion({this.description});
+}
+
+class FigSubCommand extends FigSuggestion {
+  final List<String> names;
+
+  final List<FigSubCommand> subCommands;
+
+  final bool requiresSubCommand;
+
+  final List<FigOption> options;
+
+  final List<FigArgument> args;
+
+  FigSubCommand({
+    required this.names,
+    super.description,
+    required this.subCommands,
+    required this.requiresSubCommand,
+    required this.options,
+    required this.args,
+  });
+
+  factory FigSubCommand.fromJson(Map<String, dynamic> json) {
+    return FigSubCommand(
+      names: singleOrList<String>(json['name']),
+      description: json['description'],
+      subCommands: singleOrList(json['subcommands'])
+          .map<FigSubCommand>((e) => FigSubCommand.fromJson(e))
+          .toList(),
+      requiresSubCommand: json['requiresSubCommand'] ?? false,
+      options: singleOrList(json['options'])
+          .map<FigOption>((e) => FigOption.fromJson(e))
+          .toList(),
+      args: singleOrList(json['args'])
+          .map<FigArgument>((e) => FigArgument.fromJson(e))
+          .toList(),
+    );
+  }
+
+  @override
+  String toString() {
+    return 'FigSubCommand($names)';
+  }
+}
+
+class FigOption extends FigSuggestion {
+  final List<String> name;
+
+  final List<FigArgument> args;
+
+  final bool isPersistent;
+
+  final bool isRequired;
+
+  final String? separator;
+
+  final int? repeat;
+
+  final List<String> exclusiveOn;
+
+  final List<String> dependsOn;
+
+  FigOption({
+    required this.name,
+    super.description,
+    required this.args,
+    required this.isPersistent,
+    required this.isRequired,
+    this.separator,
+    this.repeat,
+    required this.exclusiveOn,
+    required this.dependsOn,
+  });
+
+  factory FigOption.fromJson(Map<String, dynamic> json) {
+    return FigOption(
+      name: singleOrList(json['name']).cast<String>(),
+      description: json['description'],
+      args: singleOrList(json['args'])
+          .map<FigArgument>((e) => FigArgument.fromJson(e))
+          .toList(),
+      isPersistent: json['isPersistent'] ?? false,
+      isRequired: json['isRequired'] ?? false,
+      separator: json['separator'],
+      repeat: json['repeat'],
+      exclusiveOn: singleOrList<String>(json['exclusiveOn']),
+      dependsOn: singleOrList<String>(json['dependsOn']),
+    );
+  }
+
+  @override
+  String toString() {
+    return 'FigOption($name)';
+  }
+}
+
+class FigArgument extends FigSuggestion {
+  final String? name;
+
+  final bool isDangerous;
+
+  final bool isOptional;
+
+  final bool isCommand;
+
+  final String? defaultValue;
+
+  FigArgument({
+    required this.name,
+    super.description,
+    required this.isDangerous,
+    required this.isOptional,
+    required this.isCommand,
+    this.defaultValue,
+  });
+
+  factory FigArgument.fromJson(Map<String, dynamic> json) {
+    return FigArgument(
+      name: json['name'],
+      description: json['description'],
+      isDangerous: json['isDangerous'] ?? false,
+      isOptional: json['isOptional'] ?? false,
+      isCommand: json['isCommand'] ?? false,
+      defaultValue: json['defaultValue'],
+    );
+  }
+
+  @override
+  String toString() {
+    return 'FigArgument($name)';
+  }
+}
+
+List<T> singleOrList<T>(item) {
+  if (item == null) return <T>[];
+  return item is List ? item.cast<T>() : <T>[item as T];
+}

+ 0 - 4
example/linux/flutter/generated_plugin_registrant.cc

@@ -6,10 +6,6 @@
 
 #include "generated_plugin_registrant.h"
 
-#include <flutter_acrylic/flutter_acrylic_plugin.h>
 
 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);
 }

+ 0 - 1
example/linux/flutter/generated_plugins.cmake

@@ -3,7 +3,6 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
-  flutter_acrylic
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST

+ 0 - 2
example/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,8 +5,6 @@
 import FlutterMacOS
 import Foundation
 
-import flutter_acrylic
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
-  FlutterAcrylicPlugin.register(with: registry.registrar(forPlugin: "FlutterAcrylicPlugin"))
 }

+ 1 - 1
example/macos/Podfile

@@ -1,4 +1,4 @@
-platform :osx, '10.11'
+platform :osx, '10.14'
 
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'

+ 2 - 8
example/macos/Podfile.lock

@@ -1,28 +1,22 @@
 PODS:
-  - flutter_acrylic (0.1.0):
-    - FlutterMacOS
   - flutter_pty (0.0.1):
     - FlutterMacOS
   - FlutterMacOS (1.0.0)
 
 DEPENDENCIES:
-  - flutter_acrylic (from `Flutter/ephemeral/.symlinks/plugins/flutter_acrylic/macos`)
   - flutter_pty (from `Flutter/ephemeral/.symlinks/plugins/flutter_pty/macos`)
   - FlutterMacOS (from `Flutter/ephemeral`)
 
 EXTERNAL SOURCES:
-  flutter_acrylic:
-    :path: Flutter/ephemeral/.symlinks/plugins/flutter_acrylic/macos
   flutter_pty:
     :path: Flutter/ephemeral/.symlinks/plugins/flutter_pty/macos
   FlutterMacOS:
     :path: Flutter/ephemeral
 
 SPEC CHECKSUMS:
-  flutter_acrylic: c3df24ae52ab6597197837ce59ef2a8542640c17
   flutter_pty: 41b6f848ade294be726a6b94cdd4a67c3bc52f59
-  FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811
+  FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
 
-PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
+PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7
 
 COCOAPODS: 1.11.3

+ 39 - 38
example/macos/Runner.xcodeproj/project.pbxproj

@@ -3,7 +3,7 @@
 	archiveVersion = 1;
 	classes = {
 	};
-	objectVersion = 51;
+	objectVersion = 54;
 	objects = {
 
 /* Begin PBXAggregateTarget section */
@@ -26,7 +26,7 @@
 		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
 		33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
 		33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
-		A6151BD419F68182C8FF85D2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 413CC3D3B2FBCF7B69907E26 /* Pods_Runner.framework */; };
+		A63EDDC4424F7733E4F1089E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BFF3568FCDF6A623BAE2DF2 /* Pods_Runner.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -53,6 +53,7 @@
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
+		327BAFDBBDAC4BC4B3F62492 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
 		335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
 		33CC10ED2044A3C60003C045 /* example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = example.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -67,12 +68,11 @@
 		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
 		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
 		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
-		413CC3D3B2FBCF7B69907E26 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-		49AA7380F80473893FD60C2E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
+		3BFF3568FCDF6A623BAE2DF2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
+		831993642494A8EE586D7606 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
-		E0725F2979814304119369B0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
-		F2CA369AF483BC5EA72B3581 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
+		98BB7BB02D086BDD59672A1C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -80,7 +80,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				A6151BD419F68182C8FF85D2 /* Pods_Runner.framework in Frameworks */,
+				A63EDDC4424F7733E4F1089E /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -105,7 +105,7 @@
 				33CEB47122A05771004F2AC0 /* Flutter */,
 				33CC10EE2044A3C60003C045 /* Products */,
 				D73912EC22F37F3D000D13A0 /* Frameworks */,
-				F3BFAC646F7524479B4C81FB /* Pods */,
+				5D0EEDE84B575FFD99D06C18 /* Pods */,
 			);
 			sourceTree = "<group>";
 		};
@@ -152,23 +152,23 @@
 			path = Runner;
 			sourceTree = "<group>";
 		};
-		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
+		5D0EEDE84B575FFD99D06C18 /* Pods */ = {
 			isa = PBXGroup;
 			children = (
-				413CC3D3B2FBCF7B69907E26 /* Pods_Runner.framework */,
+				327BAFDBBDAC4BC4B3F62492 /* Pods-Runner.debug.xcconfig */,
+				98BB7BB02D086BDD59672A1C /* Pods-Runner.release.xcconfig */,
+				831993642494A8EE586D7606 /* Pods-Runner.profile.xcconfig */,
 			);
-			name = Frameworks;
+			name = Pods;
+			path = Pods;
 			sourceTree = "<group>";
 		};
-		F3BFAC646F7524479B4C81FB /* Pods */ = {
+		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
-				49AA7380F80473893FD60C2E /* Pods-Runner.debug.xcconfig */,
-				F2CA369AF483BC5EA72B3581 /* Pods-Runner.release.xcconfig */,
-				E0725F2979814304119369B0 /* Pods-Runner.profile.xcconfig */,
+				3BFF3568FCDF6A623BAE2DF2 /* Pods_Runner.framework */,
 			);
-			name = Pods;
-			path = Pods;
+			name = Frameworks;
 			sourceTree = "<group>";
 		};
 /* End PBXGroup section */
@@ -178,13 +178,13 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
 			buildPhases = (
-				3B927F223EF0FB46C39660FE /* [CP] Check Pods Manifest.lock */,
+				8E54A65EC2374C96D72E72EB /* [CP] Check Pods Manifest.lock */,
 				33CC10E92044A3C60003C045 /* Sources */,
 				33CC10EA2044A3C60003C045 /* Frameworks */,
 				33CC10EB2044A3C60003C045 /* Resources */,
 				33CC110E2044A8840003C045 /* Bundle Framework */,
 				3399D490228B24CF009A79C7 /* ShellScript */,
-				9092D76C686A497A89A31B0A /* [CP] Embed Pods Frameworks */,
+				8AEB9E182B43A490F7FF61EE /* [CP] Embed Pods Frameworks */,
 			);
 			buildRules = (
 			);
@@ -203,7 +203,7 @@
 			isa = PBXProject;
 			attributes = {
 				LastSwiftUpdateCheck = 0920;
-				LastUpgradeCheck = 1300;
+				LastUpgradeCheck = 1430;
 				ORGANIZATIONNAME = "";
 				TargetAttributes = {
 					33CC10EC2044A3C60003C045 = {
@@ -256,6 +256,7 @@
 /* Begin PBXShellScriptBuildPhase section */
 		3399D490228B24CF009A79C7 /* ShellScript */ = {
 			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
 			buildActionMask = 2147483647;
 			files = (
 			);
@@ -291,43 +292,43 @@
 			shellPath = /bin/sh;
 			shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
 		};
-		3B927F223EF0FB46C39660FE /* [CP] Check Pods Manifest.lock */ = {
+		8AEB9E182B43A490F7FF61EE /* [CP] Embed Pods Frameworks */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			inputPaths = (
-				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
-				"${PODS_ROOT}/Manifest.lock",
-			);
-			name = "[CP] Check Pods Manifest.lock";
+			name = "[CP] Embed Pods Frameworks";
 			outputFileListPaths = (
-			);
-			outputPaths = (
-				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
 			showEnvVarsInLog = 0;
 		};
-		9092D76C686A497A89A31B0A /* [CP] Embed Pods Frameworks */ = {
+		8E54A65EC2374C96D72E72EB /* [CP] Check Pods Manifest.lock */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
 			);
-			name = "[CP] Embed Pods Frameworks";
+			inputPaths = (
+				"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+				"${PODS_ROOT}/Manifest.lock",
+			);
+			name = "[CP] Check Pods Manifest.lock";
 			outputFileListPaths = (
-				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+			);
+			outputPaths = (
+				"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+			shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n    # print error to STDERR\n    echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n    exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 			showEnvVarsInLog = 0;
 		};
 /* End PBXShellScriptBuildPhase section */
@@ -404,7 +405,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.11;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
 				SWIFT_COMPILATION_MODE = wholemodule;
@@ -483,7 +484,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.11;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
 				MTL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				SDKROOT = macosx;
@@ -530,7 +531,7 @@
 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
-				MACOSX_DEPLOYMENT_TARGET = 10.11;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				SDKROOT = macosx;
 				SWIFT_COMPILATION_MODE = wholemodule;

+ 1 - 1
example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1300"
+   LastUpgradeVersion = "1430"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png


BIN
example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png


+ 1 - 1
example/macos/Runner/Configs/AppInfo.xcconfig

@@ -11,4 +11,4 @@ PRODUCT_NAME = example
 PRODUCT_BUNDLE_IDENTIFIER = com.example.example
 
 // The copyright displayed in application information
-PRODUCT_COPYRIGHT = Copyright © 2022 com.example. All rights reserved.
+PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved.

+ 6 - 10
example/macos/Runner/MainFlutterWindow.swift

@@ -1,19 +1,15 @@
 import Cocoa
 import FlutterMacOS
-import flutter_acrylic
 
 class MainFlutterWindow: NSWindow {
   override func awakeFromNib() {
-   let windowFrame = self.frame
-   let blurryContainerViewController = BlurryContainerViewController()
-   self.contentViewController = blurryContainerViewController
-   self.setFrame(windowFrame, display: true)
+    let flutterViewController = FlutterViewController.init()
+    let windowFrame = self.frame
+    self.contentViewController = flutterViewController
+    self.setFrame(windowFrame, display: true)
 
-   /* Initialize the flutter_acrylic plugin */
-   MainFlutterWindowManipulator.start(mainFlutterWindow: self)
-
-   RegisterGeneratedPlugins(registry: blurryContainerViewController.flutterViewController)
+    RegisterGeneratedPlugins(registry: flutterViewController)
 
     super.awakeFromNib()
   }
-}
+}

+ 12 - 0
example/macos/RunnerTests/RunnerTests.swift

@@ -0,0 +1,12 @@
+import FlutterMacOS
+import Cocoa
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+  func testExample() {
+    // If you add code to the Runner application, consider adding tests here.
+    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+  }
+
+}

+ 152 - 92
example/pubspec.lock

@@ -5,163 +5,186 @@ packages:
     dependency: transitive
     description:
       name: _fe_analyzer_shared
-      url: "https://pub.dartlang.org"
+      sha256: d976d24314f193899a3079b14fe336215a63a3b1e1c3743eabba8f83e049e9a9
+      url: "https://pub.dev"
     source: hosted
     version: "49.0.0"
   after_layout:
     dependency: "direct main"
     description:
       name: after_layout
-      url: "https://pub.dartlang.org"
+      sha256: "95a1cb2ca1464f44f14769329fbf15987d20ab6c88f8fc5d359bd362be625f29"
+      url: "https://pub.dev"
     source: hosted
     version: "1.2.0"
   analyzer:
     dependency: transitive
     description:
       name: analyzer
-      url: "https://pub.dartlang.org"
+      sha256: "40ba2c6d2ab41a66476f8f1f099da6be0795c1b47221f5e2c5f8ad6048cdffae"
+      url: "https://pub.dev"
     source: hosted
     version: "5.1.0"
   analyzer_plugin:
     dependency: transitive
     description:
       name: analyzer_plugin
-      url: "https://pub.dartlang.org"
+      sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d
+      url: "https://pub.dev"
     source: hosted
     version: "0.11.2"
   ansicolor:
     dependency: transitive
     description:
       name: ansicolor
-      url: "https://pub.dartlang.org"
+      sha256: "607f8fa9786f392043f169898923e6c59b4518242b68b8862eb8a8b7d9c30b4a"
+      url: "https://pub.dev"
     source: hosted
     version: "2.0.1"
   args:
     dependency: transitive
     description:
       name: args
-      url: "https://pub.dartlang.org"
+      sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
+      url: "https://pub.dev"
     source: hosted
-    version: "2.4.0"
+    version: "2.4.1"
   asn1lib:
     dependency: transitive
     description:
       name: asn1lib
-      url: "https://pub.dartlang.org"
+      sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
+      url: "https://pub.dev"
     source: hosted
     version: "1.4.0"
   async:
     dependency: transitive
     description:
       name: async
-      url: "https://pub.dartlang.org"
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.9.0"
+    version: "2.11.0"
   boolean_selector:
     dependency: transitive
     description:
       name: boolean_selector
-      url: "https://pub.dartlang.org"
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.1"
   characters:
     dependency: transitive
     description:
       name: characters
-      url: "https://pub.dartlang.org"
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.dev"
     source: hosted
-    version: "1.2.1"
+    version: "1.3.0"
   clock:
     dependency: transitive
     description:
       name: clock
-      url: "https://pub.dartlang.org"
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.dev"
     source: hosted
     version: "1.1.1"
   collection:
     dependency: transitive
     description:
       name: collection
-      url: "https://pub.dartlang.org"
+      sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
+      url: "https://pub.dev"
     source: hosted
-    version: "1.16.0"
+    version: "1.17.1"
   convert:
     dependency: transitive
     description:
       name: convert
-      url: "https://pub.dartlang.org"
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.dev"
     source: hosted
     version: "3.1.1"
   crypto:
     dependency: transitive
     description:
       name: crypto
-      url: "https://pub.dartlang.org"
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
+    version: "3.0.3"
   csslib:
     dependency: transitive
     description:
       name: csslib
-      url: "https://pub.dartlang.org"
+      sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745
+      url: "https://pub.dev"
     source: hosted
     version: "0.17.2"
   dart_code_metrics:
     dependency: "direct dev"
     description:
       name: dart_code_metrics
-      url: "https://pub.dartlang.org"
+      sha256: "219607f5abbf4c0d254ca39ee009f9ff28df91c40aef26718fde15af6b7a6c24"
+      url: "https://pub.dev"
     source: hosted
     version: "4.21.3"
   dart_style:
     dependency: transitive
     description:
       name: dart_style
-      url: "https://pub.dartlang.org"
+      sha256: "5be16bf1707658e4c03078d4a9b90208ded217fb02c163e207d334082412f2fb"
+      url: "https://pub.dev"
     source: hosted
     version: "2.2.5"
   dartssh2:
     dependency: "direct main"
     description:
       name: dartssh2
-      url: "https://pub.dartlang.org"
+      sha256: "53a230c7dd6f487b704ceef1b29323ad64d19be89e786ccbc81e157a70417a56"
+      url: "https://pub.dev"
     source: hosted
     version: "2.8.2"
   equatable:
     dependency: transitive
     description:
       name: equatable
-      url: "https://pub.dartlang.org"
+      sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
+      url: "https://pub.dev"
     source: hosted
     version: "2.0.5"
   fake_async:
     dependency: transitive
     description:
       name: fake_async
-      url: "https://pub.dartlang.org"
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.dev"
     source: hosted
     version: "1.3.1"
   ffi:
     dependency: transitive
     description:
       name: ffi
-      url: "https://pub.dartlang.org"
+      sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
+      url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.2"
   file:
     dependency: transitive
     description:
       name: file
-      url: "https://pub.dartlang.org"
+      sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
+      url: "https://pub.dev"
     source: hosted
     version: "6.1.4"
   file_picker:
     dependency: "direct main"
     description:
       name: file_picker
-      url: "https://pub.dartlang.org"
+      sha256: c7a8e25ca60e7f331b153b0cb3d405828f18d3e72a6fa1d9440c86556fffc877
+      url: "https://pub.dev"
     source: hosted
-    version: "5.0.1"
+    version: "5.3.0"
   flutter:
     dependency: "direct main"
     description: flutter
@@ -171,14 +194,16 @@ packages:
     dependency: transitive
     description:
       name: flutter_plugin_android_lifecycle
-      url: "https://pub.dartlang.org"
+      sha256: "96af49aa6b57c10a312106ad6f71deed5a754029c24789bbf620ba784f0bd0b0"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.0.12"
+    version: "2.0.14"
   flutter_pty:
     dependency: "direct main"
     description:
       name: flutter_pty
-      url: "https://pub.dartlang.org"
+      sha256: "1f3114f125e4c447866511560818d6ac368471712cc952a25b5a06586aa80b64"
+      url: "https://pub.dev"
     source: hosted
     version: "0.3.1"
   flutter_test:
@@ -195,154 +220,176 @@ packages:
     dependency: transitive
     description:
       name: glob
-      url: "https://pub.dartlang.org"
+      sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
+      url: "https://pub.dev"
     source: hosted
     version: "2.1.1"
   html:
     dependency: transitive
     description:
       name: html
-      url: "https://pub.dartlang.org"
+      sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8"
+      url: "https://pub.dev"
     source: hosted
-    version: "0.15.2"
+    version: "0.15.3"
   http:
     dependency: transitive
     description:
       name: http
-      url: "https://pub.dartlang.org"
+      sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
+      url: "https://pub.dev"
     source: hosted
-    version: "0.13.5"
+    version: "0.13.6"
   http_parser:
     dependency: transitive
     description:
       name: http_parser
-      url: "https://pub.dartlang.org"
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.dev"
     source: hosted
     version: "4.0.2"
   js:
     dependency: transitive
     description:
       name: js
-      url: "https://pub.dartlang.org"
+      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+      url: "https://pub.dev"
     source: hosted
-    version: "0.6.4"
+    version: "0.6.7"
   json_annotation:
     dependency: transitive
     description:
       name: json_annotation
-      url: "https://pub.dartlang.org"
+      sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
+      url: "https://pub.dev"
     source: hosted
-    version: "4.8.0"
+    version: "4.8.1"
   lints:
     dependency: "direct dev"
     description:
       name: lints
-      url: "https://pub.dartlang.org"
+      sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.0.1"
+    version: "2.1.0"
   matcher:
     dependency: transitive
     description:
       name: matcher
-      url: "https://pub.dartlang.org"
+      sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
+      url: "https://pub.dev"
     source: hosted
-    version: "0.12.12"
+    version: "0.12.15"
   material_color_utilities:
     dependency: transitive
     description:
       name: material_color_utilities
-      url: "https://pub.dartlang.org"
+      sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
+      url: "https://pub.dev"
     source: hosted
-    version: "0.1.5"
+    version: "0.2.0"
   meta:
     dependency: transitive
     description:
       name: meta
-      url: "https://pub.dartlang.org"
+      sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
+      url: "https://pub.dev"
     source: hosted
-    version: "1.8.0"
+    version: "1.9.1"
   package_config:
     dependency: transitive
     description:
       name: package_config
-      url: "https://pub.dartlang.org"
+      sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
+      url: "https://pub.dev"
     source: hosted
     version: "2.1.0"
   path:
     dependency: "direct main"
     description:
       name: path
-      url: "https://pub.dartlang.org"
+      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      url: "https://pub.dev"
     source: hosted
-    version: "1.8.2"
+    version: "1.8.3"
   petitparser:
     dependency: transitive
     description:
       name: petitparser
-      url: "https://pub.dartlang.org"
+      sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
+      url: "https://pub.dev"
     source: hosted
-    version: "5.1.0"
+    version: "5.4.0"
   pinenacl:
     dependency: transitive
     description:
       name: pinenacl
-      url: "https://pub.dartlang.org"
+      sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327"
+      url: "https://pub.dev"
     source: hosted
     version: "0.5.1"
   platform:
     dependency: transitive
     description:
       name: platform
-      url: "https://pub.dartlang.org"
+      sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
+      url: "https://pub.dev"
     source: hosted
     version: "3.1.0"
   platform_info:
     dependency: transitive
     description:
       name: platform_info
-      url: "https://pub.dartlang.org"
+      sha256: "012e73712166cf0b56d3eb95c0d33491f56b428c169eca385f036448474147e4"
+      url: "https://pub.dev"
     source: hosted
     version: "3.2.0"
   plugin_platform_interface:
     dependency: transitive
     description:
       name: plugin_platform_interface
-      url: "https://pub.dartlang.org"
+      sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc"
+      url: "https://pub.dev"
     source: hosted
     version: "2.1.4"
   pointycastle:
     dependency: transitive
     description:
       name: pointycastle
-      url: "https://pub.dartlang.org"
+      sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
+      url: "https://pub.dev"
     source: hosted
     version: "3.7.3"
   process:
     dependency: transitive
     description:
       name: process
-      url: "https://pub.dartlang.org"
+      sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
+      url: "https://pub.dev"
     source: hosted
     version: "4.2.4"
   pub_semver:
     dependency: transitive
     description:
       name: pub_semver
-      url: "https://pub.dartlang.org"
+      sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.1.3"
+    version: "2.1.4"
   pub_updater:
     dependency: transitive
     description:
       name: pub_updater
-      url: "https://pub.dartlang.org"
+      sha256: "42890302ab2672adf567dc2b20e55b4ecc29d7e19c63b6b98143ab68dd717d3a"
+      url: "https://pub.dev"
     source: hosted
     version: "0.2.4"
   quiver:
     dependency: transitive
     description:
       name: quiver
-      url: "https://pub.dartlang.org"
+      sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47
+      url: "https://pub.dev"
     source: hosted
     version: "3.2.1"
   sky_engine:
@@ -354,100 +401,113 @@ packages:
     dependency: transitive
     description:
       name: source_span
-      url: "https://pub.dartlang.org"
+      sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
+      url: "https://pub.dev"
     source: hosted
-    version: "1.9.0"
+    version: "1.9.1"
   stack_trace:
     dependency: transitive
     description:
       name: stack_trace
-      url: "https://pub.dartlang.org"
+      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+      url: "https://pub.dev"
     source: hosted
-    version: "1.10.0"
+    version: "1.11.0"
   stream_channel:
     dependency: transitive
     description:
       name: stream_channel
-      url: "https://pub.dartlang.org"
+      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.1.0"
+    version: "2.1.1"
   string_scanner:
     dependency: transitive
     description:
       name: string_scanner
-      url: "https://pub.dartlang.org"
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.dev"
     source: hosted
-    version: "1.1.1"
+    version: "1.2.0"
   term_glyph:
     dependency: transitive
     description:
       name: term_glyph
-      url: "https://pub.dartlang.org"
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.dev"
     source: hosted
     version: "1.2.1"
   test_api:
     dependency: transitive
     description:
       name: test_api
-      url: "https://pub.dartlang.org"
+      sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
+      url: "https://pub.dev"
     source: hosted
-    version: "0.4.12"
+    version: "0.5.1"
   typed_data:
     dependency: transitive
     description:
       name: typed_data
-      url: "https://pub.dartlang.org"
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.dev"
     source: hosted
-    version: "1.3.1"
+    version: "1.3.2"
   vector_math:
     dependency: transitive
     description:
       name: vector_math
-      url: "https://pub.dartlang.org"
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.1.2"
+    version: "2.1.4"
   watcher:
     dependency: transitive
     description:
       name: watcher
-      url: "https://pub.dartlang.org"
+      sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+      url: "https://pub.dev"
     source: hosted
     version: "1.0.2"
   win32:
     dependency: transitive
     description:
       name: win32
-      url: "https://pub.dartlang.org"
+      sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
+      url: "https://pub.dev"
     source: hosted
-    version: "2.7.0"
+    version: "4.1.4"
   xml:
     dependency: transitive
     description:
       name: xml
-      url: "https://pub.dartlang.org"
+      sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
+      url: "https://pub.dev"
     source: hosted
-    version: "6.1.0"
+    version: "6.3.0"
   xterm:
     dependency: "direct main"
     description:
       path: ".."
       relative: true
     source: path
-    version: "3.5.0"
+    version: "3.6.1-pre"
   yaml:
     dependency: transitive
     description:
       name: yaml
-      url: "https://pub.dartlang.org"
+      sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
+      url: "https://pub.dev"
     source: hosted
-    version: "3.1.1"
+    version: "3.1.2"
   zmodem:
     dependency: transitive
     description:
       name: zmodem
-      url: "https://pub.dartlang.org"
+      sha256: "3b7e5b29f3a7d8aee472029b05165a68438eff2f3f7766edf13daba1e297adbf"
+      url: "https://pub.dev"
     source: hosted
     version: "0.0.6"
 sdks:
-  dart: ">=2.18.0 <3.0.0"
+  dart: ">=3.0.0 <4.0.0"
   flutter: ">=3.0.0"

+ 3 - 2
example/pubspec.yaml

@@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
 version: 1.0.0+1
 
 environment:
-  sdk: ">=2.17.0 <3.0.0"
+  sdk: ">=3.0.0 <4.0.0"
 
 dependencies:
   xterm:
@@ -62,7 +62,8 @@ flutter:
   uses-material-design: true
 
   # To add assets to your application, add an assets section, like this:
-  # assets:
+  assets:
+    - assets/
   #   - images/a_dot_burr.jpeg
   #   - images/a_dot_ham.jpeg
 

+ 0 - 3
example/windows/flutter/generated_plugin_registrant.cc

@@ -6,9 +6,6 @@
 
 #include "generated_plugin_registrant.h"
 
-#include <flutter_acrylic/flutter_acrylic_plugin.h>
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
-  FlutterAcrylicPluginRegisterWithRegistrar(
-      registry->GetRegistrarForPlugin("FlutterAcrylicPlugin"));
 }

+ 0 - 1
example/windows/flutter/generated_plugins.cmake

@@ -3,7 +3,6 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
-  flutter_acrylic
 )
 
 list(APPEND FLUTTER_FFI_PLUGIN_LIST