mirror of
https://github.com/chenasraf/mudblock.git
synced 2026-05-18 01:48:57 +00:00
feat: add toggles to aliases/triggers
refactor: remove deprecated localstore
This commit is contained in:
@@ -11,7 +11,7 @@ class Alias extends Automation {
|
||||
super.isRegex = false,
|
||||
super.isCaseSensitive = false,
|
||||
super.isRemovedFromBuffer = false,
|
||||
super.isTemporary = false,
|
||||
super.autoDisable = false,
|
||||
super.invokeCount = 0,
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ class Alias extends Automation {
|
||||
isRegex: false,
|
||||
isCaseSensitive: false,
|
||||
isRemovedFromBuffer: false,
|
||||
isTemporary: false,
|
||||
autoDisable: false,
|
||||
invokeCount: 0,
|
||||
action: MUDAction.empty(),
|
||||
);
|
||||
@@ -34,7 +34,7 @@ class Alias extends Automation {
|
||||
isRegex: json['isRegex'],
|
||||
isCaseSensitive: json['isCaseSensitive'],
|
||||
isRemovedFromBuffer: json['isRemovedFromBuffer'],
|
||||
isTemporary: json['isTemporary'],
|
||||
autoDisable: json['autoDisable'],
|
||||
invokeCount: json['invokeCount'],
|
||||
action: MUDAction.fromJson(json['action']),
|
||||
);
|
||||
@@ -47,7 +47,7 @@ class Alias extends Automation {
|
||||
bool? isRegex,
|
||||
bool? isCaseSensitive,
|
||||
bool? isRemovedFromBuffer,
|
||||
bool? isTemporary,
|
||||
bool? autoDisable,
|
||||
int? invokeCount = 0,
|
||||
MUDAction? action,
|
||||
}) =>
|
||||
@@ -58,7 +58,7 @@ class Alias extends Automation {
|
||||
isRegex: isRegex ?? this.isRegex,
|
||||
isCaseSensitive: isCaseSensitive ?? this.isCaseSensitive,
|
||||
isRemovedFromBuffer: isRemovedFromBuffer ?? this.isRemovedFromBuffer,
|
||||
isTemporary: isTemporary ?? this.isTemporary,
|
||||
autoDisable: autoDisable ?? this.autoDisable,
|
||||
invokeCount: invokeCount ?? this.invokeCount,
|
||||
action: action ?? this.action,
|
||||
);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../store.dart';
|
||||
@@ -12,8 +11,10 @@ class Automation {
|
||||
bool isRegex;
|
||||
bool isCaseSensitive;
|
||||
bool isRemovedFromBuffer;
|
||||
bool isTemporary;
|
||||
bool autoDisable;
|
||||
int invokeCount;
|
||||
/// This is used to temporarily disable an automation after using it once when it has autoDisable set to true.
|
||||
bool tempDisabled = false;
|
||||
MUDAction action;
|
||||
|
||||
Automation({
|
||||
@@ -24,10 +25,12 @@ class Automation {
|
||||
this.isRegex = false,
|
||||
this.isCaseSensitive = false,
|
||||
this.isRemovedFromBuffer = false,
|
||||
this.isTemporary = false,
|
||||
this.autoDisable = false,
|
||||
this.invokeCount = 0,
|
||||
});
|
||||
|
||||
bool get isAvailable => enabled && !tempDisabled;
|
||||
|
||||
factory Automation.empty() => Automation(
|
||||
id: uuid(),
|
||||
pattern: '',
|
||||
@@ -35,7 +38,7 @@ class Automation {
|
||||
isRegex: false,
|
||||
isCaseSensitive: false,
|
||||
isRemovedFromBuffer: false,
|
||||
isTemporary: false,
|
||||
autoDisable: false,
|
||||
invokeCount: 0,
|
||||
action: MUDAction.empty(),
|
||||
);
|
||||
@@ -47,7 +50,7 @@ class Automation {
|
||||
isRegex: json['isRegex'],
|
||||
isCaseSensitive: json['isCaseSensitive'],
|
||||
isRemovedFromBuffer: json['isRemovedFromBuffer'],
|
||||
isTemporary: json['isTemporary'],
|
||||
autoDisable: json['autoDisable'],
|
||||
invokeCount: json['invokeCount'],
|
||||
action: MUDAction.fromJson(json['action']),
|
||||
);
|
||||
@@ -59,7 +62,7 @@ class Automation {
|
||||
'isRegex': isRegex,
|
||||
'isCaseSensitive': isCaseSensitive,
|
||||
'isRemovedFromBuffer': isRemovedFromBuffer,
|
||||
'isTemporary': isTemporary,
|
||||
'autoDisable': autoDisable,
|
||||
'invokeCount': invokeCount,
|
||||
'action': action.toJson(),
|
||||
};
|
||||
@@ -122,7 +125,7 @@ class Automation {
|
||||
bool? isRegex,
|
||||
bool? isCaseSensitive,
|
||||
bool? isRemovedFromBuffer,
|
||||
bool? isTemporary,
|
||||
bool? autoDisable,
|
||||
int? invokeCount = 0,
|
||||
MUDAction? action,
|
||||
}) =>
|
||||
@@ -133,7 +136,7 @@ class Automation {
|
||||
isRegex: isRegex ?? this.isRegex,
|
||||
isCaseSensitive: isCaseSensitive ?? this.isCaseSensitive,
|
||||
isRemovedFromBuffer: isRemovedFromBuffer ?? this.isRemovedFromBuffer,
|
||||
isTemporary: isTemporary ?? this.isTemporary,
|
||||
autoDisable: autoDisable ?? this.autoDisable,
|
||||
invokeCount: invokeCount ?? this.invokeCount,
|
||||
action: action ?? this.action,
|
||||
);
|
||||
|
||||
@@ -101,7 +101,16 @@ class MUDProfile {
|
||||
Future<List<Alias>> loadAliases() async {
|
||||
debugPrint('MUDProfile.loadAliases: $id');
|
||||
final aliases = await ProfileStorage.listProfileFiles(id, 'aliases');
|
||||
return aliases.map((e) => Alias.fromJson(jsonDecode(e))).toList();
|
||||
final aliasFiles = <String>[];
|
||||
for (final alias in aliases) {
|
||||
debugPrint('MUDProfile.loadAliases: $id/aliases/$alias');
|
||||
final aliasFile =
|
||||
await ProfileStorage.readProfileFile(id, 'aliases/$alias');
|
||||
if (aliasFile != null) {
|
||||
aliasFiles.add(aliasFile);
|
||||
}
|
||||
}
|
||||
return aliasFiles.map((e) => Alias.fromJson(jsonDecode(e))).toList();
|
||||
}
|
||||
|
||||
Future<void> saveAlias(Alias alias) async {
|
||||
|
||||
@@ -11,7 +11,7 @@ class Trigger extends Automation {
|
||||
super.isRegex = false,
|
||||
super.isCaseSensitive = false,
|
||||
super.isRemovedFromBuffer = false,
|
||||
super.isTemporary = false,
|
||||
super.autoDisable = false,
|
||||
super.invokeCount = 0,
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ class Trigger extends Automation {
|
||||
isRegex: false,
|
||||
isCaseSensitive: false,
|
||||
isRemovedFromBuffer: false,
|
||||
isTemporary: false,
|
||||
autoDisable: false,
|
||||
invokeCount: 0,
|
||||
action: MUDAction.empty(),
|
||||
);
|
||||
@@ -34,7 +34,7 @@ class Trigger extends Automation {
|
||||
isRegex: json['isRegex'],
|
||||
isCaseSensitive: json['isCaseSensitive'],
|
||||
isRemovedFromBuffer: json['isRemovedFromBuffer'],
|
||||
isTemporary: json['isTemporary'],
|
||||
autoDisable: json['autoDisable'],
|
||||
invokeCount: json['invokeCount'],
|
||||
action: MUDAction.fromJson(json['action']),
|
||||
);
|
||||
@@ -47,7 +47,7 @@ class Trigger extends Automation {
|
||||
bool? isRegex,
|
||||
bool? isCaseSensitive,
|
||||
bool? isRemovedFromBuffer,
|
||||
bool? isTemporary,
|
||||
bool? autoDisable,
|
||||
int? invokeCount = 0,
|
||||
MUDAction? action,
|
||||
}) =>
|
||||
@@ -58,7 +58,7 @@ class Trigger extends Automation {
|
||||
isRegex: isRegex ?? this.isRegex,
|
||||
isCaseSensitive: isCaseSensitive ?? this.isCaseSensitive,
|
||||
isRemovedFromBuffer: isRemovedFromBuffer ?? this.isRemovedFromBuffer,
|
||||
isTemporary: isTemporary ?? this.isTemporary,
|
||||
autoDisable: autoDisable ?? this.autoDisable,
|
||||
invokeCount: invokeCount ?? this.invokeCount,
|
||||
action: action ?? this.action,
|
||||
);
|
||||
|
||||
@@ -10,10 +10,12 @@ class PlatformUtils {
|
||||
|
||||
static Future<String> getStorageBasePath() async {
|
||||
switch (Platform.operatingSystem) {
|
||||
case 'macos':
|
||||
case 'linux':
|
||||
final username = Platform.environment['USER'] ?? Platform.environment['USERNAME'];
|
||||
return '/Users/$username/.config/mudblock';
|
||||
case 'macos':
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
return dir.path;
|
||||
case 'windows':
|
||||
final username = Platform.environment['USERNAME'];
|
||||
return 'C:\\Users\\$username\\AppData\\Roaming\\mudblock';
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:localstore/localstore.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'platform_utils.dart';
|
||||
|
||||
class FileStorage {
|
||||
@deprecated
|
||||
static final Localstore _store = Localstore.instance;
|
||||
static late final String _base;
|
||||
static late final String base;
|
||||
|
||||
static Future<void> init() async {
|
||||
_base = await PlatformUtils.getStorageBasePath();
|
||||
debugPrint('Storage base: $_base');
|
||||
base = await PlatformUtils.getStorageBasePath();
|
||||
debugPrint('Storage base: $base');
|
||||
}
|
||||
|
||||
static Future<String?> readFile(String filename) async {
|
||||
@@ -21,7 +18,7 @@ class FileStorage {
|
||||
// final collection = path.dirname(filename);
|
||||
// filename = path.basename(filename);
|
||||
// return _store.collection(collection).doc(filename).get();
|
||||
final file = File(path.join(_base, filename));
|
||||
final file = File(path.join(base, filename));
|
||||
var exists = await file.exists();
|
||||
if (!exists) {
|
||||
debugPrint('File does not exist: $filename');
|
||||
@@ -30,14 +27,13 @@ class FileStorage {
|
||||
return file.readAsString();
|
||||
}
|
||||
|
||||
static Future<void> writeFile(
|
||||
String filename, String data) async {
|
||||
static Future<void> writeFile(String filename, String data) async {
|
||||
debugPrint(
|
||||
'Setting file: $filename, data: ${data.toString().length} bytes');
|
||||
// final collection = path.dirname(filename);
|
||||
// filename = path.basename(filename);
|
||||
// await _store.collection(collection).doc(filename).set(data);
|
||||
final file = File(path.join(_base, filename));
|
||||
final file = File(path.join(base, filename));
|
||||
await file.create(recursive: true);
|
||||
await file.writeAsString(data);
|
||||
}
|
||||
@@ -47,7 +43,7 @@ class FileStorage {
|
||||
// final collection = path.dirname(filename);
|
||||
// filename = path.basename(filename);
|
||||
// await _store.collection(collection).doc(filename).delete();
|
||||
final file = File(path.join(_base, filename));
|
||||
final file = File(path.join(base, filename));
|
||||
await file.delete();
|
||||
}
|
||||
|
||||
@@ -57,7 +53,7 @@ class FileStorage {
|
||||
// final docs = await _store.collection(collection).get();
|
||||
// debugPrint('Listing collection: $collection, ${docs?.length} docs');
|
||||
// return (docs ?? {}).cast<String, String>();
|
||||
final dir = Directory(path.join(_base, collection));
|
||||
final dir = Directory(path.join(base, collection));
|
||||
var exists = await dir.exists();
|
||||
if (!exists) {
|
||||
debugPrint('Directory does not exist: $collection');
|
||||
@@ -70,7 +66,7 @@ class FileStorage {
|
||||
static Future<void> deleteDirectory(String collection) async {
|
||||
debugPrint('Clearing collection: $collection');
|
||||
// await _store.collection(collection).delete();
|
||||
final dir = Directory(path.join(_base, collection));
|
||||
final dir = Directory(path.join(base, collection));
|
||||
await dir.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
@@ -95,7 +91,11 @@ class ProfileStorage {
|
||||
}
|
||||
|
||||
static Future<List<String>> listAllProfiles() async {
|
||||
return FileStorage.readDirectory('profiles');
|
||||
final list = await FileStorage.readDirectory('profiles');
|
||||
return list
|
||||
.where((f) =>
|
||||
Directory(path.join(FileStorage.base, 'profiles', f)).existsSync())
|
||||
.toList();
|
||||
}
|
||||
|
||||
static Future<List<String>> listProfileFiles(
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:localstore/localstore.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class FileStorage {
|
||||
static final Localstore _store = Localstore.instance;
|
||||
|
||||
static Future<Map<String, dynamic>?> readFile(String filename) async {
|
||||
debugPrint('Getting file: $filename');
|
||||
final collection = path.dirname(filename);
|
||||
filename = path.basename(filename);
|
||||
return _store.collection(collection).doc(filename).get();
|
||||
}
|
||||
|
||||
static Future<void> writeFile(
|
||||
String filename, Map<String, dynamic> data) async {
|
||||
debugPrint(
|
||||
'Setting file: $filename, data: ${data.toString().length} bytes');
|
||||
final collection = path.dirname(filename);
|
||||
filename = path.basename(filename);
|
||||
await _store.collection(collection).doc(filename).set(data);
|
||||
}
|
||||
|
||||
static Future<void> deleteFile(String filename) async {
|
||||
debugPrint('Deleting file: $filename');
|
||||
final collection = path.dirname(filename);
|
||||
filename = path.basename(filename);
|
||||
await _store.collection(collection).doc(filename).delete();
|
||||
}
|
||||
|
||||
static Future<Map<String, Map<String, dynamic>>> readDirectory(
|
||||
String collection,
|
||||
) async {
|
||||
final docs = await _store.collection(collection).get();
|
||||
debugPrint('Listing collection: $collection, ${docs?.length} docs');
|
||||
return (docs ?? {}).cast<String, Map<String, dynamic>>();
|
||||
}
|
||||
|
||||
static Future<void> deleteDirectory(String collection) async {
|
||||
debugPrint('Clearing collection: $collection');
|
||||
await _store.collection(collection).delete();
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileStorage {
|
||||
static Future<Map<String, dynamic>?> readProfileFile(
|
||||
String profile, String filename) async {
|
||||
return FileStorage.readFile('profiles/$profile/$filename');
|
||||
}
|
||||
|
||||
static Future<void> writeProfileFile(
|
||||
String profile, String filename, Map<String, dynamic> data) async {
|
||||
await FileStorage.writeFile('profiles/$profile/$filename', data);
|
||||
}
|
||||
|
||||
static Future<void> deleteProfile(String profile) async {
|
||||
await FileStorage.deleteDirectory('profiles/$profile');
|
||||
}
|
||||
|
||||
static Future<void> deleteProfileFile(String profile, String filename) async {
|
||||
await FileStorage.deleteFile('profiles/$profile/$filename');
|
||||
}
|
||||
|
||||
static Future<List<Map<String, dynamic>>> listAllProfiles() async {
|
||||
final list = await FileStorage.readDirectory('profiles');
|
||||
return list.values.toList();
|
||||
}
|
||||
|
||||
static Future<Map<String, Map<String, dynamic>>> listProfileFiles(
|
||||
String profile, [
|
||||
String? directory,
|
||||
]) async {
|
||||
return FileStorage.readDirectory(
|
||||
'profiles/$profile${directory != null ? '/$directory' : ''}');
|
||||
}
|
||||
|
||||
static Future<void> deleteAllProfiles() async {
|
||||
await FileStorage.deleteDirectory('profiles');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class GameStore extends ChangeNotifier {
|
||||
late StreamSubscription<List<int>> _decodedSub;
|
||||
late final List<MUDProfile> profiles = [];
|
||||
MUDProfile? _currentProfile;
|
||||
bool _clientReady = false;
|
||||
|
||||
MUDProfile get currentProfile => _currentProfile!;
|
||||
|
||||
Future<GameStore> init() async {
|
||||
@@ -90,7 +92,7 @@ class GameStore extends ChangeNotifier {
|
||||
bool showLine = true;
|
||||
final str = ColorUtils.stripColor(line);
|
||||
for (final trigger in triggers) {
|
||||
if (!trigger.enabled) {
|
||||
if (!trigger.isAvailable) {
|
||||
continue;
|
||||
}
|
||||
if (trigger.matches(str)) {
|
||||
@@ -98,8 +100,8 @@ class GameStore extends ChangeNotifier {
|
||||
if (trigger.isRemovedFromBuffer) {
|
||||
showLine = false;
|
||||
}
|
||||
if (trigger.isTemporary) {
|
||||
trigger.enabled = false;
|
||||
if (trigger.autoDisable) {
|
||||
trigger.tempDisabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,21 +112,22 @@ class GameStore extends ChangeNotifier {
|
||||
bool sendLine = true;
|
||||
final str = line;
|
||||
for (final alias in aliases) {
|
||||
if (!alias.enabled) {
|
||||
if (!alias.isAvailable) {
|
||||
continue;
|
||||
}
|
||||
if (alias.matches(str)) {
|
||||
alias.invokeEffect(this, str);
|
||||
sendLine = false;
|
||||
}
|
||||
if (alias.isTemporary) {
|
||||
alias.enabled = false;
|
||||
if (alias.autoDisable) {
|
||||
alias.tempDisabled = true;
|
||||
}
|
||||
}
|
||||
return sendLine;
|
||||
}
|
||||
|
||||
void _onConnect() {
|
||||
_clientReady = true;
|
||||
echo('Connected');
|
||||
}
|
||||
|
||||
@@ -231,6 +234,7 @@ class GameStore extends ChangeNotifier {
|
||||
}
|
||||
|
||||
void sendString(String line) {
|
||||
debugPrint('sending string: $line');
|
||||
_client.send(line + newline);
|
||||
}
|
||||
|
||||
@@ -253,6 +257,9 @@ class GameStore extends ChangeNotifier {
|
||||
}
|
||||
|
||||
void submitInput(String text) {
|
||||
if (!_clientReady || !_client.connected) {
|
||||
return;
|
||||
}
|
||||
echo(text);
|
||||
execute(text);
|
||||
scrollToEnd();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'core/platform_utils.dart';
|
||||
@@ -11,10 +10,10 @@ import 'core/store.dart';
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await getPrefs();
|
||||
final status = await Permission.manageExternalStorage.status;
|
||||
if (!status.isGranted) {
|
||||
await Permission.manageExternalStorage.request();
|
||||
}
|
||||
// final status = await Permission.manageExternalStorage.status;
|
||||
// if (!status.isGranted) {
|
||||
// await Permission.manageExternalStorage.request();
|
||||
// }
|
||||
await FileStorage.init();
|
||||
await gameStore.init();
|
||||
if (PlatformUtils.isDesktop) {
|
||||
|
||||
@@ -19,37 +19,49 @@ class AliasListPage extends StatelessWidget with GameStoreMixin {
|
||||
final aliases = store.aliases;
|
||||
return ListView.builder(
|
||||
itemCount: aliases.length,
|
||||
itemBuilder: (context, item) => ListTile(
|
||||
key: Key(aliases[item].id),
|
||||
title: Text(aliases[item].pattern),
|
||||
subtitle: Text(aliases[item].action.content),
|
||||
onTap: () async {
|
||||
final alias = await Navigator.pushNamed(
|
||||
context,
|
||||
Paths.alias,
|
||||
arguments: aliases[item],
|
||||
);
|
||||
if (alias != null) {
|
||||
await store.currentProfile.saveAlias(alias as Alias);
|
||||
await store.loadAliases();
|
||||
}
|
||||
},
|
||||
),
|
||||
itemBuilder: (context, item) {
|
||||
final alias = aliases[item];
|
||||
return ListTile(
|
||||
key: Key(alias.id),
|
||||
title: Text(alias.pattern),
|
||||
subtitle: Text(alias.action.content),
|
||||
leading: Switch.adaptive(
|
||||
value: alias.enabled,
|
||||
onChanged: (value) {
|
||||
alias.enabled = value;
|
||||
save(store, alias); },
|
||||
),
|
||||
onTap: () async {
|
||||
final updated = await Navigator.pushNamed(
|
||||
context,
|
||||
Paths.alias,
|
||||
arguments: alias,
|
||||
);
|
||||
if (updated != null) {
|
||||
await save(store, updated as Alias);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
child: const Icon(Icons.add),
|
||||
onPressed: () async {
|
||||
final store = storeOf(context);
|
||||
final store = storeOf(context);
|
||||
final alias = await Navigator.pushNamed(context, Paths.alias);
|
||||
if (alias != null) {
|
||||
await store.currentProfile.saveAlias(alias as Alias);
|
||||
await store.loadAliases();
|
||||
}
|
||||
save(store, alias as Alias); }
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> save(GameStore store, Alias updated) async {
|
||||
await store.currentProfile.saveAlias(updated);
|
||||
// TODO - stop re-loading all aliases, only replace the one that changed
|
||||
await store.loadAliases();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,14 @@ class _AliasPageState extends State<AliasPage> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Alias'),
|
||||
actions: [
|
||||
Switch.adaptive(
|
||||
value: alias.enabled,
|
||||
onChanged: (value) async {
|
||||
alias.enabled = value;
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
@@ -138,7 +146,7 @@ class _AliasPageState extends State<AliasPage> {
|
||||
},
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Remove From Buffer'),
|
||||
title: const Text('Remove From Output'),
|
||||
subtitle: const Text(
|
||||
'If checked, your input line will be removed from the buffer when it is matched.',
|
||||
),
|
||||
@@ -151,15 +159,15 @@ class _AliasPageState extends State<AliasPage> {
|
||||
},
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Temporary'),
|
||||
title: const Text('Auto Disable'),
|
||||
subtitle: const Text(
|
||||
'If checked, the alias will be disabled after it is matched once.',
|
||||
),
|
||||
value: alias.isTemporary,
|
||||
value: alias.autoDisable,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
alias.isTemporary = value ?? false;
|
||||
alias.autoDisable = value ?? false;
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
@@ -19,22 +19,30 @@ class TriggerListPage extends StatelessWidget with GameStoreMixin {
|
||||
final triggers = store.triggers;
|
||||
return ListView.builder(
|
||||
itemCount: triggers.length,
|
||||
itemBuilder: (context, item) => ListTile(
|
||||
key: Key(triggers[item].id),
|
||||
title: Text(triggers[item].pattern),
|
||||
subtitle: Text(triggers[item].action.content),
|
||||
onTap: () async {
|
||||
final trigger = await Navigator.pushNamed(
|
||||
context,
|
||||
Paths.trigger,
|
||||
arguments: triggers[item],
|
||||
);
|
||||
if (trigger != null) {
|
||||
await store.currentProfile.saveTrigger(trigger as Trigger);
|
||||
await store.loadTriggers();
|
||||
}
|
||||
},
|
||||
),
|
||||
itemBuilder: (context, item) {
|
||||
final trigger = triggers[item];
|
||||
return ListTile(
|
||||
key: Key(trigger.id),
|
||||
title: Text(trigger.pattern),
|
||||
subtitle: Text(trigger.action.content),
|
||||
leading: Switch.adaptive(
|
||||
value: trigger.enabled,
|
||||
onChanged: (value) {
|
||||
trigger.enabled = value;
|
||||
save(store, trigger); },
|
||||
),
|
||||
onTap: () async {
|
||||
final updated = await Navigator.pushNamed(
|
||||
context,
|
||||
Paths.trigger,
|
||||
arguments: trigger,
|
||||
);
|
||||
if (updated != null) {
|
||||
await save(store, updated as Trigger);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -44,12 +52,16 @@ class TriggerListPage extends StatelessWidget with GameStoreMixin {
|
||||
final store = storeOf(context);
|
||||
final trigger = await Navigator.pushNamed(context, Paths.trigger);
|
||||
if (trigger != null) {
|
||||
await store.currentProfile.saveTrigger(trigger as Trigger);
|
||||
await store.loadTriggers();
|
||||
}
|
||||
save(store, trigger as Trigger); }
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> save(GameStore store, Trigger updated) async {
|
||||
await store.currentProfile.saveTrigger(updated);
|
||||
// TODO - stop re-loading all triggers, only replace the one that changed
|
||||
await store.loadTriggers();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,14 @@ class _TriggerPageState extends State<TriggerPage> {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Trigger'),
|
||||
actions: [
|
||||
Switch.adaptive(
|
||||
value: trigger.enabled,
|
||||
onChanged: (value) {
|
||||
trigger.enabled = value;
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
body: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
@@ -138,7 +146,7 @@ class _TriggerPageState extends State<TriggerPage> {
|
||||
},
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Remove From Buffer'),
|
||||
title: const Text('Remove From Output'),
|
||||
subtitle: const Text(
|
||||
'If checked, the output line will be removed from the buffer when it is matched.',
|
||||
),
|
||||
@@ -151,15 +159,15 @@ class _TriggerPageState extends State<TriggerPage> {
|
||||
},
|
||||
),
|
||||
CheckboxListTile(
|
||||
title: const Text('Temporary'),
|
||||
title: const Text('Auto Disable'),
|
||||
subtitle: const Text(
|
||||
'If checked, the trigger will be disabled after it is matched once.',
|
||||
),
|
||||
value: trigger.isTemporary,
|
||||
value: trigger.autoDisable,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
trigger.isTemporary = value ?? false;
|
||||
trigger.autoDisable = value ?? false;
|
||||
});
|
||||
},
|
||||
),
|
||||
|
||||
12
pubspec.lock
12
pubspec.lock
@@ -93,10 +93,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: ctelnet
|
||||
sha256: "6e188a06fc683e04f217eaf8062919492447ce8cd2ddeabbf44992500f5025c3"
|
||||
sha256: "06cba141577de338adc9436ad733f33668224b0cfcf046f8edd58fcde09aeed2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.3"
|
||||
version: "0.1.4"
|
||||
cupertino_icons:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -184,14 +184,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
localstore:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: localstore
|
||||
sha256: "42a0afb7696cfab1b4bd7d08355b4ee01f975fd364553b28d51496eccaf11cce"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.5"
|
||||
lua_dardo:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -28,7 +28,7 @@ environment:
|
||||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
ctelnet: ^0.1.3
|
||||
ctelnet: ^0.1.4
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
@@ -40,7 +40,7 @@ dependencies:
|
||||
shared_preferences: ^2.2.1
|
||||
easy_debounce: ^2.0.3
|
||||
encrypt: ^5.0.3
|
||||
localstore: ^1.3.5
|
||||
# localstore: ^1.3.5
|
||||
path: ^1.8.3
|
||||
uuid: ^3.0.7
|
||||
meta: ^1.9.1
|
||||
|
||||
Reference in New Issue
Block a user