diff --git a/doc/package-lock.json b/doc/package-lock.json index 809a1c6..e6ac82a 100644 --- a/doc/package-lock.json +++ b/doc/package-lock.json @@ -1,11 +1,11 @@ { - "name": "my-website", + "name": "asp_doc", "version": "0.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "my-website", + "name": "asp_doc", "version": "0.0.0", "dependencies": { "@docusaurus/core": "3.4.0", diff --git a/example/command_hub/apps/desktop/lib/app/(public)/home/(pages)/commands_page.dart b/example/command_hub/apps/desktop/lib/app/(public)/home/(pages)/commands_page.dart index f4da7b9..4de577c 100644 --- a/example/command_hub/apps/desktop/lib/app/(public)/home/(pages)/commands_page.dart +++ b/example/command_hub/apps/desktop/lib/app/(public)/home/(pages)/commands_page.dart @@ -22,6 +22,79 @@ class CommandsPage extends StatefulWidget { } class _CommandsPageState extends State { + void _createCommand() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Create command'), + content: const Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('data'), + SizedBox(height: 10), + TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Name', + ), + ), + SizedBox(height: 10), + TextField( + decoration: InputDecoration( + border: OutlineInputBorder(), + labelText: 'Name', + ), + maxLines: 3, + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Save'), + ), + ], + ); + }, + ); + } + + void _confirmDelete() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Delete command'), + content: const Text('Are you sure you want to delete this command?'), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Cancel'), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('Delete'), + ), + ], + ); + }, + ); + } + @override Widget build(BuildContext context) { return CommandScaffold( @@ -40,6 +113,10 @@ class _CommandsPageState extends State { CommandTile( title: 'Command 1', icon: Icons.ac_unit, + actions: const ['Edit', 'Delete'], + onAction: (action) { + _confirmDelete(); + }, onLongPress: () { Routefly.push(routePaths.home.editCommand); }, @@ -47,6 +124,10 @@ class _CommandsPageState extends State { CommandTile( title: 'Command 2', icon: Icons.access_alarm, + actions: const ['Edit', 'Delete'], + onAction: (action) { + _createCommand(); + }, onLongPress: () { Routefly.push(routePaths.home.editCommand); }, diff --git a/example/command_hub/apps/mobile/lib/app/(public)/home_page.dart b/example/command_hub/apps/mobile/lib/app/(public)/home_page.dart index e69de29..0ff65ec 100644 --- a/example/command_hub/apps/mobile/lib/app/(public)/home_page.dart +++ b/example/command_hub/apps/mobile/lib/app/(public)/home_page.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; + +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/example/command_hub/packages/core_module/lib/core_module.dart b/example/command_hub/packages/core_module/lib/core_module.dart index 86e53f9..d1d8aea 100644 --- a/example/command_hub/packages/core_module/lib/core_module.dart +++ b/example/command_hub/packages/core_module/lib/core_module.dart @@ -2,5 +2,4 @@ library core_module; export 'package:routefly/routefly.dart'; -export 'src/agent.dart'; -export 'src/pipeline.dart'; +export 'src/command.dart'; diff --git a/example/command_hub/packages/core_module/lib/src/agent.dart b/example/command_hub/packages/core_module/lib/src/agent.dart deleted file mode 100644 index 6b4bc64..0000000 --- a/example/command_hub/packages/core_module/lib/src/agent.dart +++ /dev/null @@ -1,96 +0,0 @@ -import 'dart:io'; - -class Agent { - final String name; - final String description; - final List inputs; - final Map platformCommands; - - Agent({ - required this.name, - required this.description, - required this.inputs, - required this.platformCommands, - }); - - factory Agent.fromYaml(Map yaml) { - var inputs = (yaml['inputs'] as List).map((input) => Input.fromYaml(input)).toList(); - - var platform = (yaml['platform'] as Map).map( - (key, value) => MapEntry(key, value['execute'] as String), - ); - - return Agent( - name: yaml['name'], - description: yaml['description'], - inputs: inputs, - platformCommands: platform, - ); - } - - Future execute(Map vars) async { - var platform = Platform.operatingSystem; - var commandTemplate = platformCommands[platform] ?? platformCommands['all']; - - if (commandTemplate != null) { - var finalCommand = commandTemplate; - for (var entry in vars.entries) { - final key = entry.key; - final value = entry.value; - finalCommand = finalCommand.replaceAll('\${$key}', value.toString()); - } - - // Seleciona o shell apropriado para a plataforma - List shellCommand; - if (platform == 'windows') { - shellCommand = ['powershell', '-Command', finalCommand]; - } else { - shellCommand = ['bash', '-c', finalCommand]; - } - - // Executa o comando usando Process.run e retorna stdout ou stderr - try { - var result = await Process.run(shellCommand.first, shellCommand.sublist(1)); - return _processResult(result); - } catch (e) { - return 'Erro ao executar o comando: $e'; - } - } else { - return 'Nenhum template de comando encontrado para a plataforma: $platform'; - } - } - - String _processResult(ProcessResult result) { - if (result.exitCode == 0) { - return result.stdout is String ? result.stdout : String.fromCharCodes(result.stdout); - } else { - return result.stderr is String ? result.stderr : String.fromCharCodes(result.stderr); - } - } -} - -class Input { - final String name; - final String description; - final String type; - dynamic _value; - - dynamic get value => _value; - void setValue(dynamic value) { - _value = value; - } - - Input({ - required this.name, - required this.description, - required this.type, - }); - - factory Input.fromYaml(Map yaml) { - return Input( - name: yaml['name'], - description: yaml['description'], - type: yaml['type'], - ); - } -} diff --git a/example/command_hub/packages/core_module/lib/src/command.dart b/example/command_hub/packages/core_module/lib/src/command.dart new file mode 100644 index 0000000..a2b37a9 --- /dev/null +++ b/example/command_hub/packages/core_module/lib/src/command.dart @@ -0,0 +1,58 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:convert'; + +import 'symbol_icon.dart'; + +class Command { + final String name; + final SymbolIcon icon; + final String prompt; + + Command({ + required this.icon, + required this.name, + required this.prompt, + }); + + @override + bool operator ==(covariant Command other) { + if (identical(this, other)) return true; + + return other.name == name && other.icon == icon && other.prompt == prompt; + } + + @override + int get hashCode => name.hashCode ^ icon.hashCode ^ prompt.hashCode; + + Map toMap() { + return { + 'name': name, + 'icon': icon.name, + 'prompt': prompt, + }; + } + + factory Command.fromMap(Map map) { + return Command( + name: map['name'] as String, + icon: SymbolIcon.fromString(map['icon'] as String), + prompt: map['prompt'] as String, + ); + } + + String toJson() => json.encode(toMap()); + + factory Command.fromJson(String source) => Command.fromMap(json.decode(source) as Map); + + Command copyWith({ + String? name, + SymbolIcon? icon, + String? prompt, + }) { + return Command( + name: name ?? this.name, + icon: icon ?? this.icon, + prompt: prompt ?? this.prompt, + ); + } +} diff --git a/example/command_hub/packages/core_module/lib/src/pipeline.dart b/example/command_hub/packages/core_module/lib/src/pipeline.dart deleted file mode 100644 index 0e1e10e..0000000 --- a/example/command_hub/packages/core_module/lib/src/pipeline.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:core_module/core_module.dart'; - -class Pipeline { - final String title; - final bool favorite; - final String description; - final List agents; - - Pipeline({ - required this.title, - required this.favorite, - required this.description, - required this.agents, - }); - - Pipeline copyWith({ - String? title, - String? description, - List? agents, - bool? favorite, - }) { - return Pipeline( - title: title ?? this.title, - description: description ?? this.description, - agents: agents ?? this.agents, - favorite: favorite ?? this.favorite, - ); - } -} diff --git a/example/command_hub/packages/core_module/lib/src/symbol_icon.dart b/example/command_hub/packages/core_module/lib/src/symbol_icon.dart new file mode 100644 index 0000000..3d8af63 --- /dev/null +++ b/example/command_hub/packages/core_module/lib/src/symbol_icon.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +enum SymbolIcon { + home(Icons.home); + + // constructor + final IconData data; + const SymbolIcon(this.data); + + // adapters + static SymbolIcon fromString(String value) { + return SymbolIcon.values.firstWhere( + (e) => e.name == value, + orElse: () => SymbolIcon.home, + ); + } +} diff --git a/example/command_hub/packages/design_system/lib/src/command_tile.dart b/example/command_hub/packages/design_system/lib/src/command_tile.dart index 7f8b3ae..218903e 100644 --- a/example/command_hub/packages/design_system/lib/src/command_tile.dart +++ b/example/command_hub/packages/design_system/lib/src/command_tile.dart @@ -4,6 +4,8 @@ import 'package:flutter/material.dart' hide ColorScheme; class CommandTile extends StatefulWidget { final String title; final IconData icon; + final List actions; + final void Function(String action)? onAction; final void Function()? onTap; final void Function()? onLongPress; @@ -11,6 +13,8 @@ class CommandTile extends StatefulWidget { super.key, this.onTap, this.onLongPress, + this.onAction, + this.actions = const [], required this.title, required this.icon, }); @@ -62,65 +66,86 @@ class _CommandTileState extends State with SingleTickerProviderStat @override Widget build(BuildContext context) { return Card( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - backgroundColor.startColor, - backgroundColor.endColor, - ], - ), - ), - child: InkWell( - borderRadius: BorderRadius.circular(12), - onLongPress: widget.onLongPress, - onTap: _controller.value == 0 - ? () { - _controller.forward().then((_) => _controller.reset()); - widget.onTap?.call(); - } - : null, - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: Stack( - children: [ - FractionalTranslation( - translation: Offset(slideAnimation.value, 0.0), - child: Container( - decoration: BoxDecoration( - color: Colors.black.withOpacity(opacityAnimation.value), - borderRadius: BorderRadius.circular(8), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon( - widget.icon, - color: Colors.white, + child: Stack( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [ + backgroundColor.startColor, + backgroundColor.endColor, + ], + ), + ), + child: InkWell( + borderRadius: BorderRadius.circular(12), + onLongPress: widget.onLongPress, + onTap: _controller.value == 0 + ? () { + _controller.forward().then((_) => _controller.reset()); + widget.onTap?.call(); + } + : null, + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: Stack( + children: [ + FractionalTranslation( + translation: Offset(slideAnimation.value, 0.0), + child: Container( + decoration: BoxDecoration( + color: Colors.black.withOpacity(opacityAnimation.value), + borderRadius: BorderRadius.circular(8), + ), ), - const Spacer(), - Text( - widget.title, - style: Theme.of(context) // - .textTheme - .titleSmall - ?.copyWith(color: Colors.white), + ), + Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + widget.icon, + color: Colors.white, + ), + const Spacer(), + Text( + widget.title, + style: Theme.of(context) // + .textTheme + .titleSmall + ?.copyWith(color: Colors.white), + ), + ], ), - ], - ), + ), + ], ), - ], + ), ), ), - ), + if (widget.actions.isNotEmpty) + Align( + alignment: Alignment.topRight, + child: PopupMenuButton( + offset: const Offset(-80, 10), + iconColor: Colors.white, + onSelected: widget.onAction?.call, + itemBuilder: (context) { + return widget.actions + .map((action) => PopupMenuItem( + value: action, + child: Text(action), + )) + .toList(); + }, + ), + ), + ], ), ); } diff --git a/example/shop_cart/pubspec.lock b/example/shop_cart/pubspec.lock index 97eab63..4e953e0 100644 --- a/example/shop_cart/pubspec.lock +++ b/example/shop_cart/pubspec.lock @@ -31,7 +31,7 @@ packages: path: "../.." relative: true source: path - version: "1.2.0" + version: "2.0.0" async: dependency: transitive description: diff --git a/example/trivial_counter/pubspec.lock b/example/trivial_counter/pubspec.lock index ef1fd74..af246a4 100644 --- a/example/trivial_counter/pubspec.lock +++ b/example/trivial_counter/pubspec.lock @@ -7,7 +7,7 @@ packages: path: "../.." relative: true source: path - version: "1.2.0" + version: "2.0.0" async: dependency: transitive description: diff --git a/example/trivial_counter/windows/flutter/CMakeLists.txt b/example/trivial_counter/windows/flutter/CMakeLists.txt index 930d207..903f489 100644 --- a/example/trivial_counter/windows/flutter/CMakeLists.txt +++ b/example/trivial_counter/windows/flutter/CMakeLists.txt @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -92,7 +97,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS diff --git a/example/trivial_counter/windows/runner/flutter_window.cpp b/example/trivial_counter/windows/runner/flutter_window.cpp index b25e363..955ee30 100644 --- a/example/trivial_counter/windows/runner/flutter_window.cpp +++ b/example/trivial_counter/windows/runner/flutter_window.cpp @@ -31,6 +31,11 @@ bool FlutterWindow::OnCreate() { this->Show(); }); + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + return true; }