mirror of
https://github.com/chenasraf/mudblock.git
synced 2026-05-18 01:48:57 +00:00
feat: triggers
This commit is contained in:
@@ -1,52 +1,15 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mudblock/core/consts.dart';
|
||||
|
||||
import 'parser/parser.dart';
|
||||
|
||||
class ColorUtils {
|
||||
static stripColor(String text) {
|
||||
return text
|
||||
// esc
|
||||
// .replaceAll(esc, '')
|
||||
// .replaceAll(r'^[', '')
|
||||
// color
|
||||
.replaceAll(RegExp(esc + colorPatternRaw), '')
|
||||
|
||||
// color
|
||||
// .replaceAll(RegExp(r'\[\d+m'), '')
|
||||
// esc
|
||||
// .replaceAll(String.fromCharCode(0xff), '');
|
||||
|
||||
//
|
||||
;
|
||||
return split(text).map((e) => e.text).join();
|
||||
}
|
||||
|
||||
static Iterable<ColoredText> split(String line) {
|
||||
// return line.split(RegExp(esc + colorPatternRaw)).map(
|
||||
// (raw) => ColoredText(
|
||||
// text: stripColor(raw),
|
||||
// color: 0,
|
||||
// raw: raw,
|
||||
// ),
|
||||
// );
|
||||
|
||||
try {
|
||||
final result = <ColoredText>[];
|
||||
// final tokenizer = Tokenizer(StringReader(line));
|
||||
// var lexer = Lexer(tokenizer);
|
||||
// final tokens = lexer.lex();
|
||||
// for (var i = 0; i < tokens.length; i++) {
|
||||
// final token = tokens[i];
|
||||
// result.add(
|
||||
// ColoredText(
|
||||
// text: token.text,
|
||||
// fgColor: token.fgColor,
|
||||
// bgColor: token.bgColor,
|
||||
// raw: token.text,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
|
||||
final tokens = ColorParser(line).parse();
|
||||
|
||||
for (final token in tokens) {
|
||||
@@ -91,7 +54,7 @@ class ColoredText extends ColorToken {
|
||||
return xterm256 ? (xtermColorMap[fgColor] ?? xtermColorMap[15]!) : (ansiFgColorMap[fgColor] ?? ansiFgColorMap[97]!);
|
||||
}
|
||||
|
||||
int get themedBgColor => ansiBgColorMap[bgColor] ?? ansiBgColorMap[40]!;
|
||||
int get themedBgColor => ansiBgColorMap[bgColor] ?? 0x00000000;
|
||||
}
|
||||
|
||||
/// map of ansi colors to flutter color ints
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
const newline = '\n';
|
||||
const cr = '\r';
|
||||
const lf = '\n';
|
||||
@@ -9,3 +11,4 @@ const colorPatternRaw = r'\[\d*m';
|
||||
const boldByte = 1;
|
||||
const italicByte = 3;
|
||||
const underlineByte = 4;
|
||||
final homeKey = GlobalKey(debugLabel: 'Home');
|
||||
|
||||
45
lib/core/features/action.dart
Normal file
45
lib/core/features/action.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../store.dart';
|
||||
|
||||
enum MUDActionTarget {
|
||||
world,
|
||||
execute,
|
||||
script,
|
||||
input,
|
||||
}
|
||||
|
||||
class MUDAction {
|
||||
final String content;
|
||||
final MUDActionTarget sendTo;
|
||||
const MUDAction(this.content, {this.sendTo = MUDActionTarget.world});
|
||||
|
||||
void invoke(BuildContext context, List<String> matches) {
|
||||
final store = Provider.of<GameStore>(context, listen: false);
|
||||
debugPrint('MUDAction.invoke: ${this.content}, $matches');
|
||||
var content = this.content;
|
||||
for (var i = 0; i < matches.length; i++) {
|
||||
content = content.replaceAll('%$i', matches[i]);
|
||||
}
|
||||
debugPrint('MUDAction.invoking: $content');
|
||||
|
||||
switch (sendTo) {
|
||||
case MUDActionTarget.world:
|
||||
debugPrint('ActionSendTo.world: $content');
|
||||
store.send(content);
|
||||
break;
|
||||
case MUDActionTarget.execute:
|
||||
debugPrint('ActionSendTo.execute: $content');
|
||||
break;
|
||||
case MUDActionTarget.script:
|
||||
debugPrint('ActionSendTo.script: $content');
|
||||
break;
|
||||
case MUDActionTarget.input:
|
||||
debugPrint('ActionSendTo.input: $content');
|
||||
store.setInput(content);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
14
lib/core/features/profile.dart
Normal file
14
lib/core/features/profile.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
class MUDProfile {
|
||||
String id;
|
||||
String name;
|
||||
String host;
|
||||
int port;
|
||||
|
||||
MUDProfile({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.host,
|
||||
required this.port,
|
||||
});
|
||||
}
|
||||
|
||||
68
lib/core/features/trigger.dart
Normal file
68
lib/core/features/trigger.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'action.dart';
|
||||
|
||||
class Trigger {
|
||||
String id;
|
||||
String pattern;
|
||||
bool isRegex;
|
||||
bool isCaseSensitive;
|
||||
// bool isMultiLine;
|
||||
bool isRemovedFromBuffer;
|
||||
bool isTemporary;
|
||||
int invokeCount = 0;
|
||||
MUDAction action;
|
||||
|
||||
Trigger({
|
||||
required this.id,
|
||||
required this.pattern,
|
||||
required this.action,
|
||||
this.isRegex = false,
|
||||
this.isCaseSensitive = false,
|
||||
// required this.isMultiLine,
|
||||
this.isRemovedFromBuffer = false,
|
||||
this.isTemporary = false,
|
||||
});
|
||||
|
||||
bool matches(String line) {
|
||||
if (isRegex) {
|
||||
final regex = RegExp(pattern, caseSensitive: isCaseSensitive);
|
||||
return regex.hasMatch(line);
|
||||
} else {
|
||||
if (isCaseSensitive) {
|
||||
return line.toLowerCase().contains(pattern.toLowerCase());
|
||||
}
|
||||
return line.contains(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
void invokeEffect(BuildContext context, String line) {
|
||||
invokeCount++;
|
||||
action.invoke(context, allMatches(line));
|
||||
}
|
||||
|
||||
List<String> allMatches(str) {
|
||||
if (!matches(str)) {
|
||||
return [];
|
||||
}
|
||||
if (isRegex) {
|
||||
final regex = RegExp(pattern, caseSensitive: isCaseSensitive);
|
||||
debugPrint('allMatches: ${regex.allMatches(str).map((m) => m.group(1)!).toList()}');
|
||||
return regex.allMatches(str).map((m) => m.group(0)!).toList();
|
||||
} else {
|
||||
final input = isCaseSensitive ? str.toLowerCase() : str;
|
||||
final compare = isCaseSensitive ? pattern.toLowerCase() : pattern;
|
||||
final matches = <String>[str];
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
final index = input.indexOf(compare, i);
|
||||
if (index == -1) {
|
||||
break;
|
||||
}
|
||||
matches.add(str.substring(index, index + compare.length));
|
||||
i = index + compare.length;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
lib/core/storage/shared_prefs.dart
Normal file
7
lib/core/storage/shared_prefs.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
late final SharedPreferences prefs;
|
||||
Future<SharedPreferences> getPrefs() async {
|
||||
return prefs = await SharedPreferences.getInstance();
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export './storage_macos.dart' if (dart.library.io) './storage_io.dart' if (dart.library.html) './storage_web.dart';
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
abstract class IFileStorage {
|
||||
Future<String> read(String path);
|
||||
Future<void> write(String path, String value);
|
||||
Future<void> delete(String path);
|
||||
Future<bool> exists(String path);
|
||||
Future<List<String>> list(String path);
|
||||
Future<void> createDirectory(String path);
|
||||
Future<void> deleteDirectory(String path);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:mudblock/core/storage/storage_base.dart';
|
||||
|
||||
class FileStorage implements IFileStorage {
|
||||
@override
|
||||
Future<void> createDirectory(String path) => Directory(path).create(recursive: true);
|
||||
|
||||
@override
|
||||
Future<void> delete(String path) => File(path).delete();
|
||||
|
||||
@override
|
||||
Future<void> deleteDirectory(String path) => Directory(path).delete(recursive: true);
|
||||
|
||||
@override
|
||||
Future<bool> exists(String path) async {
|
||||
final type = await FileSystemEntity.type(path);
|
||||
return type != FileSystemEntityType.notFound;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> list(String path) {
|
||||
return Directory(path)
|
||||
.list()
|
||||
.map((e) => e.path.substring(
|
||||
e.path.lastIndexOf(Platform.pathSeparator) + 1,
|
||||
))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> read(String path) => File(path).readAsString();
|
||||
|
||||
@override
|
||||
Future<void> write(String path, String value) => File(path).writeAsString(value);
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import 'package:mudblock/core/storage/storage_base.dart';
|
||||
|
||||
class FileStorage implements IFileStorage {
|
||||
@override
|
||||
Future<void> createDirectory(String path) {
|
||||
// TODO: implement createDirectory
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> delete(String path) {
|
||||
// TODO: implement delete
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> deleteDirectory(String path) {
|
||||
// TODO: implement deleteDirectory
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> exists(String path) {
|
||||
// TODO: implement exists
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> list(String path) {
|
||||
// TODO: implement list
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String> read(String path) {
|
||||
// TODO: implement read
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> write(String path, String value) {
|
||||
// TODO: implement write
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:ctelnet/ctelnet.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../pages/home_page.dart';
|
||||
import 'color_utils.dart';
|
||||
import 'consts.dart';
|
||||
import 'features/action.dart';
|
||||
import 'features/profile.dart';
|
||||
import 'features/trigger.dart';
|
||||
|
||||
const maxLines = 2000;
|
||||
|
||||
@@ -20,24 +24,68 @@ class GameStore extends ChangeNotifier {
|
||||
final FocusNode inputFocus = FocusNode();
|
||||
bool isCompressed = false;
|
||||
final ZLibDecoder decoder = ZLibDecoder();
|
||||
final List<Trigger> triggers = [];
|
||||
|
||||
MUDProfile? _currentProfile;
|
||||
MUDProfile get currentProfile => _currentProfile!;
|
||||
|
||||
GameStore init() {
|
||||
debugPrint('GameStore.init');
|
||||
addLine('Connecting...');
|
||||
final profiles = [
|
||||
MUDProfile(id: 'local', name: 'Local', host: 'localhost', port: 4000),
|
||||
MUDProfile(id: 'smud', name: 'SimpleMUD', host: 'smud.ourmmo.com', port: 3000),
|
||||
MUDProfile(id: 'aardwolf', name: 'Aardwolf', host: 'aardmud.org', port: 23),
|
||||
MUDProfile(id: 'batmud', name: 'BatMUD', host: 'batmud.bat.org', port: 23),
|
||||
MUDProfile(id: 'dune', name: 'Dune', host: 'dune.servint.com', port: 6789),
|
||||
];
|
||||
_currentProfile = profiles[1];
|
||||
_client = CTelnetClient(
|
||||
// host: 'aardmud.org',
|
||||
// port: 23,
|
||||
host: 'smud.ourmmo.com',
|
||||
port: 3000,
|
||||
host: currentProfile.host,
|
||||
port: currentProfile.port,
|
||||
onConnect: _onConnect,
|
||||
onDisconnect: onDisconnect,
|
||||
onData: onData,
|
||||
onError: onError,
|
||||
);
|
||||
scrollController = ScrollController();
|
||||
loadTriggers();
|
||||
_client.connect();
|
||||
return this;
|
||||
}
|
||||
|
||||
void loadTriggers() {
|
||||
triggers.clear();
|
||||
triggers.add(
|
||||
Trigger(
|
||||
id: 'test',
|
||||
pattern: r'^You are in the ([^.]+)\. This is the ([^.]+)\.',
|
||||
action: const MUDAction('Hello, %1, the %2!', sendTo: MUDActionTarget.world),
|
||||
isRegex: true,
|
||||
),
|
||||
);
|
||||
debugPrint('triggers: ${triggers.length}');
|
||||
}
|
||||
|
||||
bool processTriggers(BuildContext context, String line) {
|
||||
bool showLine = true;
|
||||
final str = ColorUtils.stripColor(line);
|
||||
debugPrint('Processing triggers for: $str');
|
||||
for (final trigger in triggers) {
|
||||
debugPrint('trigger: ${trigger.pattern}');
|
||||
if (trigger.matches(str)) {
|
||||
debugPrint('trigger matches: ${trigger.pattern}');
|
||||
trigger.invokeEffect(context, str);
|
||||
if (trigger.isRemovedFromBuffer) {
|
||||
debugPrint('line is removed from buffer');
|
||||
showLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
debugPrint('');
|
||||
return showLine;
|
||||
}
|
||||
|
||||
void _onConnect() {
|
||||
addLine('Connected');
|
||||
}
|
||||
@@ -53,7 +101,8 @@ class GameStore extends ChangeNotifier {
|
||||
|
||||
void onData(Message data) {
|
||||
try {
|
||||
debugPrint('text: ${data.text}');
|
||||
final home = homeKey.currentState as HomePageState;
|
||||
debugPrint('text: ${data.text}');
|
||||
debugPrint('subnegotiations: ${data.data.subnegotiations}');
|
||||
|
||||
if (mccpEnabled && isCompressed) {
|
||||
@@ -65,7 +114,7 @@ class GameStore extends ChangeNotifier {
|
||||
|
||||
final pattern = RegExp("($cr$lf)|($lf$cr)|$cr|$lf");
|
||||
for (final line in data.text.trimRight().split(pattern)) {
|
||||
onLine(line);
|
||||
onLine(home.context, line);
|
||||
}
|
||||
} catch (e, stack) {
|
||||
debugPrint('error: $e$newline$stack');
|
||||
@@ -116,8 +165,11 @@ class GameStore extends ChangeNotifier {
|
||||
onError('Error: $error');
|
||||
}
|
||||
|
||||
void onLine(String line) {
|
||||
addLine(line);
|
||||
void onLine(BuildContext context, String line) {
|
||||
var showLine = processTriggers(context, line);
|
||||
if (showLine) {
|
||||
addLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
List<String> get lines => _lines.sublist(max(0, _lines.length - maxLines), _lines.length);
|
||||
@@ -162,6 +214,10 @@ class GameStore extends ChangeNotifier {
|
||||
});
|
||||
}
|
||||
|
||||
void unselectInput() {
|
||||
input.selection = const TextSelection.collapsed(offset: -1);
|
||||
}
|
||||
|
||||
void selectInput() {
|
||||
input.selection = TextSelection(
|
||||
baseOffset: 0,
|
||||
@@ -170,6 +226,11 @@ class GameStore extends ChangeNotifier {
|
||||
inputFocus.previousFocus();
|
||||
inputFocus.requestFocus();
|
||||
}
|
||||
|
||||
void setInput(String content) {
|
||||
input.text = content;
|
||||
selectInput();
|
||||
}
|
||||
}
|
||||
|
||||
mixin GameStoreMixin<T extends StatefulWidget> on State<T> {
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mudblock/core/consts.dart';
|
||||
import 'package:mudblock/core/store.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
import 'core/storage/shared_prefs.dart';
|
||||
import 'pages/home_page.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await getPrefs();
|
||||
await windowManager.ensureInitialized();
|
||||
|
||||
WindowOptions windowOptions = const WindowOptions(
|
||||
size: Size(1000, 900),
|
||||
center: true,
|
||||
final w = prefs.getInt('windowWidth') ?? 1000;
|
||||
final h = prefs.getInt('windowHeight') ?? 900;
|
||||
final size = Size(w.toDouble(), h.toDouble());
|
||||
|
||||
WindowOptions windowOptions = WindowOptions(
|
||||
size: size,
|
||||
backgroundColor: Colors.transparent,
|
||||
skipTaskbar: false,
|
||||
titleBarStyle: TitleBarStyle.hidden,
|
||||
@@ -42,7 +48,7 @@ class MyApp extends StatelessWidget {
|
||||
body: ChangeNotifierProvider(
|
||||
create: (_) => GameStore().init(),
|
||||
builder: (context, snapshot) {
|
||||
return const HomePage();
|
||||
return HomePage(key: homeKey);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mudblock/core/color_utils.dart';
|
||||
import 'package:mudblock/core/storage/shared_prefs.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:window_manager/window_manager.dart';
|
||||
|
||||
@@ -12,10 +14,10 @@ class HomePage extends StatefulWidget {
|
||||
const HomePage({super.key});
|
||||
|
||||
@override
|
||||
State<HomePage> createState() => _HomePageState();
|
||||
State<HomePage> createState() => HomePageState();
|
||||
}
|
||||
|
||||
class _HomePageState extends State<HomePage> with GameStoreMixin, WindowListener {
|
||||
class HomePageState extends State<HomePage> with GameStoreMixin, WindowListener {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -34,7 +36,6 @@ class _HomePageState extends State<HomePage> with GameStoreMixin, WindowListener
|
||||
color: Colors.white,
|
||||
fontFamily: 'Menlo',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1,
|
||||
);
|
||||
final inputStyle = consoleStyle.copyWith(color: Colors.grey);
|
||||
@@ -56,35 +57,38 @@ class _HomePageState extends State<HomePage> with GameStoreMixin, WindowListener
|
||||
selectionHandleColor: Colors.white,
|
||||
),
|
||||
),
|
||||
child: SingleChildScrollView(
|
||||
controller: store.scrollController,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SelectableText.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
for (final line in lines) ...[
|
||||
for (final segment in ColorUtils.split(line))
|
||||
TextSpan(
|
||||
text: segment.text,
|
||||
style: consoleStyle.copyWith(
|
||||
color: Color(segment.themedFgColor),
|
||||
backgroundColor: Color(segment.themedBgColor),
|
||||
fontWeight: segment.bold ? FontWeight.w800 : null,
|
||||
fontStyle: segment.italic ? FontStyle.italic : null,
|
||||
decoration: segment.underline ? TextDecoration.underline : null,
|
||||
child: GestureDetector(
|
||||
onTap: store.selectInput,
|
||||
child: SingleChildScrollView(
|
||||
controller: store.scrollController,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: SelectableText.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
for (final line in lines) ...[
|
||||
for (final segment in ColorUtils.split(line))
|
||||
TextSpan(
|
||||
text: segment.text,
|
||||
style: consoleStyle.copyWith(
|
||||
color: Color(segment.themedFgColor),
|
||||
backgroundColor: Color(segment.themedBgColor),
|
||||
fontWeight: segment.bold ? FontWeight.w800 : null,
|
||||
fontStyle: segment.italic ? FontStyle.italic : null,
|
||||
decoration: segment.underline ? TextDecoration.underline : null,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: newline,
|
||||
style: consoleStyle, // .copyWith(fontSize: 1),
|
||||
),
|
||||
TextSpan(
|
||||
text: newline,
|
||||
style: consoleStyle.copyWith(fontSize: 1),
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
enableInteractiveSelection: true,
|
||||
selectionWidthStyle: BoxWidthStyle.tight,
|
||||
selectionHeightStyle: BoxHeightStyle.max,
|
||||
),
|
||||
enableInteractiveSelection: true,
|
||||
selectionWidthStyle: BoxWidthStyle.tight,
|
||||
selectionHeightStyle: BoxHeightStyle.max,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -95,30 +99,54 @@ class _HomePageState extends State<HomePage> with GameStoreMixin, WindowListener
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
autofocus: true,
|
||||
focusNode: store.inputFocus,
|
||||
controller: store.input,
|
||||
onSubmitted: (text) {
|
||||
store.submitInput(text);
|
||||
},
|
||||
onTap: store.selectInput,
|
||||
style: consoleStyle.copyWith(color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter command',
|
||||
border: const OutlineInputBorder(),
|
||||
hintStyle: inputStyle,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
autofocus: true,
|
||||
focusNode: store.inputFocus,
|
||||
controller: store.input,
|
||||
onSubmitted: store.submitInput,
|
||||
onTap: store.selectInput,
|
||||
style: consoleStyle.copyWith(color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter command',
|
||||
border: const OutlineInputBorder(),
|
||||
hintStyle: inputStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.bug_report),
|
||||
onPressed: store.loadTriggers,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
onWindowBlur() {
|
||||
debugPrint("Window blurred");
|
||||
store.unselectInput();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowFocus() {
|
||||
debugPrint("Window focused");
|
||||
store.selectInput();
|
||||
}
|
||||
|
||||
@override
|
||||
void onWindowResize() async {
|
||||
EasyDebounce.debounce('windowResize', const Duration(milliseconds: 500), () async {
|
||||
final size = await windowManager.getSize();
|
||||
debugPrint("Window resized to $size");
|
||||
prefs.setInt('windowWidth', size.width.toInt());
|
||||
prefs.setInt('windowHeight', size.height.toInt());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import screen_retriever
|
||||
import shared_preferences_foundation
|
||||
import window_manager
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
|
||||
}
|
||||
|
||||
@@ -2,12 +2,16 @@ PODS:
|
||||
- FlutterMacOS (1.0.0)
|
||||
- screen_retriever (0.0.1):
|
||||
- FlutterMacOS
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- window_manager (0.2.0):
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -15,12 +19,15 @@ EXTERNAL SOURCES:
|
||||
:path: Flutter/ephemeral
|
||||
screen_retriever:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
window_manager:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8
|
||||
|
||||
PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
|
||||
|
||||
135
pubspec.lock
135
pubspec.lock
@@ -80,6 +80,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
easy_debounce:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: easy_debounce
|
||||
sha256: f082609cfb8f37defb9e37fc28bc978c6712dedf08d4c5a26f820fa10165a236
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -88,6 +96,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -114,6 +130,11 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -162,6 +183,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.6"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -178,6 +239,62 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.9"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: b7f41bad7e521d205998772545de63ff4e6c97714775902c199353f8bf1511ac
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: c2eb5bf57a2fe9ad6988121609e47d3e07bb3bdca5b6f8444e4cf302428a128a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: f763a101313bd3be87edffe0560037500967de9c394a714cd598d945517f694f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
@@ -247,6 +364,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4-beta"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: c97defd418eef4ec88c0d1652cdce84b9f7b63dd7198e266d06ac1710d527067
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.8"
|
||||
window_manager:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -255,6 +380,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.6"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
sdks:
|
||||
dart: ">=3.1.2 <4.0.0"
|
||||
flutter: ">=3.3.0"
|
||||
flutter: ">=3.7.0"
|
||||
|
||||
@@ -38,6 +38,8 @@ dependencies:
|
||||
cupertino_icons: ^1.0.2
|
||||
provider: ^6.0.5
|
||||
window_manager: ^0.3.6
|
||||
shared_preferences: ^2.2.1
|
||||
easy_debounce: ^2.0.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user