diff --git a/lib/core/features/action.dart b/lib/core/features/action.dart index 719cfdc..575c82f 100644 --- a/lib/core/features/action.dart +++ b/lib/core/features/action.dart @@ -13,17 +13,20 @@ enum MUDActionTarget { output, immediate, none, + variable, } class MUDAction { String content; Automation? parent; MUDActionTarget target; + List args; MUDAction( this.content, { this.target = MUDActionTarget.execute, this.parent, + this.args = const [], }); void invoke(GameStore store, List matches) { @@ -78,6 +81,10 @@ class MUDAction { debugPrint('ActionSendTo.immediate: $content'); store.send(content); break; + case MUDActionTarget.variable: + debugPrint('ActionSendTo.variable: $content'); + store.saveVariable(args.single, content); + break; case MUDActionTarget.none: debugPrint('ActionSendTo.none: $content'); break; diff --git a/lib/core/features/alias.dart b/lib/core/features/alias.dart index 21f8420..aa61a4a 100644 --- a/lib/core/features/alias.dart +++ b/lib/core/features/alias.dart @@ -39,23 +39,23 @@ class Alias extends Automation { ); static AliasProcessResult processLine( - GameStore store, List triggers, String line) { + GameStore store, List aliases, String line) { final res = AliasProcessResult(); final str = ColorUtils.stripColor(line); - for (final trigger in triggers) { - if (!trigger.isAvailable) { + for (final alias in aliases) { + if (!alias.isAvailable) { continue; } - if (trigger.matches(str)) { + if (alias.matches(str)) { res.processed = true; - trigger.invokeEffect(store, str); - if (trigger.isRemovedFromBuffer || + alias.invokeEffect(store, str); + if (alias.isRemovedFromBuffer || [MUDActionTarget.script, MUDActionTarget.input] - .contains(trigger.action.target)) { + .contains(alias.action.target)) { res.lineRemoved = true; } - if (trigger.autoDisable) { - trigger.tempDisabled = true; + if (alias.autoDisable) { + alias.tempDisabled = true; } } } diff --git a/lib/core/features/automation.dart b/lib/core/features/automation.dart index 3542854..93064f0 100644 --- a/lib/core/features/automation.dart +++ b/lib/core/features/automation.dart @@ -19,6 +19,7 @@ class Automation { /// This is used to temporarily disable an automation after using it once when it has autoDisable set to true. bool tempDisabled = false; MUDAction action; + String get displayName => label.isNotEmpty ? label : pattern; Automation({ this.enabled = true, diff --git a/lib/core/features/lua.dart b/lib/core/features/lua.dart index 0bcaf3b..7798c25 100644 --- a/lib/core/features/lua.dart +++ b/lib/core/features/lua.dart @@ -6,7 +6,6 @@ import 'action.dart'; import 'alias.dart'; import 'game_button_set.dart'; import 'trigger.dart'; -import 'variable.dart'; class LuaInterpreter { LuaState state = LuaState.newState(); @@ -99,13 +98,7 @@ class LuaBindings { ls.pop(2); debugPrint("lua.setVariable $name, $value"); final profile = store.currentProfile; - if (profile.variables[name] == null) { - profile.variables[name] = Variable(name, value); - } - profile.variables[name]!.value = value; - profile.saveVariable( - profile.variables[name]!, - ); + profile.saveVariable(name, value); return 0; } diff --git a/lib/core/features/plugin.dart b/lib/core/features/plugin.dart index 0ca2cf0..de1a416 100644 --- a/lib/core/features/plugin.dart +++ b/lib/core/features/plugin.dart @@ -145,8 +145,9 @@ class PluginBase extends ChangeNotifier { return storage.deleteFile('button_sets/${buttonSet.id}'); } - Future saveVariable(Variable update) async { - debugPrint('$this saveVariable: $update'); + Future saveVariable(String name, String value) async { + debugPrint('$this saveVariable: $name, $value'); + final update = Variable(name, value); variables[update.name] = update; notifyListeners(); return storage.writeFile( diff --git a/lib/core/features/profile.dart b/lib/core/features/profile.dart index fa81ccd..bf61298 100644 --- a/lib/core/features/profile.dart +++ b/lib/core/features/profile.dart @@ -192,6 +192,7 @@ class MUDProfile extends PluginBase { return password; } } + } enum AuthMethod { diff --git a/lib/core/routes.dart b/lib/core/routes.dart index 08c2414..c59a80d 100644 --- a/lib/core/routes.dart +++ b/lib/core/routes.dart @@ -110,7 +110,7 @@ final routes = { builder: (context, store, child) => VariableListPage( variables: store.currentProfile.variables.values.toList(), onSave: (variable) async { - store.currentProfile.saveVariable(variable); + store.currentProfile.saveVariable(variable.name, variable.value); }, ), ), diff --git a/lib/core/store.dart b/lib/core/store.dart index f5492ba..36f09aa 100644 --- a/lib/core/store.dart +++ b/lib/core/store.dart @@ -12,7 +12,6 @@ import 'package:provider/provider.dart'; import '../core/features/settings.dart'; import '../core/profile_presets.dart'; import '../core/storage.dart'; -import '../core/string_utils.dart'; import 'consts.dart'; import 'features/action.dart'; import 'features/alias.dart'; @@ -166,7 +165,11 @@ class GameStore extends ChangeNotifier { if (color != null && !line.startsWith('$esc[')) { line = '$esc[${color}m$line'; } - onLine(line, newLine: i != lines.length - 1); + onLine( + line, + // newLine: i != lines.length - 1); + newLine: true, + ); } } @@ -250,6 +253,7 @@ class GameStore extends ChangeNotifier { void onLine(String line, {bool newLine = false}) { final result = Trigger.processLine(this, triggers, line); + debugPrint('Processed line: $line'); if (!result.lineRemoved) { echo(line, newLine: newLine); } @@ -499,6 +503,10 @@ class GameStore extends ChangeNotifier { static GameStore of(BuildContext context) { return Provider.of(context, listen: false); } + + void saveVariable(String name, String value) { + currentProfile.saveVariable(name, value); + } } mixin GameStoreMixin { diff --git a/lib/pages/alias_list_page.dart b/lib/pages/alias_list_page.dart index c32e869..98e2e81 100644 --- a/lib/pages/alias_list_page.dart +++ b/lib/pages/alias_list_page.dart @@ -3,7 +3,7 @@ import 'package:mudblock/core/store.dart'; import '../core/features/alias.dart'; import '../core/routes.dart'; -import 'generic_list_page.dart'; +import 'automation_list_page.dart'; class AliasListPage extends StatelessWidget with GameStoreMixin { const AliasListPage({ @@ -19,59 +19,13 @@ class AliasListPage extends StatelessWidget with GameStoreMixin { @override Widget build(BuildContext context) { - return GenericListPage( - title: const Text('Aliases'), - save: onSave, - items: storeOf(context).currentProfile.aliases, - detailsPath: Paths.alias, - displayName: (alias) => alias.pattern, - searchTags: (alias) => [ - alias.action.content, - alias.group, - ], - itemBuilder: (context, alias) { - return ListTile( - key: Key(alias.id), - title: Text(alias.pattern), - subtitle: Text(alias.action.content.replaceAll('\n', ' ')), - leading: Switch.adaptive( - value: alias.enabled, - onChanged: (value) { - alias.enabled = value; - onSave(alias); - }, - ), - trailing: PopupMenuButton( - itemBuilder: (context) { - return [ - const PopupMenuItem( - value: 'delete', - child: Text('Delete'), - ), - ]; - }, - onSelected: (value) { - switch (value) { - case 'delete': - onDelete(alias); - break; - } - }, - ), - onTap: () async { - final updated = await Navigator.pushNamed( - context, - Paths.alias, - arguments: alias, - ); - if (updated != null) { - await onSave(updated as Alias); - } - }, - ); - }, + return AutomationListPage( + automations: aliases, + onSave: onSave, + onDelete: onDelete, + detailsPagePath: Paths.alias, + title: 'Aliases', ); } - } diff --git a/lib/pages/automation_list_page.dart b/lib/pages/automation_list_page.dart new file mode 100644 index 0000000..8469032 --- /dev/null +++ b/lib/pages/automation_list_page.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:mudblock/core/store.dart'; + +import '../core/features/automation.dart'; +import 'generic_list_page.dart'; + +class AutomationListPage extends StatelessWidget + with GameStoreMixin { + const AutomationListPage({ + super.key, + required this.automations, + required this.onSave, + required this.onDelete, + required this.detailsPagePath, + required this.title, + }); + + final List automations; + final Future Function(T) onSave; + final Future Function(T) onDelete; + final String detailsPagePath; + final String title; + + @override + Widget build(BuildContext context) { + return GenericListPage( + title: Text(title), + save: onSave, + items: automations, + detailsPath: detailsPagePath, + displayName: (automation) => automation.displayName, + searchTags: (automation) => [ + automation.action.content, + automation.group, + ], + itemBuilder: (context, automation) { + return ListTile( + key: Key(automation.id), + title: Text(automation.displayName), + subtitle: Text(automation.action.content.replaceAll('\n', '↵')), + leading: Switch.adaptive( + value: automation.enabled, + onChanged: (value) { + automation.enabled = value; + onSave(automation); + }, + ), + isThreeLine: true, + trailing: PopupMenuButton( + itemBuilder: (context) { + return [ + const PopupMenuItem( + value: 'delete', + child: Text('Delete'), + ), + ]; + }, + onSelected: (value) { + switch (value) { + case 'delete': + onDelete(automation); + break; + } + }, + ), + onTap: () async { + final updated = await Navigator.pushNamed( + context, + detailsPagePath, + arguments: automation, + ); + if (updated != null) { + await onSave(updated as T); + } + }, + ); + }, + ); + } +} + diff --git a/lib/pages/automation_page.dart b/lib/pages/automation_page.dart index 4108e4f..1d0ba11 100644 --- a/lib/pages/automation_page.dart +++ b/lib/pages/automation_page.dart @@ -26,10 +26,13 @@ class AutomationPage extends StatefulWidget { class _AutomationPageState extends State> { late final T automation; + final variableTargetController = TextEditingController(); @override void initState() { automation = widget.create(widget.automation); + variableTargetController.text = + automation.action.args.isNotEmpty ? automation.action.args.single : ''; super.initState(); } @@ -139,14 +142,12 @@ class _AutomationPageState initialSelection: automation.action.target, onSelected: (value) { if (value is MUDActionTarget) { - automation.action.target = value; + setState(() { + automation.action.target = value; + }); } }, dropdownMenuEntries: const [ - DropdownMenuEntry( - value: MUDActionTarget.world, - label: 'World', - ), DropdownMenuEntry( value: MUDActionTarget.execute, label: 'Execute', @@ -155,6 +156,14 @@ class _AutomationPageState value: MUDActionTarget.script, label: 'Script', ), + DropdownMenuEntry( + value: MUDActionTarget.variable, + label: 'Variable', + ), + DropdownMenuEntry( + value: MUDActionTarget.world, + label: 'World', + ), DropdownMenuEntry( value: MUDActionTarget.input, label: 'Command Input', @@ -169,6 +178,18 @@ class _AutomationPageState ), ], ), + if (automation.action.target == MUDActionTarget.variable) + TextField( + controller: variableTargetController, + decoration: const InputDecoration( + labelText: 'Variable name', + floatingLabelBehavior: FloatingLabelBehavior.always, + helperText: 'The name of the variable to set', + ), + onChanged: (value) { + automation.action.args = [value]; + }, + ), CheckboxListTile( title: const Text('Case Sensitive'), subtitle: const Text( diff --git a/lib/pages/trigger_list_page.dart b/lib/pages/trigger_list_page.dart index 436538a..18e6f99 100644 --- a/lib/pages/trigger_list_page.dart +++ b/lib/pages/trigger_list_page.dart @@ -3,7 +3,7 @@ import 'package:mudblock/core/store.dart'; import '../core/features/trigger.dart'; import '../core/routes.dart'; -import 'generic_list_page.dart'; +import 'automation_list_page.dart'; class TriggerListPage extends StatelessWidget with GameStoreMixin { const TriggerListPage({ @@ -19,58 +19,12 @@ class TriggerListPage extends StatelessWidget with GameStoreMixin { @override Widget build(BuildContext context) { - return GenericListPage( - title: const Text('Triggers'), - save: onSave, - items: storeOf(context).currentProfile.triggers, - detailsPath: Paths.trigger, - displayName: (trigger) => trigger.pattern, - searchTags: (trigger) => [ - trigger.action.content, - trigger.group, - ], - itemBuilder: (context, trigger) { - return ListTile( - key: Key(trigger.id), - title: Text(trigger.pattern), - subtitle: Text(trigger.action.content.replaceAll('\n', ' ')), - leading: Switch.adaptive( - value: trigger.enabled, - onChanged: (value) { - trigger.enabled = value; - onSave(trigger); - }, - ), - isThreeLine: true, - trailing: PopupMenuButton( - itemBuilder: (context) { - return [ - const PopupMenuItem( - value: 'delete', - child: Text('Delete'), - ), - ]; - }, - onSelected: (value) { - switch (value) { - case 'delete': - onDelete(trigger); - break; - } - }, - ), - onTap: () async { - final updated = await Navigator.pushNamed( - context, - Paths.trigger, - arguments: trigger, - ); - if (updated != null) { - await onSave(updated as Trigger); - } - }, - ); - }, + return AutomationListPage( + automations: triggers, + onSave: onSave, + onDelete: onDelete, + detailsPagePath: Paths.trigger, + title: 'Triggers', ); } }