mirror of
https://gitlab.com/veilid/veilidchat.git
synced 2025-06-08 22:52:46 -04:00
ellet
This commit is contained in:
parent
711f82735e
commit
9291dc2b80
8 changed files with 196 additions and 88 deletions
|
@ -1,11 +1,16 @@
|
|||
import 'package:ansicolor/ansicolor.dart';
|
||||
import 'package:awesome_extensions/awesome_extensions.dart';
|
||||
import 'package:cool_dropdown/cool_dropdown.dart';
|
||||
import 'package:cool_dropdown/models/cool_dropdown_item.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_translate/flutter_translate.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:loggy/loggy.dart';
|
||||
import 'package:quickalert/quickalert.dart';
|
||||
import 'package:xterm/xterm.dart';
|
||||
|
||||
import '../tools/tools.dart';
|
||||
|
@ -28,60 +33,63 @@ class DeveloperPage extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class DeveloperPageState extends ConsumerState<DeveloperPage> {
|
||||
final terminalController = TerminalController();
|
||||
var logLevelDropDown = log.level.logLevel;
|
||||
final TextEditingController _debugCommandController = TextEditingController();
|
||||
final _terminalController = TerminalController();
|
||||
final _debugCommandController = TextEditingController();
|
||||
final _logLevelController = DropdownController(duration: 250.ms);
|
||||
final List<CoolDropdownItem<LogLevel>> _logLevelDropdownItems = [];
|
||||
var _logLevelDropDown = log.level.logLevel;
|
||||
var _showEllet = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// _scrollController = ScrollController(
|
||||
// onAttach: _handlePositionAttach,
|
||||
// onDetach: _handlePositionDetach,
|
||||
// );
|
||||
super.initState();
|
||||
terminalController.addListener(() {
|
||||
_terminalController.addListener(() {
|
||||
setState(() {});
|
||||
});
|
||||
|
||||
for (var i = 0; i < logLevels.length; i++) {
|
||||
_logLevelDropdownItems.add(CoolDropdownItem<LogLevel>(
|
||||
label: logLevelName(logLevels[i]),
|
||||
icon: Text(logLevelEmoji(logLevels[i])),
|
||||
value: logLevels[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// void _handleScrollChange() {
|
||||
// if (_isScrolling != _scrollController.position.isScrollingNotifier.value) {
|
||||
// _isScrolling = _scrollController.position.isScrollingNotifier.value;
|
||||
// _wantsBottom = _scrollController.position.pixels ==
|
||||
// _scrollController.position.maxScrollExtent;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void _handlePositionAttach(ScrollPosition position) {
|
||||
// // From here, add a listener to the given ScrollPosition.
|
||||
// // Here the isScrollingNotifier will be used to inform when scrolling starts
|
||||
// // and stops and change the AppBar's color in response.
|
||||
// position.isScrollingNotifier.addListener(_handleScrollChange);
|
||||
// }
|
||||
|
||||
// void _handlePositionDetach(ScrollPosition position) {
|
||||
// // From here, add a listener to the given ScrollPosition.
|
||||
// // Here the isScrollingNotifier will be used to inform when scrolling starts
|
||||
// // and stops and change the AppBar's color in response.
|
||||
// position.isScrollingNotifier.removeListener(_handleScrollChange);
|
||||
// }
|
||||
|
||||
// void _scrollToBottom() {
|
||||
// _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
|
||||
// _wantsBottom = true;
|
||||
// }
|
||||
void _debugOut(String out) {
|
||||
final pen = AnsiPen()..cyan(bold: true);
|
||||
final colorOut = pen(out);
|
||||
debugPrint(colorOut);
|
||||
globalDebugTerminal.write(colorOut.replaceAll('\n', '\r\n'));
|
||||
}
|
||||
|
||||
Future<void> _sendDebugCommand(String debugCommand) async {
|
||||
log.info('DEBUG >>>\n$debugCommand');
|
||||
final out = await Veilid.instance.debug(debugCommand);
|
||||
log.info('<<< DEBUG\n$out');
|
||||
if (debugCommand == 'ellet') {
|
||||
setState(() {
|
||||
_showEllet = !_showEllet;
|
||||
});
|
||||
return;
|
||||
}
|
||||
_debugOut('DEBUG >>>\n$debugCommand\n');
|
||||
try {
|
||||
final out = await Veilid.instance.debug(debugCommand);
|
||||
_debugOut('<<< DEBUG\n$out\n');
|
||||
} on Exception catch (e, st) {
|
||||
_debugOut('<<< ERROR\n$e\n<<< STACK\n$st');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> clear(BuildContext context) async {
|
||||
globalDebugTerminal.buffer.clear();
|
||||
if (context.mounted) {
|
||||
showInfoToast(context, translate('developer.cleared'));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> copySelection(BuildContext context) async {
|
||||
final selection = terminalController.selection;
|
||||
final selection = _terminalController.selection;
|
||||
if (selection != null) {
|
||||
final text = globalDebugTerminal.buffer.getText(selection);
|
||||
terminalController.clearSelection();
|
||||
_terminalController.clearSelection();
|
||||
await Clipboard.setData(ClipboardData(text: text));
|
||||
if (context.mounted) {
|
||||
showInfoToast(context, translate('developer.copied'));
|
||||
|
@ -92,7 +100,7 @@ class DeveloperPageState extends ConsumerState<DeveloperPage> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
//final textTheme = theme.textTheme;
|
||||
final textTheme = theme.textTheme;
|
||||
final scale = theme.extension<ScaleScheme>()!;
|
||||
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
@ -112,49 +120,99 @@ class DeveloperPageState extends ConsumerState<DeveloperPage> {
|
|||
icon: const Icon(Icons.copy),
|
||||
color: scale.primaryScale.text,
|
||||
disabledColor: scale.grayScale.subtleText,
|
||||
onPressed: terminalController.selection == null
|
||||
onPressed: _terminalController.selection == null
|
||||
? null
|
||||
: () async {
|
||||
await copySelection(context);
|
||||
}),
|
||||
DropdownMenu<LogLevel>(
|
||||
initialSelection: logLevelDropDown,
|
||||
onSelected: (value) {
|
||||
if (value != null) {
|
||||
setState(() {
|
||||
logLevelDropDown = value;
|
||||
//log. = value;
|
||||
setVeilidLogLevel(value);
|
||||
});
|
||||
}
|
||||
},
|
||||
dropdownMenuEntries: [
|
||||
DropdownMenuEntry<LogLevel>(
|
||||
value: LogLevel.error, label: translate('log.error')),
|
||||
DropdownMenuEntry<LogLevel>(
|
||||
value: LogLevel.warning, label: translate('log.warning')),
|
||||
DropdownMenuEntry<LogLevel>(
|
||||
value: LogLevel.info, label: translate('log.info')),
|
||||
DropdownMenuEntry<LogLevel>(
|
||||
value: LogLevel.debug, label: translate('log.debug')),
|
||||
DropdownMenuEntry<LogLevel>(
|
||||
value: traceLevel, label: translate('log.trace')),
|
||||
])
|
||||
IconButton(
|
||||
icon: const Icon(Icons.clear_all),
|
||||
color: scale.primaryScale.text,
|
||||
disabledColor: scale.grayScale.subtleText,
|
||||
onPressed: () async {
|
||||
await QuickAlert.show(
|
||||
context: context,
|
||||
type: QuickAlertType.confirm,
|
||||
title: translate('developer.are_you_sure_clear'),
|
||||
textColor: scale.primaryScale.text,
|
||||
confirmBtnColor: scale.primaryScale.elementBackground,
|
||||
backgroundColor: scale.primaryScale.subtleBackground,
|
||||
headerBackgroundColor: scale.primaryScale.background,
|
||||
confirmBtnText: translate('button.ok'),
|
||||
cancelBtnText: translate('button.cancel'),
|
||||
onConfirmBtnTap: () async {
|
||||
Navigator.pop(context);
|
||||
if (context.mounted) {
|
||||
await clear(context);
|
||||
}
|
||||
});
|
||||
}),
|
||||
CoolDropdown<LogLevel>(
|
||||
controller: _logLevelController,
|
||||
defaultItem: _logLevelDropdownItems
|
||||
.singleWhere((x) => x.value == _logLevelDropDown),
|
||||
onChange: (value) {
|
||||
setState(() {
|
||||
_logLevelDropDown = value;
|
||||
Loggy('').level = getLogOptions(value);
|
||||
setVeilidLogLevel(value);
|
||||
_logLevelController.close();
|
||||
});
|
||||
},
|
||||
resultOptions: ResultOptions(
|
||||
width: 64,
|
||||
height: 40,
|
||||
render: ResultRender.icon,
|
||||
textStyle: textTheme.labelMedium!
|
||||
.copyWith(color: scale.primaryScale.text),
|
||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||
openBoxDecoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
boxDecoration:
|
||||
BoxDecoration(color: scale.primaryScale.elementBackground),
|
||||
),
|
||||
dropdownOptions: DropdownOptions(
|
||||
width: 160,
|
||||
align: DropdownAlign.right,
|
||||
duration: 150.ms,
|
||||
color: scale.primaryScale.elementBackground,
|
||||
borderSide: BorderSide(color: scale.primaryScale.border),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||
),
|
||||
dropdownTriangleOptions: const DropdownTriangleOptions(
|
||||
align: DropdownTriangleAlign.right),
|
||||
dropdownItemOptions: DropdownItemOptions(
|
||||
selectedTextStyle: textTheme.labelMedium!
|
||||
.copyWith(color: scale.primaryScale.text),
|
||||
textStyle: textTheme.labelMedium!
|
||||
.copyWith(color: scale.primaryScale.text),
|
||||
selectedBoxDecoration: BoxDecoration(
|
||||
color: scale.primaryScale.activeElementBackground),
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
padding: const EdgeInsets.fromLTRB(8, 4, 8, 4),
|
||||
selectedPadding: const EdgeInsets.fromLTRB(8, 4, 8, 4)),
|
||||
dropdownList: _logLevelDropdownItems,
|
||||
)
|
||||
],
|
||||
title: Text(translate('developer.title')),
|
||||
title: Text(translate('developer.title'),
|
||||
style:
|
||||
textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.bold)),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: Column(children: [
|
||||
TerminalView(
|
||||
globalDebugTerminal,
|
||||
textStyle: kDefaultTerminalStyle,
|
||||
controller: terminalController,
|
||||
//autofocus: true,
|
||||
//backgroundOpacity: 0.9,
|
||||
onSecondaryTapDown: (details, offset) async {
|
||||
body: SafeArea(
|
||||
child: Column(children: [
|
||||
Stack(alignment: AlignmentDirectional.center, children: [
|
||||
Image.asset('assets/images/ellet.png'),
|
||||
TerminalView(globalDebugTerminal,
|
||||
textStyle: kDefaultTerminalStyle,
|
||||
controller: _terminalController,
|
||||
//autofocus: true,
|
||||
backgroundOpacity: _showEllet ? 0.75 : 1.0,
|
||||
onSecondaryTapDown: (details, offset) async {
|
||||
await copySelection(context);
|
||||
},
|
||||
).expanded(),
|
||||
})
|
||||
]).expanded(),
|
||||
TextField(
|
||||
controller: _debugCommandController,
|
||||
decoration: InputDecoration(
|
||||
|
@ -167,24 +225,32 @@ class DeveloperPageState extends ConsumerState<DeveloperPage> {
|
|||
hintText: translate('developer.command'),
|
||||
suffixIcon: IconButton(
|
||||
icon: const Icon(Icons.send),
|
||||
onPressed: () async {
|
||||
final debugCommand = _debugCommandController.text;
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
onPressed: _debugCommandController.text.isEmpty
|
||||
? null
|
||||
: () async {
|
||||
final debugCommand = _debugCommandController.text;
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
)),
|
||||
onChanged: (_) {
|
||||
setState(() => {});
|
||||
},
|
||||
onSubmitted: (debugCommand) async {
|
||||
_debugCommandController.clear();
|
||||
await _sendDebugCommand(debugCommand);
|
||||
},
|
||||
).paddingAll(4)
|
||||
]));
|
||||
])));
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(DiagnosticsProperty<TerminalController>(
|
||||
'terminalController', terminalController));
|
||||
properties
|
||||
..add(DiagnosticsProperty<TerminalController>(
|
||||
'terminalController', _terminalController))
|
||||
..add(
|
||||
DiagnosticsProperty<LogLevel>('logLevelDropDown', _logLevelDropDown));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue