Merge branch 'debugging' into 'main'

Developer Console Support

See merge request veilid/veilidchat!14
This commit is contained in:
Christien Rioux 2023-10-10 02:13:44 +00:00
commit eae1388e4d
41 changed files with 435 additions and 36 deletions

View File

@ -62,6 +62,7 @@ android {
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
} }
namespace 'com.veilid.veilidchat'
} }
flutter { flutter {

View File

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.veilid.veilidchat">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.

View File

@ -1,9 +1,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.veilid.veilidchat">
<application <application
android:label="VeilidChat" android:label="VeilidChat"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_rounded">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_round"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#FFFFFFFF</color>
</resources>

View File

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.veilid.veilidchat">
<!-- The INTERNET permission is required for development. Specifically, <!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc. to allow setting breakpoints, to provide hot reload, etc.

View File

@ -6,7 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.0' classpath 'com.android.tools.build:gradle:7.4.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-7.3.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

Binary file not shown.

Binary file not shown.

View File

@ -159,5 +159,19 @@
"titlebar": "Settings", "titlebar": "Settings",
"color_theme": "Color Theme", "color_theme": "Color Theme",
"brightness_mode": "Brightness Mode" "brightness_mode": "Brightness Mode"
},
"developer": {
"title": "Developer Logs",
"command": "Command",
"copied": "Selection copied",
"cleared": "Logs cleared",
"are_you_sure_clear": "Are you sure you want to clear the logs?"
},
"log": {
"error": "Error",
"warning": "Warning",
"info": "Info",
"debug": "Debug",
"trace": "Trace"
} }
} }

Binary file not shown.

View File

