2023-04-04 16:06:14 +00:00
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:selfprivacy/logic/models/message.dart';
|
|
|
|
|
|
|
|
class LogListItem extends StatelessWidget {
|
|
|
|
const LogListItem({
|
|
|
|
required this.message,
|
|
|
|
super.key,
|
|
|
|
});
|
|
|
|
|
|
|
|
final Message message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) {
|
|
|
|
final messageItem = message;
|
|
|
|
if (messageItem is RestApiRequestMessage) {
|
|
|
|
return _RestApiRequestMessageItem(message: messageItem);
|
|
|
|
} else if (messageItem is RestApiResponseMessage) {
|
|
|
|
return _RestApiResponseMessageItem(message: messageItem);
|
|
|
|
} else if (messageItem is GraphQlResponseMessage) {
|
|
|
|
return _GraphQlResponseMessageItem(message: messageItem);
|
|
|
|
} else if (messageItem is GraphQlRequestMessage) {
|
|
|
|
return _GraphQlRequestMessageItem(message: messageItem);
|
|
|
|
} else {
|
|
|
|
return _DefaultMessageItem(message: messageItem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class _RestApiRequestMessageItem extends StatelessWidget {
|
|
|
|
const _RestApiRequestMessageItem({required this.message});
|
|
|
|
|
|
|
|
final RestApiRequestMessage message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) => ListTile(
|
|
|
|
title: Text(
|
|
|
|
'${message.method}\n${message.uri}',
|
|
|
|
),
|
|
|
|
subtitle: Text(message.timeString),
|
|
|
|
leading: const Icon(Icons.upload_outlined),
|
|
|
|
iconColor: Theme.of(context).colorScheme.secondary,
|
|
|
|
onTap: () => showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (final BuildContext context) => AlertDialog(
|
|
|
|
scrollable: true,
|
|
|
|
title: Text(
|
|
|
|
'${message.method}\n${message.uri}',
|
|
|
|
),
|
|
|
|
content: Column(
|
|
|
|
children: [
|
|
|
|
Text(message.timeString),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Headers is a map of key-value pairs
|
|
|
|
if (message.headers != null) const Text('Headers'),
|
|
|
|
if (message.headers != null)
|
|
|
|
Text(
|
|
|
|
message.headers!.entries
|
|
|
|
.map((final entry) => '${entry.key}: ${entry.value}')
|
|
|
|
.join('\n'),
|
|
|
|
),
|
|
|
|
if (message.data != null && message.data != 'null')
|
|
|
|
const Text('Data'),
|
|
|
|
if (message.data != null && message.data != 'null')
|
|
|
|
Text(message.data!),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
actions: [
|
|
|
|
// A button to copy the request to the clipboard
|
2023-05-30 17:25:46 +00:00
|
|
|
if (message.text != null)
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
Clipboard.setData(ClipboardData(text: message.text ?? ''));
|
|
|
|
},
|
|
|
|
child: Text('console_page.copy'.tr()),
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
TextButton(
|
|
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
|
|
child: Text('basis.close'.tr()),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class _RestApiResponseMessageItem extends StatelessWidget {
|
|
|
|
const _RestApiResponseMessageItem({required this.message});
|
|
|
|
|
|
|
|
final RestApiResponseMessage message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) => ListTile(
|
|
|
|
title: Text(
|
|
|
|
'${message.statusCode} ${message.method}\n${message.uri}',
|
|
|
|
),
|
|
|
|
subtitle: Text(message.timeString),
|
|
|
|
leading: const Icon(Icons.download_outlined),
|
|
|
|
iconColor: Theme.of(context).colorScheme.primary,
|
|
|
|
onTap: () => showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (final BuildContext context) => AlertDialog(
|
|
|
|
scrollable: true,
|
|
|
|
title: Text(
|
|
|
|
'${message.statusCode} ${message.method}\n${message.uri}',
|
|
|
|
),
|
|
|
|
content: Column(
|
|
|
|
children: [
|
|
|
|
Text(message.timeString),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
// Headers is a map of key-value pairs
|
|
|
|
if (message.data != null && message.data != 'null')
|
|
|
|
const Text('Data'),
|
|
|
|
if (message.data != null && message.data != 'null')
|
|
|
|
Text(message.data!),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
actions: [
|
|
|
|
// A button to copy the request to the clipboard
|
2023-05-30 17:25:46 +00:00
|
|
|
if (message.text != null)
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
Clipboard.setData(ClipboardData(text: message.text ?? ''));
|
|
|
|
},
|
|
|
|
child: Text('console_page.copy'.tr()),
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
TextButton(
|
|
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
|
|
child: Text('basis.close'.tr()),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class _GraphQlResponseMessageItem extends StatelessWidget {
|
|
|
|
const _GraphQlResponseMessageItem({required this.message});
|
|
|
|
|
|
|
|
final GraphQlResponseMessage message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) => ListTile(
|
|
|
|
title: Text(
|
|
|
|
'GraphQL Response at ${message.timeString}',
|
|
|
|
),
|
2023-04-05 10:33:53 +00:00
|
|
|
subtitle: Text(
|
|
|
|
message.data.toString(),
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
maxLines: 1,
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
leading: const Icon(Icons.arrow_circle_down_outlined),
|
|
|
|
iconColor: Theme.of(context).colorScheme.tertiary,
|
|
|
|
onTap: () => showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (final BuildContext context) => AlertDialog(
|
|
|
|
scrollable: true,
|
|
|
|
title: Text(
|
|
|
|
'GraphQL Response at ${message.timeString}',
|
|
|
|
),
|
|
|
|
content: Column(
|
|
|
|
children: [
|
|
|
|
Text(message.timeString),
|
|
|
|
const Divider(),
|
|
|
|
if (message.data != null) const Text('Data'),
|
|
|
|
// Data is a map of key-value pairs
|
|
|
|
if (message.data != null)
|
|
|
|
Text(
|
|
|
|
message.data!.entries
|
|
|
|
.map((final entry) => '${entry.key}: ${entry.value}')
|
|
|
|
.join('\n'),
|
|
|
|
),
|
|
|
|
const Divider(),
|
|
|
|
if (message.errors != null) const Text('Errors'),
|
|
|
|
if (message.errors != null)
|
|
|
|
Text(
|
|
|
|
message.errors!
|
2023-04-05 10:33:53 +00:00
|
|
|
.map(
|
|
|
|
(final entry) =>
|
|
|
|
'${entry.message} at ${entry.locations}',
|
|
|
|
)
|
2023-04-04 16:06:14 +00:00
|
|
|
.join('\n'),
|
|
|
|
),
|
|
|
|
const Divider(),
|
|
|
|
if (message.context != null) const Text('Context'),
|
|
|
|
if (message.context != null)
|
|
|
|
Text(
|
|
|
|
message.context!.toString(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
actions: [
|
|
|
|
// A button to copy the request to the clipboard
|
2023-05-30 17:25:46 +00:00
|
|
|
if (message.text != null)
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
Clipboard.setData(ClipboardData(text: message.text ?? ''));
|
|
|
|
},
|
|
|
|
child: Text('console_page.copy'.tr()),
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
TextButton(
|
|
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
|
|
child: Text('basis.close'.tr()),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class _GraphQlRequestMessageItem extends StatelessWidget {
|
|
|
|
const _GraphQlRequestMessageItem({required this.message});
|
|
|
|
|
|
|
|
final GraphQlRequestMessage message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) => ListTile(
|
|
|
|
title: Text(
|
|
|
|
'GraphQL Request at ${message.timeString}',
|
|
|
|
),
|
2023-04-05 10:33:53 +00:00
|
|
|
subtitle: Text(
|
|
|
|
message.operation.toString(),
|
|
|
|
overflow: TextOverflow.ellipsis,
|
|
|
|
maxLines: 1,
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
leading: const Icon(Icons.arrow_circle_up_outlined),
|
|
|
|
iconColor: Theme.of(context).colorScheme.secondary,
|
|
|
|
onTap: () => showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (final BuildContext context) => AlertDialog(
|
|
|
|
scrollable: true,
|
|
|
|
title: Text(
|
|
|
|
'GraphQL Response at ${message.timeString}',
|
|
|
|
),
|
|
|
|
content: Column(
|
|
|
|
children: [
|
|
|
|
Text(message.timeString),
|
|
|
|
const Divider(),
|
|
|
|
if (message.operation != null) const Text('Operation'),
|
|
|
|
// Data is a map of key-value pairs
|
|
|
|
if (message.operation != null)
|
|
|
|
Text(
|
|
|
|
message.operation!.toString(),
|
|
|
|
),
|
|
|
|
const Divider(),
|
|
|
|
if (message.variables != null) const Text('Variables'),
|
|
|
|
if (message.variables != null)
|
|
|
|
Text(
|
|
|
|
message.variables!.entries
|
|
|
|
.map((final entry) => '${entry.key}: ${entry.value}')
|
|
|
|
.join('\n'),
|
|
|
|
),
|
|
|
|
const Divider(),
|
|
|
|
if (message.context != null) const Text('Context'),
|
|
|
|
if (message.context != null)
|
|
|
|
Text(
|
|
|
|
message.context!.toString(),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
actions: [
|
|
|
|
// A button to copy the request to the clipboard
|
2023-05-30 17:25:46 +00:00
|
|
|
if (message.text != null)
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
Clipboard.setData(ClipboardData(text: message.text ?? ''));
|
|
|
|
},
|
|
|
|
child: Text('console_page.copy'.tr()),
|
|
|
|
),
|
2023-04-04 16:06:14 +00:00
|
|
|
TextButton(
|
|
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
|
|
child: Text('basis.close'.tr()),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
class _DefaultMessageItem extends StatelessWidget {
|
|
|
|
const _DefaultMessageItem({required this.message});
|
|
|
|
|
|
|
|
final Message message;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(final BuildContext context) => Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(vertical: 4),
|
|
|
|
child: RichText(
|
|
|
|
text: TextSpan(
|
|
|
|
style: DefaultTextStyle.of(context).style,
|
|
|
|
children: <TextSpan>[
|
|
|
|
TextSpan(
|
|
|
|
text: '${message.timeString}: \n',
|
|
|
|
style: const TextStyle(
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
TextSpan(text: message.text),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|