feat: unified automation list page

This commit is contained in:
2023-10-31 03:07:04 +02:00
parent 4496592f67
commit 03bb875cc7
12 changed files with 154 additions and 133 deletions

View File

@@ -13,17 +13,20 @@ enum MUDActionTarget {
output,
immediate,
none,
variable,
}
class MUDAction {
String content;
Automation? parent;
MUDActionTarget target;
List<String> args;
MUDAction(
this.content, {
this.target = MUDActionTarget.execute,
this.parent,
this.args = const [],
});
void invoke(GameStore store, List<String> 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;

View File

@@ -39,23 +39,23 @@ class Alias extends Automation {
);
static AliasProcessResult processLine(
GameStore store, List<Alias> triggers, String line) {
GameStore store, List<Alias> 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;
}
}
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -145,8 +145,9 @@ class PluginBase extends ChangeNotifier {
return storage.deleteFile('button_sets/${buttonSet.id}');
}
Future<void> saveVariable(Variable update) async {
debugPrint('$this saveVariable: $update');
Future<void> saveVariable(String name, String value) async {
debugPrint('$this saveVariable: $name, $value');
final update = Variable(name, value);
variables[update.name] = update;
notifyListeners();
return storage.writeFile(

View File

@@ -192,6 +192,7 @@ class MUDProfile extends PluginBase {
return password;
}
}
}
enum AuthMethod {

View File

@@ -110,7 +110,7 @@ final routes = <String, Widget Function(BuildContext)>{
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);
},
),
),

View File

@@ -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<GameStore>(context, listen: false);
}
void saveVariable(String name, String value) {
currentProfile.saveVariable(name, value);
}
}
mixin GameStoreMixin {

View File

@@ -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<Alias>(
automations: aliases,
onSave: onSave,
onDelete: onDelete,
detailsPagePath: Paths.alias,
title: 'Aliases',
);
}
}

View File

@@ -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<T extends Automation> 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<T> automations;
final Future<void> Function(T) onSave;
final Future<void> 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);
}
},
);
},
);
}
}

View File

@@ -26,10 +26,13 @@ class AutomationPage<T extends Automation> extends StatefulWidget {
class _AutomationPageState<T extends Automation>
extends State<AutomationPage<T>> {
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<T extends Automation>
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<T extends Automation>
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<T extends Automation>
),
],
),
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(

View File

@@ -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<Trigger>(
automations: triggers,
onSave: onSave,
onDelete: onDelete,
detailsPagePath: Paths.trigger,
title: 'Triggers',
);
}
}