@ -20,7 +20,6 @@ class VeilidChatApp extends ConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final router = ref.watch(routerProvider); final router = ref.watch(routerProvider);
final localizationDelegate = LocalizedApp.of(context).delegate; final localizationDelegate = LocalizedApp.of(context).delegate;
return ThemeProvider( return ThemeProvider(

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui';
import 'package:awesome_extensions/awesome_extensions.dart'; import 'package:awesome_extensions/awesome_extensions.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -83,10 +84,16 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
Future<void> Function({required Uint8List inviteData}) Future<void> Function({required Uint8List inviteData})
validateInviteData) { validateInviteData) {
final theme = Theme.of(context); final theme = Theme.of(context);
//final scale = theme.extension<ScaleScheme>()!; final scale = theme.extension<ScaleScheme>()!;
final textTheme = theme.textTheme; //final textTheme = theme.textTheme;
//final height = MediaQuery.of(context).size.height; //final height = MediaQuery.of(context).size.height;
final monoStyle = TextStyle(
fontFamily: 'Source Code Pro',
fontSize: 11,
color: scale.primaryScale.text,
);
return Column(mainAxisSize: MainAxisSize.min, children: [ return Column(mainAxisSize: MainAxisSize.min, children: [
Text( Text(
translate('paste_invite_dialog.paste_invite_here'), translate('paste_invite_dialog.paste_invite_here'),
@ -97,8 +104,7 @@ class PasteInviteDialogState extends ConsumerState<PasteInviteDialog> {
enabled: !dialogState.isValidating, enabled: !dialogState.isValidating,
onChanged: (text) async => onChanged: (text) async =>
_onPasteChanged(text, validateInviteData), _onPasteChanged(text, validateInviteData),
style: textTheme.labelSmall! style: monoStyle,
.copyWith(fontFamily: 'Victor Mono', fontSize: 11),
keyboardType: TextInputType.multiline, keyboardType: TextInputType.multiline,
maxLines: null, maxLines: null,
controller: _pasteTextController, controller: _pasteTextController,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:signal_strength_indicator/signal_strength_indicator.dart'; import 'package:signal_strength_indicator/signal_strength_indicator.dart';
import 'package:go_router/go_router.dart';
import '../providers/connection_state.dart'; import '../providers/connection_state.dart';
import '../tools/tools.dart'; import '../tools/tools.dart';
@ -48,13 +49,17 @@ class SignalStrengthMeterWidget extends ConsumerWidget {
} }
inactiveColor = scale.grayScale.subtleText; inactiveColor = scale.grayScale.subtleText;
return SignalStrengthIndicator.bars( return GestureDetector(
value: value, onLongPress: () async {
activeColor: color, await context.push('/developer');
inactiveColor: inactiveColor, },
size: iconSize, child: SignalStrengthIndicator.bars(
barCount: 4, value: value,
spacing: 1, activeColor: color,
); inactiveColor: inactiveColor,
size: iconSize,
barCount: 4,
spacing: 1,
));
} }
} }

View File

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_translate/flutter_translate.dart'; import 'package:flutter_translate/flutter_translate.dart';
import 'package:intl/date_symbol_data_local.dart';
import 'app.dart'; import 'app.dart';
import 'providers/window_control.dart'; import 'providers/window_control.dart';
@ -22,6 +24,9 @@ void main() async {
debugPrint('VeilidChat PID: $pid'); debugPrint('VeilidChat PID: $pid');
} }
// Ansi colors
ansiColorDisabled = false;
// Logs // Logs
initLoggy(); initLoggy();
@ -36,13 +41,18 @@ void main() async {
// Make localization delegate // Make localization delegate
final delegate = await LocalizationDelegate.create( final delegate = await LocalizationDelegate.create(
fallbackLocale: 'en_US', supportedLocales: ['en_US']); fallbackLocale: 'en_US', supportedLocales: ['en_US']);
await initializeDateFormatting();
// Start up Veilid and Veilid processor in the background // Start up Veilid and Veilid processor in the background
unawaited(initializeVeilid()); unawaited(initializeVeilid());
// Run the app // Run the app
// Hot reloads will only restart this part, not Veilid // Hot reloads will only restart this part, not Veilid
runApp(ProviderScope( runZonedGuarded(() {
observers: const [StateLogger()], runApp(ProviderScope(
child: LocalizedApp(delegate, VeilidChatApp(theme: initTheme)))); observers: const [StateLogger()],
child: LocalizedApp(delegate, VeilidChatApp(theme: initTheme))));
}, (error, stackTrace) {
log.error('Dart Runtime: {$error}\n{$stackTrace}');
});
} }

256
lib/pages/developer.dart Normal file
View File

@ -0,0 +1,256 @@
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';
import '../veilid_support/veilid_support.dart';
final globalDebugTerminal = Terminal(
maxLines: 50000,
);
const kDefaultTerminalStyle = TerminalStyle(
fontSize: 11,
// height: 1.2,
fontFamily: 'Source Code Pro');
class DeveloperPage extends ConsumerStatefulWidget {
const DeveloperPage({super.key});
@override
DeveloperPageState createState() => DeveloperPageState();
}
class DeveloperPageState extends ConsumerState<DeveloperPage> {
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() {
super.initState();
_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 _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 {
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;
if (selection != null) {
final text = globalDebugTerminal.buffer.getText(selection);
_terminalController.clearSelection();
await Clipboard.setData(ClipboardData(text: text));
if (context.mounted) {
showInfoToast(context, translate('developer.copied'));
}
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final scale = theme.extension<ScaleScheme>()!;
// WidgetsBinding.instance.addPostFrameCallback((_) {
// if (!_isScrolling && _wantsBottom) {
// _scrollToBottom();
// }
// });
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: scale.primaryScale.text),
onPressed: () => GoRouterHelper(context).pop(),
),
actions: [
IconButton(
icon: const Icon(Icons.copy),
color: scale.primaryScale.text,
disabledColor: scale.grayScale.subtleText,
onPressed: _terminalController.selection == null
? null
: () async {
await copySelection(context);
}),
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'),
style:
textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.bold)),
centerTitle: true,
),
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(),
TextField(
controller: _debugCommandController,
decoration: InputDecoration(
filled: true,
contentPadding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
borderSide: BorderSide(color: scale.primaryScale.border)),
fillColor: scale.primaryScale.subtleBackground,
hintText: translate('developer.command'),
suffixIcon: IconButton(
icon: const Icon(Icons.send),
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))
..add(
DiagnosticsProperty<LogLevel>('logLevelDropDown', _logLevelDropDown));
}
}

View File

