From 0241ad21da655c229e623aa3193811ecbe747da4 Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:30:25 +1030 Subject: [PATCH 1/8] use reflection to allow inspection of app state --- commet/.gitignore | 1 + commet/lib/client/client_manager.dart | 2 + commet/lib/client/matrix/matrix_client.dart | 4 + .../app_inspector/app_inspector_page.dart | 18 ++++ .../app_inspector/field_display.dart | 15 +++ .../app_inspector/field_inspector.dart | 96 +++++++++++++++++++ .../app_inspector/reflectable_extensions.dart | 9 ++ .../reflectable_matrix_client.dart | 12 +++ .../app_inspector/value_reflector_widget.dart | 69 +++++++++++++ .../developer/developer_settings_page.dart | 25 +++++ commet/pubspec.lock | 8 ++ commet/pubspec.yaml | 1 + 12 files changed, 260 insertions(+) create mode 100644 commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart create mode 100644 commet/lib/ui/pages/developer/app_inspector/field_display.dart create mode 100644 commet/lib/ui/pages/developer/app_inspector/field_inspector.dart create mode 100644 commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart create mode 100644 commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart create mode 100644 commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart diff --git a/commet/.gitignore b/commet/.gitignore index 5b1f87c42..ef6ac7264 100644 --- a/commet/.gitignore +++ b/commet/.gitignore @@ -9,6 +9,7 @@ .history .svn/ *.g.dart +*.reflectable.dart *.widgetbook.dart migrate_working_dir/ diff --git a/commet/lib/client/client_manager.dart b/commet/lib/client/client_manager.dart index c8f7d4ff0..f2d7934a5 100644 --- a/commet/lib/client/client_manager.dart +++ b/commet/lib/client/client_manager.dart @@ -8,8 +8,10 @@ import 'package:commet/client/matrix/matrix_client.dart'; import 'package:commet/client/stale_info.dart'; import 'package:commet/client/tasks/client_connection_status_task.dart'; import 'package:commet/main.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/utils/notifying_list.dart'; +@Reflector() class ClientManager { final Map _clients = {}; diff --git a/commet/lib/client/matrix/matrix_client.dart b/commet/lib/client/matrix/matrix_client.dart index 0565a2dfe..d10c47003 100644 --- a/commet/lib/client/matrix/matrix_client.dart +++ b/commet/lib/client/matrix/matrix_client.dart @@ -18,6 +18,7 @@ import 'package:commet/debug/log.dart'; import 'package:commet/diagnostic/diagnostics.dart'; import 'package:commet/main.dart'; import 'package:commet/ui/navigation/adaptive_dialog.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/ui/pages/matrix/authentication/matrix_uia_request.dart'; import 'package:commet/utils/list_extension.dart'; import 'package:commet/utils/notifying_list.dart'; @@ -37,6 +38,7 @@ import 'matrix_room.dart'; import 'matrix_space.dart'; import 'package:olm/olm.dart' as olm; +@Reflector() class MatrixClient extends Client { late matrix.Client _matrixClient; late final List> componentsInternal; @@ -45,6 +47,8 @@ class MatrixClient extends Client { matrix.ServerConfig? config; + matrix.Client get matrixClient => _matrixClient; + late String _id; final NotifyingList _rooms = NotifyingList.empty( diff --git a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart new file mode 100644 index 000000000..20b4cdcf1 --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart @@ -0,0 +1,18 @@ +import 'package:commet/main.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; +import 'package:flutter/material.dart'; + +class AppInspectorPage extends StatelessWidget { + const AppInspectorPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: SingleChildScrollView( + child: Column( + children: [ValueReflectorWidget(value: clientManager!)], + ), + ), + ); + } +} diff --git a/commet/lib/ui/pages/developer/app_inspector/field_display.dart b/commet/lib/ui/pages/developer/app_inspector/field_display.dart new file mode 100644 index 000000000..76e7ae337 --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/field_display.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class FieldDisplay extends StatefulWidget { + const FieldDisplay({super.key}); + + @override + State createState() => _FieldDisplayState(); +} + +class _FieldDisplayState extends State { + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart new file mode 100644 index 000000000..08461d43f --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart @@ -0,0 +1,96 @@ +import 'package:commet/client/matrix/matrix_client.dart'; +import 'package:commet/ui/pages/developer/app_inspector/reflectable_extensions.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:reflectable/reflectable.dart'; +import 'package:tiamat/tiamat.dart' as tiamat; + +class FieldInspector extends StatefulWidget { + const FieldInspector( + {required this.declaration, required this.instance, super.key}); + final MethodMirror declaration; + final dynamic instance; + @override + State createState() => FieldInspectorState(); +} + +class FieldInspectorState extends State { + dynamic fieldValue; + + @override + void initState() { + try { + final result = ReflectableExtensions.invoke( + widget.instance, widget.declaration.simpleName); + fieldValue = result; + } catch (_) {} + + super.initState(); + } + + static String displayValue(dynamic value) { + if (value == null) { + return "null"; + } + + if (value is String) { + return value; + } + + try { + var v = "name: ${value.name}"; + return v; + } catch (_) {} + + try { + var v = "displayname: ${value.displayname}"; + return v; + } catch (_) {} + + try { + var v = "id: ${value.id}"; + return v; + } catch (_) {} + + return value.toString(); + } + + @override + Widget build(BuildContext context) { + return ExpansionTile( + expandedCrossAxisAlignment: CrossAxisAlignment.start, + expandedAlignment: Alignment.topLeft, + dense: true, + title: Row( + children: [ + tiamat.Text(widget.declaration.simpleName.toString()), + SizedBox(width: 20), + tiamat.Text.labelLow(displayValue(fieldValue)) + ], + ), + children: [ + tiamat.Tile.low( + child: Padding( + padding: const EdgeInsets.fromLTRB(30, 0, 0, 0), + child: buildValue(fieldValue), + )) + ], + ); + } + + Widget buildValue(dynamic value) { + print("Building value: ${value}"); + + if (value == null) { + return tiamat.Text("null"); + } + + if (value is List) { + return Column( + children: (value as List).map((e) => buildValue(e)).toList(), + ); + } + + return ValueReflectorWidget(value: value); + } +} diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart new file mode 100644 index 000000000..c292bf4e5 --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart @@ -0,0 +1,9 @@ +import 'package:reflectable/src/reflectable_builder_based.dart' as builder; + +class ReflectableExtensions { + static Object? invoke(dynamic object, String name) { + var getter = builder.data.values.first.getters[name]!; + var result = getter(object); + return result; + } +} diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart new file mode 100644 index 000000000..547b37db1 --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart @@ -0,0 +1,12 @@ +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; +import 'package:matrix/matrix.dart' as matrix; + +@Reflector() +class ReflectableMatrixClient extends matrix.Client { + ReflectableMatrixClient(super.clientName); +} + +@Reflector() +class ReflectableMatrixRoom extends matrix.Room { + ReflectableMatrixRoom({required super.id, required super.client}); +} diff --git a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart new file mode 100644 index 000000000..4f2e47a2a --- /dev/null +++ b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart @@ -0,0 +1,69 @@ +import 'package:commet/main.reflectable.dart'; +import 'package:commet/ui/pages/developer/app_inspector/app_inspector_page.dart'; +import 'package:commet/ui/pages/developer/app_inspector/field_inspector.dart'; +import 'package:commet/ui/pages/developer/app_inspector/reflectable_matrix_client.dart'; +import 'package:flutter/material.dart'; +import 'package:reflectable/reflectable.dart'; +import 'package:tiamat/tiamat.dart' as tiamat; +import 'package:matrix/matrix.dart' as matrix; + +class Reflector extends Reflectable { + const Reflector() + : super(typingCapability, invokingCapability, + libraryDependenciesCapability); +} + +const reflector = const Reflector(); + +class ValueReflectorWidget extends StatefulWidget { + const ValueReflectorWidget({required this.value, super.key}); + final dynamic value; + + @override + State createState() => _ValueReflectorWidgetState(); +} + +class _ValueReflectorWidgetState extends State { + ClassMirror? classMirror; + + @override + void initState() { + initializeReflectable(); + + var type = { + matrix.Client: ReflectableMatrixClient, + matrix.Room: ReflectableMatrixRoom, + }[widget.value.runtimeType] ?? + widget.value.runtimeType; + + if (reflector.canReflectType(type)) { + classMirror = reflector.reflectType(type) as ClassMirror; + } + + super.initState(); + } + + @override + Widget build(BuildContext context) { + if (classMirror == null) { + return tiamat.Text.label(widget.value.toString()); + } + + var sorted = classMirror!.instanceMembers.keys.toList() + ..sort((a, b) => a.compareTo(b)); + return ExpansionTile( + title: tiamat.Text.label( + "${FieldInspectorState.displayValue(widget.value)}"), + children: [ + Column( + children: sorted.map((e) { + print("Building: ${e}"); + + return FieldInspector( + declaration: classMirror!.instanceMembers[e]!, + instance: widget.value, + ); + }).toList()), + ]); + } +} diff --git a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart index 3d2a793f2..98d0a2343 100644 --- a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart @@ -5,7 +5,9 @@ import 'package:commet/config/app_config.dart'; import 'package:commet/diagnostic/diagnostics.dart'; import 'package:commet/main.dart'; import 'package:commet/ui/navigation/navigation_utils.dart'; +import 'package:commet/ui/pages/developer/app_inspector/app_inspector_page.dart'; import 'package:commet/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart'; import 'package:commet/utils/background_tasks/background_task_manager.dart'; import 'package:commet/utils/background_tasks/mock_tasks.dart'; @@ -30,6 +32,7 @@ class _DeveloperSettingsPageState extends State { children: [ performance(), benchmarks(), + inspect(), windowSize(), notificationTests(), rendering(), @@ -88,6 +91,28 @@ class _DeveloperSettingsPageState extends State { ]); } + Widget inspect() { + return ExpansionTile( + title: const tiamat.Text.labelEmphasised("Inspect"), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: + Theme.of(context).colorScheme.surfaceContainerLow, + children: [ + Wrap( + spacing: 8, + runSpacing: 8, + children: [ + tiamat.Button( + text: "Inspect App State", + onTap: () => NavigationUtils.navigateTo( + context, const AppInspectorPage()), + ) + ], + ), + ]); + } + Widget benchmarks() { return ExpansionTile( title: const tiamat.Text.labelEmphasised("Benchmarks"), diff --git a/commet/pubspec.lock b/commet/pubspec.lock index 683a02bb5..708335df8 100644 --- a/commet/pubspec.lock +++ b/commet/pubspec.lock @@ -1329,6 +1329,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.5" + reflectable: + dependency: "direct main" + description: + name: reflectable + sha256: f6abe4c7779c6c88f77b79a4317d9277c870c7292a3d6c2e56624c4846124368 + url: "https://pub.dev" + source: hosted + version: "4.0.10" safe_local_storage: dependency: transitive description: diff --git a/commet/pubspec.yaml b/commet/pubspec.yaml index bcf0009f9..6fea80dcd 100644 --- a/commet/pubspec.yaml +++ b/commet/pubspec.yaml @@ -90,6 +90,7 @@ dependencies: archive: ^3.6.1 exif: ^3.3.0 image: ^4.2.0 + reflectable: ^4.0.10 ## ---- Putting some extra lines in here to help git with the diff ## ---- Probably good to keep this stuff at the bottom of the list From 3c7a73e1d7251646e9928bae46e176c6d3fb52fe Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:32:49 +1030 Subject: [PATCH 2/8] improving inspector --- .../app_inspector/app_inspector_page.dart | 24 +++++- .../app_inspector/field_inspector.dart | 80 ++++++++++++++----- .../app_inspector/reflectable_extensions.dart | 1 + .../reflectable_matrix_client.dart | 11 +++ .../app_inspector/value_reflector_widget.dart | 65 ++++++++++----- .../developer/developer_settings_page.dart | 1 - 6 files changed, 140 insertions(+), 42 deletions(-) diff --git a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart index 20b4cdcf1..d11cec6e4 100644 --- a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart +++ b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart @@ -1,6 +1,8 @@ import 'package:commet/main.dart'; +import 'package:commet/ui/atoms/scaled_safe_area.dart'; import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:flutter/material.dart'; +import 'package:tiamat/tiamat.dart' as tiamat; class AppInspectorPage extends StatelessWidget { const AppInspectorPage({super.key}); @@ -9,8 +11,26 @@ class AppInspectorPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( - child: Column( - children: [ValueReflectorWidget(value: clientManager!)], + child: ScaledSafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.CircleButton( + icon: Icons.arrow_back, + radius: 27, + onPressed: () => Navigator.of(context).pop(), + ), + ), + const Padding( + padding: EdgeInsets.all(20.0), + child: tiamat.Text.body( + "Warning: This inspector allows you to view lots of information that would typically be hidden, some of which could be sensitive. It is recommended that you do not view this page while it may be visible to others\n\nWhile effort has been made to redact sensitive information, we cannot guarantee that we have caught everything. Continue at your own risk."), + ), + ValueReflectorWidget(value: clientManager!) + ], + ), ), ), ); diff --git a/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart index 08461d43f..2f336ddff 100644 --- a/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart +++ b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart @@ -1,4 +1,3 @@ -import 'package:commet/client/matrix/matrix_client.dart'; import 'package:commet/ui/pages/developer/app_inspector/reflectable_extensions.dart'; import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:flutter/material.dart'; @@ -38,17 +37,17 @@ class FieldInspectorState extends State { } try { - var v = "name: ${value.name}"; + var v = "$value name: ${value.name}"; return v; } catch (_) {} try { - var v = "displayname: ${value.displayname}"; + var v = "$value displayname: ${value.displayname}"; return v; } catch (_) {} try { - var v = "id: ${value.id}"; + var v = "$value id: ${value.id}"; return v; } catch (_) {} @@ -57,40 +56,83 @@ class FieldInspectorState extends State { @override Widget build(BuildContext context) { + final color = (Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black) + .withAlpha(7); + return ExpansionTile( expandedCrossAxisAlignment: CrossAxisAlignment.start, expandedAlignment: Alignment.topLeft, + backgroundColor: color, dense: true, title: Row( children: [ tiamat.Text(widget.declaration.simpleName.toString()), - SizedBox(width: 20), - tiamat.Text.labelLow(displayValue(fieldValue)) + const SizedBox(width: 20), + Flexible( + child: tiamat.Text.labelLow( + displayValue(fieldValue), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ) ], ), - children: [ - tiamat.Tile.low( - child: Padding( - padding: const EdgeInsets.fromLTRB(30, 0, 0, 0), - child: buildValue(fieldValue), - )) - ], + children: [buildValue(fieldValue)], ); } - Widget buildValue(dynamic value) { - print("Building value: ${value}"); - + Widget buildValue(dynamic value, {int index = 0}) { if (value == null) { - return tiamat.Text("null"); + return const tiamat.Text("null"); } if (value is List) { return Column( - children: (value as List).map((e) => buildValue(e)).toList(), + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: (value) + .mapIndexed((e, i) => Container(child: buildValue(e))) + .toList(), + ); + } + + if (value is Map) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: value.keys.mapIndexed((e, i) { + var label = displayValue(e); + if (label == "") { + label = "\"\""; + } + return Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + tiamat.Text.labelLow( + "$label:", + ), + Padding( + padding: const EdgeInsets.fromLTRB(10, 0, 0, 0), + child: buildValue(value[e], index: i), + ) + ], + ), + ); + }).toList(), ); } - return ValueReflectorWidget(value: value); + return Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 0, 0), + child: ValueReflectorWidget( + value: value, + index: index, + ), + ); } } diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart index c292bf4e5..53a234ec5 100644 --- a/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_extensions.dart @@ -1,3 +1,4 @@ +// ignore: implementation_imports import 'package:reflectable/src/reflectable_builder_based.dart' as builder; class ReflectableExtensions { diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart index 547b37db1..a4605ac2c 100644 --- a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart @@ -10,3 +10,14 @@ class ReflectableMatrixClient extends matrix.Client { class ReflectableMatrixRoom extends matrix.Room { ReflectableMatrixRoom({required super.id, required super.client}); } + +@Reflector() +class ReflectableMatrixEvent extends matrix.Event { + ReflectableMatrixEvent( + {required super.content, + required super.type, + required super.eventId, + required super.senderId, + required super.originServerTs, + required super.room}); +} diff --git a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart index 4f2e47a2a..de2907e52 100644 --- a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart +++ b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart @@ -1,5 +1,4 @@ import 'package:commet/main.reflectable.dart'; -import 'package:commet/ui/pages/developer/app_inspector/app_inspector_page.dart'; import 'package:commet/ui/pages/developer/app_inspector/field_inspector.dart'; import 'package:commet/ui/pages/developer/app_inspector/reflectable_matrix_client.dart'; import 'package:flutter/material.dart'; @@ -13,11 +12,12 @@ class Reflector extends Reflectable { libraryDependenciesCapability); } -const reflector = const Reflector(); +const reflector = Reflector(); class ValueReflectorWidget extends StatefulWidget { - const ValueReflectorWidget({required this.value, super.key}); + const ValueReflectorWidget({required this.value, super.key, this.index = 0}); final dynamic value; + final int index; @override State createState() => _ValueReflectorWidgetState(); @@ -25,7 +25,7 @@ class ValueReflectorWidget extends StatefulWidget { class _ValueReflectorWidgetState extends State { ClassMirror? classMirror; - + late List keys; @override void initState() { initializeReflectable(); @@ -33,11 +33,17 @@ class _ValueReflectorWidgetState extends State { var type = { matrix.Client: ReflectableMatrixClient, matrix.Room: ReflectableMatrixRoom, + matrix.Event: ReflectableMatrixEvent, }[widget.value.runtimeType] ?? widget.value.runtimeType; if (reflector.canReflectType(type)) { classMirror = reflector.reflectType(type) as ClassMirror; + keys = classMirror!.instanceMembers.keys.toList() + ..sort((a, b) => a.compareTo(b)) + ..removeWhere((e) => + classMirror!.instanceMembers[e]!.isRegularMethod || + classMirror!.instanceMembers[e]!.isSetter); } super.initState(); @@ -46,24 +52,43 @@ class _ValueReflectorWidgetState extends State { @override Widget build(BuildContext context) { if (classMirror == null) { - return tiamat.Text.label(widget.value.toString()); + return tiamat.Text.labelLow(widget.value.toString()); } - var sorted = classMirror!.instanceMembers.keys.toList() - ..sort((a, b) => a.compareTo(b)); - return ExpansionTile( - title: tiamat.Text.label( - "${FieldInspectorState.displayValue(widget.value)}"), - children: [ - Column( - children: sorted.map((e) { - print("Building: ${e}"); + final color = (Theme.of(context).brightness == Brightness.dark + ? Colors.white + : Colors.black) + .withAlpha(7); + + return Padding( + padding: const EdgeInsets.all(2), + child: ExpansionTile( + backgroundColor: color, + title: + tiamat.Text.label(FieldInspectorState.displayValue(widget.value)), + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: keys.mapIndexed((e, i) { + if ([ + "accessToken", + "bearerToken", + "fingerprintKey", + "identityKey" + ].contains(e)) { + return Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 0, 4), + child: tiamat.Text.error("$e (Redacted)"), + ); + } - return FieldInspector( - declaration: classMirror!.instanceMembers[e]!, - instance: widget.value, - ); - }).toList()), - ]); + return FieldInspector( + declaration: classMirror!.instanceMembers[e]!, + instance: widget.value, + ); + }).toList()), + ]), + ); } } diff --git a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart index 98d0a2343..191bffe8c 100644 --- a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart @@ -7,7 +7,6 @@ import 'package:commet/main.dart'; import 'package:commet/ui/navigation/navigation_utils.dart'; import 'package:commet/ui/pages/developer/app_inspector/app_inspector_page.dart'; import 'package:commet/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart'; -import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart'; import 'package:commet/utils/background_tasks/background_task_manager.dart'; import 'package:commet/utils/background_tasks/mock_tasks.dart'; From 03afae0292ed1b2939b39caffdf59b9d471850c1 Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:30:16 +1030 Subject: [PATCH 3/8] Delete field_display.dart --- .../developer/app_inspector/field_display.dart | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 commet/lib/ui/pages/developer/app_inspector/field_display.dart diff --git a/commet/lib/ui/pages/developer/app_inspector/field_display.dart b/commet/lib/ui/pages/developer/app_inspector/field_display.dart deleted file mode 100644 index 76e7ae337..000000000 --- a/commet/lib/ui/pages/developer/app_inspector/field_display.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class FieldDisplay extends StatefulWidget { - const FieldDisplay({super.key}); - - @override - State createState() => _FieldDisplayState(); -} - -class _FieldDisplayState extends State { - @override - Widget build(BuildContext context) { - return const Placeholder(); - } -} From ed8e40b2586efc2068cf6f7552c012598737e41c Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:31:26 +1030 Subject: [PATCH 4/8] Update app_inspector_page.dart --- .../ui/pages/developer/app_inspector/app_inspector_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart index d11cec6e4..b1247c32e 100644 --- a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart +++ b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart @@ -26,7 +26,7 @@ class AppInspectorPage extends StatelessWidget { const Padding( padding: EdgeInsets.all(20.0), child: tiamat.Text.body( - "Warning: This inspector allows you to view lots of information that would typically be hidden, some of which could be sensitive. It is recommended that you do not view this page while it may be visible to others\n\nWhile effort has been made to redact sensitive information, we cannot guarantee that we have caught everything. Continue at your own risk."), + "Warning: This inspector allows you to view lots of information that would typically be hidden, some of which could be sensitive. It is recommended that you do not view this page if your screen may be visible to others\n\nWhile effort has been made to redact sensitive information, we cannot guarantee that we have caught everything. Continue at your own risk."), ), ValueReflectorWidget(value: clientManager!) ], From 1bb344d3bb4d0788e000b09f7e479bd51cece9b7 Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:53:20 +1030 Subject: [PATCH 5/8] add more classes to reflection --- commet/lib/client/matrix/matrix_member.dart | 1 + commet/lib/client/matrix/matrix_profile.dart | 2 ++ commet/lib/client/matrix/matrix_room.dart | 2 ++ commet/lib/client/matrix/matrix_space.dart | 2 ++ commet/lib/client/matrix/matrix_timeline.dart | 2 ++ .../ui/pages/developer/app_inspector/field_inspector.dart | 5 +++++ 6 files changed, 14 insertions(+) diff --git a/commet/lib/client/matrix/matrix_member.dart b/commet/lib/client/matrix/matrix_member.dart index 58f2410f0..b73cf7f7c 100644 --- a/commet/lib/client/matrix/matrix_member.dart +++ b/commet/lib/client/matrix/matrix_member.dart @@ -1,5 +1,6 @@ import 'package:commet/client/matrix/matrix_mxc_image_provider.dart'; import 'package:commet/client/member.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart' as matrix; diff --git a/commet/lib/client/matrix/matrix_profile.dart b/commet/lib/client/matrix/matrix_profile.dart index 669cae0d3..edb07d355 100644 --- a/commet/lib/client/matrix/matrix_profile.dart +++ b/commet/lib/client/matrix/matrix_profile.dart @@ -1,9 +1,11 @@ import 'package:commet/client/matrix/matrix_member.dart'; import 'package:commet/client/matrix/matrix_mxc_image_provider.dart'; import 'package:commet/client/profile.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:flutter/widgets.dart'; import 'package:matrix/matrix.dart' as matrix; +@Reflector() class MatrixProfile implements Profile { matrix.Profile profile; matrix.Client client; diff --git a/commet/lib/client/matrix/matrix_room.dart b/commet/lib/client/matrix/matrix_room.dart index 8260fc8c4..7ff5aa8f4 100644 --- a/commet/lib/client/matrix/matrix_room.dart +++ b/commet/lib/client/matrix/matrix_room.dart @@ -35,6 +35,7 @@ import 'package:commet/client/timeline_events/timeline_event_message.dart'; import 'package:commet/config/build_config.dart'; import 'package:commet/debug/log.dart'; import 'package:commet/main.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/utils/image_utils.dart'; import 'package:commet/utils/mime.dart'; import 'package:flutter/material.dart'; @@ -49,6 +50,7 @@ import '../attachment.dart'; import '../client.dart'; import 'package:matrix/matrix.dart' as matrix; +@Reflector() class MatrixRoom extends Room { late matrix.Room _matrixRoom; diff --git a/commet/lib/client/matrix/matrix_space.dart b/commet/lib/client/matrix/matrix_space.dart index b09fea4c4..7da73a440 100644 --- a/commet/lib/client/matrix/matrix_space.dart +++ b/commet/lib/client/matrix/matrix_space.dart @@ -11,12 +11,14 @@ import 'package:commet/client/matrix/matrix_room_permissions.dart'; import 'package:commet/client/matrix/matrix_room_preview.dart'; import 'package:commet/client/permissions.dart'; import 'package:commet/client/room_preview.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:commet/utils/notifying_list.dart'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart' as matrix; import 'matrix_peer.dart'; +@Reflector() class MatrixSpace extends Space { late matrix.Room _matrixRoom; late matrix.Client _matrixClient; diff --git a/commet/lib/client/matrix/matrix_timeline.dart b/commet/lib/client/matrix/matrix_timeline.dart index e0b621156..ee43e6da7 100644 --- a/commet/lib/client/matrix/matrix_timeline.dart +++ b/commet/lib/client/matrix/matrix_timeline.dart @@ -6,10 +6,12 @@ import 'package:commet/client/matrix/timeline_events/matrix_timeline_event.dart' import 'package:commet/client/timeline_events/timeline_event.dart'; import 'package:commet/client/timeline_events/timeline_event_message.dart'; import 'package:commet/client/timeline_events/timeline_event_sticker.dart'; +import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import '../client.dart'; import 'package:matrix/matrix.dart' as matrix; +@Reflector() class MatrixTimeline extends Timeline { matrix.Timeline? _matrixTimeline; late matrix.Room _matrixRoom; diff --git a/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart index 2f336ddff..1a02c4550 100644 --- a/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart +++ b/commet/lib/ui/pages/developer/app_inspector/field_inspector.dart @@ -46,6 +46,11 @@ class FieldInspectorState extends State { return v; } catch (_) {} + try { + var v = "$value displayName: ${value.displayName}"; + return v; + } catch (_) {} + try { var v = "$value id: ${value.id}"; return v; From 5048c8f2d62853c3858f9a49159558f8cd46344b Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:55:57 +1030 Subject: [PATCH 6/8] Update matrix_member.dart --- commet/lib/client/matrix/matrix_member.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/commet/lib/client/matrix/matrix_member.dart b/commet/lib/client/matrix/matrix_member.dart index b73cf7f7c..58f2410f0 100644 --- a/commet/lib/client/matrix/matrix_member.dart +++ b/commet/lib/client/matrix/matrix_member.dart @@ -1,6 +1,5 @@ import 'package:commet/client/matrix/matrix_mxc_image_provider.dart'; import 'package:commet/client/member.dart'; -import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart' as matrix; From 9d1d672ae927cbd33a50ce41392ec13075ea50bc Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 23:38:20 +1030 Subject: [PATCH 7/8] make more classes reflective --- .../app_inspector/reflectable_matrix_client.dart | 12 ++++++++++++ .../app_inspector/value_reflector_widget.dart | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart index a4605ac2c..cef45b648 100644 --- a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart @@ -1,5 +1,7 @@ import 'package:commet/ui/pages/developer/app_inspector/value_reflector_widget.dart'; import 'package:matrix/matrix.dart' as matrix; +// ignore: implementation_imports +import 'package:matrix/src/utils/space_child.dart'; @Reflector() class ReflectableMatrixClient extends matrix.Client { @@ -21,3 +23,13 @@ class ReflectableMatrixEvent extends matrix.Event { required super.originServerTs, required super.room}); } + +@Reflector() +class ReflectableMatrixSpaceChild extends SpaceChild { + ReflectableMatrixSpaceChild.fromState(super.state) : super.fromState(); +} + +@Reflector() +class ReflectableMatrixSpaceParent extends SpaceParent { + ReflectableMatrixSpaceParent.fromState(super.state) : super.fromState(); +} diff --git a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart index de2907e52..af7e10762 100644 --- a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart +++ b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart @@ -6,6 +6,9 @@ import 'package:reflectable/reflectable.dart'; import 'package:tiamat/tiamat.dart' as tiamat; import 'package:matrix/matrix.dart' as matrix; +// ignore: implementation_imports +import 'package:matrix/src/utils/space_child.dart'; + class Reflector extends Reflectable { const Reflector() : super(typingCapability, invokingCapability, @@ -34,6 +37,8 @@ class _ValueReflectorWidgetState extends State { matrix.Client: ReflectableMatrixClient, matrix.Room: ReflectableMatrixRoom, matrix.Event: ReflectableMatrixEvent, + SpaceChild: ReflectableMatrixSpaceChild, + SpaceParent: ReflectableMatrixSpaceParent, }[widget.value.runtimeType] ?? widget.value.runtimeType; From d1b1e3703ef8d9d224507881cce05ec05043d935 Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Fri, 7 Mar 2025 23:58:00 +1030 Subject: [PATCH 8/8] make text selectable --- .../app_inspector/app_inspector_page.dart | 36 ++++++++++--------- .../reflectable_matrix_client.dart | 5 +++ .../app_inspector/value_reflector_widget.dart | 1 + 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart index b1247c32e..cfece26f6 100644 --- a/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart +++ b/commet/lib/ui/pages/developer/app_inspector/app_inspector_page.dart @@ -12,24 +12,26 @@ class AppInspectorPage extends StatelessWidget { return Scaffold( body: SingleChildScrollView( child: ScaledSafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: tiamat.CircleButton( - icon: Icons.arrow_back, - radius: 27, - onPressed: () => Navigator.of(context).pop(), + child: SelectionArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: tiamat.CircleButton( + icon: Icons.arrow_back, + radius: 27, + onPressed: () => Navigator.of(context).pop(), + ), ), - ), - const Padding( - padding: EdgeInsets.all(20.0), - child: tiamat.Text.body( - "Warning: This inspector allows you to view lots of information that would typically be hidden, some of which could be sensitive. It is recommended that you do not view this page if your screen may be visible to others\n\nWhile effort has been made to redact sensitive information, we cannot guarantee that we have caught everything. Continue at your own risk."), - ), - ValueReflectorWidget(value: clientManager!) - ], + const Padding( + padding: EdgeInsets.all(20.0), + child: tiamat.Text.body( + "Warning: This inspector allows you to view lots of information that would typically be hidden, some of which could be sensitive. It is recommended that you do not view this page if your screen may be visible to others\n\nWhile effort has been made to redact sensitive information, we cannot guarantee that we have caught everything. Continue at your own risk."), + ), + ValueReflectorWidget(value: clientManager!) + ], + ), ), ), ), diff --git a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart index cef45b648..bbd9ae436 100644 --- a/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart +++ b/commet/lib/ui/pages/developer/app_inspector/reflectable_matrix_client.dart @@ -33,3 +33,8 @@ class ReflectableMatrixSpaceChild extends SpaceChild { class ReflectableMatrixSpaceParent extends SpaceParent { ReflectableMatrixSpaceParent.fromState(super.state) : super.fromState(); } + +@Reflector() +class ReflectableMatrixBasicEvent extends matrix.BasicEvent { + ReflectableMatrixBasicEvent({required super.type, required super.content}); +} diff --git a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart index af7e10762..ceaa07ff4 100644 --- a/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart +++ b/commet/lib/ui/pages/developer/app_inspector/value_reflector_widget.dart @@ -39,6 +39,7 @@ class _ValueReflectorWidgetState extends State { matrix.Event: ReflectableMatrixEvent, SpaceChild: ReflectableMatrixSpaceChild, SpaceParent: ReflectableMatrixSpaceParent, + matrix.BasicEvent: ReflectableMatrixBasicEvent }[widget.value.runtimeType] ?? widget.value.runtimeType;