SimpleCloudNotifier/flutter/lib/pages/debug/debug_request_view.dart

134 lines
5.7 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:simplecloudnotifier/components/layout/scaffold.dart';
import 'package:simplecloudnotifier/state/request_log.dart';
import 'package:simplecloudnotifier/utils/toaster.dart';
import 'package:simplecloudnotifier/utils/ui.dart';
class DebugRequestViewPage extends StatefulWidget {
final SCNRequest request;
DebugRequestViewPage({required this.request});
@override
State<DebugRequestViewPage> createState() => _DebugRequestViewPageState();
}
class _DebugRequestViewPageState extends State<DebugRequestViewPage> {
Set<String> _monospaceMode = new Set();
Set<String> _prettyJson = new Set();
@override
Widget build(BuildContext context) {
return SCNScaffold(
title: 'Request',
showSearch: false,
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.start,
children: [
...buildRow(context, "name", "Name", widget.request.name),
...buildRow(context, "timestampStart", "Timestamp (Start)", widget.request.timestampStart.toString()),
...buildRow(context, "timestampEnd", "Timestamp (End)", widget.request.timestampEnd.toString()),
...buildRow(context, "duration", "Duration", widget.request.timestampEnd.difference(widget.request.timestampStart).toString()),
Divider(),
...buildRow(context, "method", "Method", widget.request.method),
...buildRow(context, "url", "URL", widget.request.url, mono: true),
if (widget.request.requestHeaders.isNotEmpty) ...buildRow(context, "request_headers", "Request->Headers", widget.request.requestHeaders.entries.map((v) => '${v.key} = ${v.value}').join('\n'), mono: true),
if (widget.request.requestBody != '') ...buildRow(context, "request_body", "Request->Body", widget.request.requestBody, mono: true, json: true),
Divider(),
if (widget.request.responseStatusCode != 0) ...buildRow(context, "response_statuscode", "Response->Statuscode", widget.request.responseStatusCode.toString()),
if (widget.request.responseBody != '') ...buildRow(context, "response_body", "Reponse->Body", widget.request.responseBody, mono: true, json: true),
if (widget.request.responseHeaders.isNotEmpty) ...buildRow(context, "response_headers", "Reponse->Headers", widget.request.responseHeaders.entries.map((v) => '${v.key} = ${v.value}').join('\n'), mono: true, json: true),
Divider(),
if (widget.request.error != '') ...buildRow(context, "error", "Error", widget.request.error, mono: true),
if (widget.request.stackTrace != '') ...buildRow(context, "trace", "Stacktrace", widget.request.stackTrace, mono: true),
],
),
),
),
);
}
List<Widget> buildRow(BuildContext context, String key, String title, String value, {bool? json, bool? mono}) {
var isMono = _monospaceMode.contains(key);
var isJson = _prettyJson.contains(key);
if (isJson) {
try {
var jsonValue = jsonDecode(value);
value = JsonEncoder.withIndent(' ').convert(jsonValue);
} catch (e) {
value = ('Error parsing JSON: $e');
}
}
return [
Padding(
padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 8.0),
child: Row(
children: [
Expanded(
child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
),
UI.buttonIconOnly(
iconSize: 14,
onPressed: () {
Clipboard.setData(new ClipboardData(text: title));
Toaster.info("Clipboard", 'Copied text to Clipboard');
print('================= [CLIPBOARD] =================\n${title}\n================= [/CLIPBOARD] =================');
},
icon: FontAwesomeIcons.copy,
),
if (mono == true)
UI.buttonIconOnly(
icon: isMono ? FontAwesomeIcons.lineColumns : FontAwesomeIcons.alignLeft,
onPressed: () {
setState(() {
_monospaceMode.contains(key) ? _monospaceMode.remove(key) : _monospaceMode.add(key);
});
},
),
if (json == true)
UI.buttonIconOnly(
icon: isJson ? FontAwesomeIcons.bracketsRound : FontAwesomeIcons.bracketsCurly,
onPressed: () {
setState(() {
_prettyJson.contains(key) ? _prettyJson.remove(key) : _prettyJson.add(key);
});
},
),
],
),
),
Card.filled(
shape: BeveledRectangleBorder(borderRadius: BorderRadius.circular(0)),
color: widget.request.type == 'SUCCESS' ? null : Theme.of(context).colorScheme.errorContainer,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 6.0),
child: (isMono || isJson)
? SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SelectableText(
value,
minLines: 1,
maxLines: 10,
),
)
: SelectableText(
value,
minLines: 1,
maxLines: 10,
),
),
),
];
}
}