@ -12,6 +12,13 @@ class IndexPage extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
ref.watch(windowControlProvider); ref.watch(windowControlProvider);
final theme = Theme.of(context);
final textTheme = theme.textTheme;
final monoTextStyle = textTheme.labelSmall!
.copyWith(fontFamily: 'Source Code Pro', fontSize: 11);
final emojiTextStyle = textTheme.labelSmall!
.copyWith(fontFamily: 'Noto Color Emoji', fontSize: 11);
return Scaffold( return Scaffold(
body: DecoratedBox( body: DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -28,6 +35,11 @@ class IndexPage extends ConsumerWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
// Hack to preload fonts
Offstage(child: Text('🧱', style: emojiTextStyle)),
// Hack to preload fonts
Offstage(child: Text('A', style: monoTextStyle)),
// Splash Screen
Expanded( Expanded(
flex: 2, flex: 2,
child: SvgPicture.asset( child: SvgPicture.asset(

View File

@ -21,8 +21,8 @@ import '../../entities/local_account.dart';
import '../../proto/proto.dart' as proto; import '../../proto/proto.dart' as proto;
import '../../tools/tools.dart'; import '../../tools/tools.dart';
import '../../veilid_support/veilid_support.dart'; import '../../veilid_support/veilid_support.dart';
import 'account_page.dart'; import 'account.dart';
import 'chats_page.dart'; import 'chats.dart';
class MainPager extends ConsumerStatefulWidget { class MainPager extends ConsumerStatefulWidget {
const MainPager( const MainPager(

View File

@ -153,7 +153,6 @@ class NewAccountPageState extends ConsumerState<NewAccountPage> {
body: _newAccountForm( body: _newAccountForm(
context, context,
onSubmit: (formKey) async { onSubmit: (formKey) async {
debugPrint(_formKey.currentState?.value.toString());
FocusScope.of(context).unfocus(); FocusScope.of(context).unfocus();
try { try {
await createAccount(); await createAccount();

View File

@ -2,7 +2,8 @@ import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import '../pages/chat_only_page.dart'; import '../pages/chat_only.dart';
import '../pages/developer.dart';
import '../pages/home.dart'; import '../pages/home.dart';
import '../pages/index.dart'; import '../pages/index.dart';
import '../pages/new_account.dart'; import '../pages/new_account.dart';
@ -91,6 +92,8 @@ class RouterNotifier extends _$RouterNotifier implements Listenable {
case '/home/settings': case '/home/settings':
case '/new_account/settings': case '/new_account/settings':
return null; return null;
case '/developer':
return null;
default: default:
return hasAnyAccount ? null : '/new_account'; return hasAnyAccount ? null : '/new_account';
} }
@ -126,6 +129,10 @@ class RouterNotifier extends _$RouterNotifier implements Listenable {
), ),
], ],
), ),
GoRoute(
path: '/developer',
builder: (context, state) => const DeveloperPage(),
)
]; ];
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////

View File

@ -6,7 +6,7 @@ part of 'router_notifier.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$routerNotifierHash() => r'b7c49cdc6f940c5a5032faaf19af08d9f478dae6'; String _$routerNotifierHash() => r'5a3527e3890f0746db4cbe051d453b89e5809989';
/// See also [RouterNotifier]. /// See also [RouterNotifier].
@ProviderFor(RouterNotifier) @ProviderFor(RouterNotifier)

View File

@ -2,8 +2,11 @@ import 'dart:io' show Platform;
import 'package:ansicolor/ansicolor.dart'; import 'package:ansicolor/ansicolor.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:intl/intl.dart';
import 'package:loggy/loggy.dart'; import 'package:loggy/loggy.dart';
import '../pages/developer.dart';
import '../veilid_support/veilid_support.dart'; import '../veilid_support/veilid_support.dart';
String wrapWithLogColor(LogLevel? level, String text) { String wrapWithLogColor(LogLevel? level, String text) {
@ -47,14 +50,57 @@ String wrapWithLogColor(LogLevel? level, String text) {
return text; return text;
} }
final DateFormat _dateFormatter = DateFormat('HH:mm:ss.SSS');
extension PrettyPrintLogRecord on LogRecord { extension PrettyPrintLogRecord on LogRecord {
String pretty() { String pretty() {
final lstr = final tm = _dateFormatter.format(time.toLocal());
wrapWithLogColor(level, '[${level.toString().substring(0, 1)}]'); final lev = logLevelEmoji(level);
return '$lstr $message'; final lstr = wrapWithLogColor(level, tm);
return '$lstr $lev $message';
} }
} }
List<LogLevel> logLevels = [
LogLevel.error,
LogLevel.warning,
LogLevel.info,
LogLevel.debug,
traceLevel,
];
String logLevelName(LogLevel logLevel) {
switch (logLevel) {
case traceLevel:
return translate('log.trace');
case LogLevel.debug:
return translate('log.debug');
case LogLevel.info:
return translate('log.info');
case LogLevel.warning:
return translate('log.warning');
case LogLevel.error:
return translate('log.error');
}
return '???';
}
String logLevelEmoji(LogLevel logLevel) {
switch (logLevel) {
case traceLevel:
return '👾';
case LogLevel.debug:
return '🐛';
case LogLevel.info:
return '💡';
case LogLevel.warning:
return '🍋';
case LogLevel.error:
return '🛑';
}
return '';
}
class CallbackPrinter extends LoggyPrinter { class CallbackPrinter extends LoggyPrinter {
CallbackPrinter() : super(); CallbackPrinter() : super();
@ -62,7 +108,9 @@ class CallbackPrinter extends LoggyPrinter {
@override @override
void onLog(LogRecord record) { void onLog(LogRecord record) {
debugPrint(record.pretty()); final out = record.pretty();
debugPrint(out);
globalDebugTerminal.write('$out\n'.replaceAll('\n', '\r\n'));
callback?.call(record); callback?.call(record);
} }

View File

@ -20,6 +20,7 @@ Future<VeilidConfig> getVeilidChatConfig() async {
return config.copyWith( return config.copyWith(
capabilities: const VeilidConfigCapabilities(disable: ['DHTV', 'TUNL']), capabilities: const VeilidConfigCapabilities(disable: ['DHTV', 'TUNL']),
protectedStore: config.protectedStore.copyWith(allowInsecureFallback: true),
// network: config.network.copyWith( // network: config.network.copyWith(
// dht: config.network.dht.copyWith( // dht: config.network.dht.copyWith(
// getValueCount: 3, // getValueCount: 3,

View File

@ -337,6 +337,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" version: "3.1.1"
cool_dropdown:
dependency: "direct main"
description:
name: cool_dropdown
sha256: "24400f57740b4779407586121e014bef241699ad2a52c506a7e1e7616cb68653"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
cross_file: cross_file:
dependency: transitive dependency: transitive
description: description:
@ -973,6 +981,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
platform_info:
dependency: transitive
description:
name: platform_info
sha256: "012e73712166cf0b56d3eb95c0d33491f56b428c169eca385f036448474147e4"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -1601,6 +1617,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.3.0" version: "6.3.0"
xterm:
dependency: "direct main"
description:
name: xterm
sha256: "6a02b15d03152b8186e12790902ff28c8a932fc441e89fa7255a7491661a8e69"
url: "https://pub.dev"
source: hosted
version: "3.5.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:

View File

@ -19,6 +19,7 @@ dependencies:
charcode: ^1.3.1 charcode: ^1.3.1
circular_profile_avatar: ^2.0.5 circular_profile_avatar: ^2.0.5
circular_reveal_animation: ^2.0.1 circular_reveal_animation: ^2.0.1
cool_dropdown: ^2.1.0
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
equatable: ^2.0.5 equatable: ^2.0.5
fast_immutable_collections: ^9.1.5 fast_immutable_collections: ^9.1.5
@ -71,6 +72,7 @@ dependencies:
# veilid: ^0.0.1 # veilid: ^0.0.1
path: ../veilid/veilid-flutter path: ../veilid/veilid-flutter
window_manager: ^0.3.5 window_manager: ^0.3.5
xterm: ^3.5.0
zxing2: ^0.2.0 zxing2: ^0.2.0
dev_dependencies: dev_dependencies:
@ -118,11 +120,14 @@ flutter:
- assets/images/icon.svg - assets/images/icon.svg
- assets/images/title.svg - assets/images/title.svg
- assets/images/vlogo.svg - assets/images/vlogo.svg
- assets/images/ellet.png
# Fonts # Fonts
fonts: fonts:
- family: Victor Mono - family: Source Code Pro
fonts: fonts:
- asset: assets/fonts/VictorMono-VariableFont_wght.ttf - asset: assets/fonts/SourceCodePro-Regular.ttf
- asset: assets/fonts/SourceCodePro-Bold.ttf
weight: 700
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware # https://flutter.dev/assets-and-images/#resolution-aware