MobileApp/lib/boxes/console.dart

231 lines
6.8 KiB
Dart
Raw Permalink Normal View History

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:ju_rc_app/lib/boxes.dart';
import 'package:ju_rc_app/lib/serial.dart';
class SerialBox extends JuBox {
const SerialBox({super.key});
@override
State<StatefulWidget> createState() => _SerialBoxState();
}
class _SerialBoxState extends State<SerialBox> {
USerial serial = getSerial();
final ScrollController _controller = ScrollController();
@override
void initState() {
super.initState();
serial.listen(serialListen);
}
@override
void dispose() {
serial.removeListen(serialListen);
super.dispose();
}
void serialListen(String line, SerialCommand? _) {
setState(() {
//change serial lines
_controller.jumpTo(_controller.position.maxScrollExtent);
});
}
@override
Widget build(BuildContext context) => GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const SerialDetailPage()),
);
},
child: ListView(
controller: _controller,
shrinkWrap: false,
physics: const NeverScrollableScrollPhysics(),
children: serial.lines
.last(20)
.map(
(e) => Row(
children: [
Padding(
padding: const EdgeInsets.all(0.0),
child: Icon(e.$1 != SerialMessageType.received
? Icons.arrow_left
: Icons.arrow_right),
),
Expanded(
child: Text(
e.$3,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
)
.toList(),
));
}
class SerialDetailPage extends StatefulWidget {
const SerialDetailPage({super.key});
@override
State<StatefulWidget> createState() => _SerialDetailPageState();
}
class _SerialDetailPageState extends State<SerialDetailPage> {
final ScrollController _controller = ScrollController();
USerial serial = getSerial();
bool jump = true;
final List<String> _messages = [];
int messageIndex = 0;
final TextEditingController _textController = TextEditingController();
FocusNode fc = FocusNode();
FocusNode _textFocus = FocusNode();
@override
void initState() {
super.initState();
serial.listen(serialListen);
fc.requestFocus();
}
@override
void dispose() {
serial.removeListen(serialListen);
_textController.dispose();
_controller.dispose();
super.dispose();
}
void serialListen(String line, SerialCommand? _) {
if (!jump) return;
setState(() {
//change serial lines
_controller.jumpTo(_controller.position.maxScrollExtent);
});
}
void submit() {
if (_textController.text.isNotEmpty) {
setState(() {
serial.sprintln(_textController.text);
_messages.add(_textController.text);
messageIndex = _messages.length;
2023-09-18 20:25:23 +02:00
_textController.text = "";
});
_textFocus.requestFocus();
}
}
void _handleKeyEvent(RawKeyEvent event) {
if (event.runtimeType.toString() == 'RawKeyDownEvent') {
if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
if (messageIndex > 0) {
2023-09-18 20:25:23 +02:00
messageIndex--;
Future.delayed(const Duration(microseconds: 10), () {
_textController.text = _messages[messageIndex];
2023-09-18 20:25:23 +02:00
_textController.selection =
TextSelection.collapsed(offset: _textController.text.length);
});
}
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
if (messageIndex >= _messages.length - 1) {
setState(() {
messageIndex = _messages.length;
2023-09-18 20:25:23 +02:00
Future.delayed(const Duration(microseconds: 10), () {
_textController.text = "";
_textController.selection = const TextSelection.collapsed(offset: 0);
});
});
} else {
2023-09-18 20:25:23 +02:00
messageIndex++;
Future.delayed(const Duration(microseconds: 10), () {
_textController.text = _messages[messageIndex];
2023-09-18 20:25:23 +02:00
_textController.selection =
TextSelection.collapsed(offset: _textController.text.length);
});
}
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text(
"Serial Console",
style: TextStyle(
fontSize: 16,
),
),
toolbarHeight: 40,
),
body: Column(
children: [
Expanded(
child: ListView(
controller: _controller,
children: serial.lines.items
.map(
(e) => Row(
children: [
Text(DateFormat('HH:mm:ss.S').format(e.$2)),
Padding(
padding: const EdgeInsets.all(0.0),
child: Icon(e.$1 != SerialMessageType.received
? Icons.arrow_left
: Icons.arrow_right),
),
Expanded(
child: Text(
e.$3,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
)
.toList(),
)),
RawKeyboardListener(
focusNode: fc,
autofocus: true,
onKey: _handleKeyEvent,
child: Padding(
padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0),
child: Row(
children: <Widget>[
Expanded(
child: TextField(
focusNode: _textFocus,
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Enter a Command',
),
onSubmitted: (_) {
submit();
},
),
),
IconButton(
icon: const Icon(Icons.send),
onPressed: submit,
),
],
),
))
],
));
}
}