diff --git a/lib/core/features/plugin.dart b/lib/core/features/plugin.dart index 9c4d048..827d8af 100644 --- a/lib/core/features/plugin.dart +++ b/lib/core/features/plugin.dart @@ -88,35 +88,70 @@ class PluginBase extends ChangeNotifier { Future saveAlias(Alias alias) async { debugPrint('MUDProfile.saveAlias: $id/aliases/${alias.id}'); + notifyListeners(); + final idx = aliases.indexWhere((a) => a.id == alias.id); + if (idx >= 0) { + aliases[idx] = alias; + } else { + aliases.add(alias); + } return ProfileStorage.writeProfileFile( id, 'aliases/${alias.id}', alias.toJson()); } Future deleteAlias(Alias alias) async { debugPrint('MUDProfile.deleteAlias: $id/aliases/${alias.id}'); + final idx = aliases.indexWhere((a) => a.id == alias.id); + if (idx >= 0) { + aliases.removeAt(idx); + } + notifyListeners(); return ProfileStorage.deleteProfileFile(id, 'aliases/${alias.id}'); } Future saveTrigger(Trigger trigger) async { debugPrint('MUDProfile.saveTrigger: $id/triggers/${trigger.id}'); + final idx = triggers.indexWhere((a) => a.id == trigger.id); + if (idx >= 0) { + triggers[idx] = trigger; + } else { + triggers.add(trigger); + } + notifyListeners(); return ProfileStorage.writeProfileFile( id, 'triggers/${trigger.id}', trigger.toJson()); } Future deleteTrigger(Trigger trigger) async { debugPrint('MUDProfile.deleteTrigger: $id/triggers/${trigger.id}'); + final idx = triggers.indexWhere((a) => a.id == trigger.id); + if (idx >= 0) { + triggers.removeAt(idx); + } + notifyListeners(); return ProfileStorage.deleteProfileFile(id, 'triggers/${trigger.id}'); } Future saveButtonSet(GameButtonSetData buttonSet) async { debugPrint('MUDProfile.saveButtonSet: $id/button_sets/${buttonSet.id}'); + final idx = buttonSets.indexWhere((a) => a.id == buttonSet.id); + if (idx >= 0) { + buttonSets[idx] = buttonSet; + } else { + buttonSets.add(buttonSet); + } + notifyListeners(); return ProfileStorage.writeProfileFile( id, 'button_sets/${buttonSet.id}', buttonSet.toJson()); } - Future deleteButtonSet(GameButtonSetData buttonSet) async { debugPrint('MUDProfile.deleteButtonSet: $id/button_sets/${buttonSet.id}'); + final idx = buttonSets.indexWhere((a) => a.id == buttonSet.id); + if (idx >= 0) { + buttonSets.removeAt(idx); + } + notifyListeners(); return ProfileStorage.deleteProfileFile(id, 'button_sets/${buttonSet.id}'); } @@ -130,6 +165,7 @@ class PluginBase extends ChangeNotifier { } else { current.add(update); } + notifyListeners(); return ProfileStorage.writeProfileFile( id, 'vars', @@ -145,6 +181,7 @@ class PluginBase extends ChangeNotifier { if (existing >= 0) { current.removeAt(existing); } + notifyListeners(); return ProfileStorage.writeProfileFile( id, 'vars', diff --git a/lib/core/store.dart b/lib/core/store.dart index 76f3f5e..4cba3ab 100644 --- a/lib/core/store.dart +++ b/lib/core/store.dart @@ -21,14 +21,14 @@ const maxLines = 2000; class GameStore extends ChangeNotifier { final List _lines = []; - late CTelnetClient _client; + CTelnetClient get _client => _clientRef!; + CTelnetClient? _clientRef; final ScrollController scrollController = ScrollController(); final TextEditingController input = TextEditingController(); final FocusNode inputFocus = FocusNode(); bool isCompressed = false; final ZLibDecoder decoder = ZLibDecoder(); final incomingMsgSplitPattern = RegExp("($cr$lf)|($lf$cr)|$cr|$lf"); - // accepts csp but NOT double csp final ZLibCodec _decoder = ZLibCodec(); final StreamController> _rawStreamController = StreamController(); late Stream> _decodedStream; @@ -38,6 +38,8 @@ class GameStore extends ChangeNotifier { bool _clientReady = false; String get commandSeparator => currentProfile.settings.commandSeparator; + + /// accepts csp but NOT double csp RegExp get outgoingMsgSplitPattern => RegExp("(?( - context: context, - builder: (context) { - return const SelectProfilePage(); - }); + context: context, + builder: (context) => const SelectProfilePage(), + ); if (profile == null) { return; } - _currentProfile?.removeListener(notifyListeners); + _currentProfile?.removeListener(onProfileUpdate); _currentProfile = profile; - currentProfile.addListener(notifyListeners); - echo('Connecting...'); - _client = CTelnetClient( + currentProfile.addListener(onProfileUpdate); + + await _clientRef?.disconnect(); + + _clientRef = CTelnetClient( host: currentProfile.host, port: currentProfile.port, onConnect: _onConnect, @@ -73,6 +76,7 @@ class GameStore extends ChangeNotifier { onError: onError, ); await currentProfile.load(); + echoSystem('Connecting...'); _client.connect(); notifyListeners(); } @@ -117,7 +121,7 @@ class GameStore extends ChangeNotifier { Future _onConnect() async { _clientReady = true; - echo('Connected'); + echoSystem('Connected'); if (currentProfile.authMethod != AuthMethod.none && currentProfile.username.isNotEmpty && currentProfile.password.isNotEmpty) { @@ -142,7 +146,7 @@ class GameStore extends ChangeNotifier { } void onDisconnect() { - echo('Disconnected'); + echoSystem('Disconnected'); } void onRawData(List bytes) { @@ -154,8 +158,9 @@ class GameStore extends ChangeNotifier { } } catch (e, stack) { debugPrint('error: $e$newline$stack'); - echo(String.fromCharCodes(bytes)); - echo('Error: $e'); + echoError('Error: $e'); + echoError('The original line was:'); + echoError(String.fromCharCodes(bytes)); } } @@ -234,16 +239,17 @@ class GameStore extends ChangeNotifier { /// echoOwn - same as echo, but with predefined color void echoOwn(String line) { - _lines.add('$esc[93m$line'); - notifyListeners(); - scrollToEnd(); + echo('$esc[93m$line'); } /// echoSystem - same as echo, but with predefined color void echoSystem(String line) { - _lines.add('$esc[92m$line'); - notifyListeners(); - scrollToEnd(); + echo('$esc[96m$line'); + } + + /// echoError - same as echo, but with predefined color + void echoError(String line) { + echo('$esc[31;1m$line'); } /// sendBytes - raw send bytes - DOES NOT split by outgoingMsgSplitPattern, no processing @@ -428,6 +434,10 @@ class GameStore extends ChangeNotifier { } echoSystem(''); } + + void onProfileUpdate() { + notifyListeners(); + } } mixin GameStoreMixin { diff --git a/lib/dialogs/button_editor_dialog.dart b/lib/dialogs/button_editor_dialog.dart index dfd22ea..ac173f0 100644 --- a/lib/dialogs/button_editor_dialog.dart +++ b/lib/dialogs/button_editor_dialog.dart @@ -63,7 +63,9 @@ class _ButtonEditorDialogState extends State { label: Text(capitalize(interaction.name)), ), onChanged: (value) { - data.setAction(interaction, MUDAction(value)); + setState(() { + data.setAction(interaction, MUDAction(value)); + }); }, ), ), @@ -115,3 +117,4 @@ class _ButtonEditorDialogState extends State { ); } } + diff --git a/lib/widgets/button_set_editor.dart b/lib/widgets/button_set_editor.dart index e983e2e..ae26587 100644 --- a/lib/widgets/button_set_editor.dart +++ b/lib/widgets/button_set_editor.dart @@ -52,6 +52,7 @@ class _ButtonSetEditorState extends State { onSave: (data) { setState(() { this.data.buttons[index] = data; + widget.onUpdate(this.data); }); }, ), @@ -65,6 +66,7 @@ class _ButtonSetEditorState extends State { onSave: (data) { setState(() { this.data.buttons[index] = data; + widget.onUpdate(this.data); }); }, ),