Skip to content

Commit 103500e

Browse files
feat(cat-voices): app/gateway info and config sections in DevTools (#2594)
* feat: more sections in DevTools page * chore: cleanup code after PR * fix: PR number
1 parent f89735c commit 103500e

File tree

21 files changed

+515
-3
lines changed

21 files changed

+515
-3
lines changed

catalyst_voices/apps/voices/lib/dependency/dependencies.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ final class Dependencies extends DependencyProvider {
334334
registerLazySingleton<DevToolsService>(() {
335335
return DevToolsService(
336336
get<DevToolsRepository>(),
337+
get<AppConfig>(),
337338
);
338339
});
339340
}

catalyst_voices/apps/voices/lib/pages/dev_tools/dev_tools_page.dart

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import 'package:catalyst_voices/pages/dev_tools/widgets/app_info_card.dart';
2+
import 'package:catalyst_voices/pages/dev_tools/widgets/config_card.dart';
3+
import 'package:catalyst_voices/pages/dev_tools/widgets/gateway_info_card.dart';
4+
import 'package:catalyst_voices/pages/dev_tools/widgets/x_close_button.dart';
15
import 'package:catalyst_voices/widgets/widgets.dart';
6+
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
27
import 'package:flutter/material.dart';
38

49
class DevToolsPage extends StatefulWidget {
@@ -26,9 +31,25 @@ class DevToolsPage extends StatefulWidget {
2631
class _DevToolsPageState extends State<DevToolsPage> {
2732
@override
2833
Widget build(BuildContext context) {
29-
return const Scaffold(
30-
appBar: VoicesAppBar(),
31-
body: SizedBox.expand(child: Placeholder(child: Center(child: Text('DevTools')))),
34+
return Scaffold(
35+
appBar: const VoicesAppBar(leading: XCloseButton()),
36+
body: ListView(
37+
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
38+
children: const [
39+
AppInfoCard(),
40+
SizedBox(height: 12),
41+
GatewayInfoCard(),
42+
SizedBox(height: 12),
43+
ConfigCard(),
44+
],
45+
),
3246
);
3347
}
48+
49+
@override
50+
void initState() {
51+
super.initState();
52+
53+
context.read<DevToolsBloc>().add(const UpdateSystemInfoEvent());
54+
}
3455
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import 'package:catalyst_voices/pages/dev_tools/widgets/build_mode_text.dart';
2+
import 'package:catalyst_voices/pages/dev_tools/widgets/build_number_text.dart';
3+
import 'package:catalyst_voices/pages/dev_tools/widgets/info_card.dart';
4+
import 'package:catalyst_voices/pages/dev_tools/widgets/value_text.dart';
5+
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
6+
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
7+
import 'package:flutter/material.dart';
8+
9+
class AppInfoCard extends StatelessWidget {
10+
const AppInfoCard({super.key});
11+
12+
@override
13+
Widget build(BuildContext context) {
14+
return BlocSelector<DevToolsBloc, DevToolsState, AppInfo?>(
15+
selector: (state) => state.systemInfo?.app,
16+
builder: (context, state) {
17+
return _AppInfoCard(
18+
version: state?.version,
19+
buildNumber: state?.buildNumber,
20+
);
21+
},
22+
);
23+
}
24+
}
25+
26+
class _AppInfoCard extends StatelessWidget {
27+
final String? version;
28+
final String? buildNumber;
29+
30+
const _AppInfoCard({
31+
this.version,
32+
this.buildNumber,
33+
});
34+
35+
@override
36+
Widget build(BuildContext context) {
37+
return InfoCard(
38+
title: const Text('App Info'),
39+
children: [
40+
ValueText(name: const Text('Version'), value: Text(version ?? '')),
41+
ValueText(name: const Text('BuildNumber'), value: BuildNumberText(buildNumber)),
42+
const ValueText(name: Text('BuildMode'), value: BuildModeText()),
43+
],
44+
);
45+
}
46+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'package:flutter/material.dart';
3+
4+
class BuildModeText extends StatelessWidget {
5+
const BuildModeText({super.key});
6+
7+
@override
8+
Widget build(BuildContext context) {
9+
final buffer = StringBuffer();
10+
11+
final mode = switch (true) {
12+
_ when kReleaseMode => 'Release',
13+
_ when kProfileMode => 'Profile',
14+
_ => 'Debug',
15+
};
16+
17+
buffer
18+
..write(mode)
19+
..write(', Web[$kIsWeb]')
20+
..write(', Wasm[$kIsWasm]');
21+
22+
return Text(buffer.toString());
23+
}
24+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import 'package:flutter/material.dart';
2+
3+
class BuildNumberText extends StatefulWidget {
4+
final String? data;
5+
6+
const BuildNumberText(
7+
this.data, {
8+
super.key,
9+
});
10+
11+
@override
12+
State<BuildNumberText> createState() => _BuildNumberTextState();
13+
}
14+
15+
class _BuildNumberTextState extends State<BuildNumberText> {
16+
DateTime? _dateTime;
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
final buffer = StringBuffer(widget.data ?? '-');
21+
22+
final dateTime = _dateTime;
23+
if (dateTime != null) {
24+
buffer.write(' -> DateTime[${dateTime.toIso8601String()}]');
25+
}
26+
27+
return Text(buffer.toString());
28+
}
29+
30+
@override
31+
void didUpdateWidget(BuildNumberText oldWidget) {
32+
super.didUpdateWidget(oldWidget);
33+
34+
if (widget.data != oldWidget.data) {
35+
_dateTime = _tryParsingAsDateTime();
36+
}
37+
}
38+
39+
@override
40+
void initState() {
41+
super.initState();
42+
_dateTime = _tryParsingAsDateTime();
43+
}
44+
45+
DateTime? _tryParsingAsDateTime() {
46+
final seconds = int.tryParse(widget.data ?? '');
47+
// one is default value from pubspec.yaml
48+
if (seconds == null || seconds == 1) {
49+
return null;
50+
}
51+
52+
return DateTime.fromMillisecondsSinceEpoch(seconds * 1000);
53+
}
54+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart';
2+
import 'package:catalyst_voices/pages/dev_tools/widgets/info_card.dart';
3+
import 'package:catalyst_voices/pages/dev_tools/widgets/value_text.dart';
4+
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
5+
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
6+
import 'package:catalyst_voices_shared/catalyst_voices_shared.dart';
7+
import 'package:flutter/material.dart';
8+
9+
class ConfigCard extends StatelessWidget {
10+
const ConfigCard({super.key});
11+
12+
@override
13+
Widget build(BuildContext context) {
14+
return BlocSelector<DevToolsBloc, DevToolsState, AppConfig?>(
15+
selector: (state) => state.systemInfo?.config,
16+
builder: (context, state) {
17+
return _ConfigCard(
18+
// TODO(damian-molinski): change it after #2135 is merged.
19+
env: 'dev',
20+
gatewayUrl: state?.api.gatewayUrl,
21+
reviewsUrl: state?.api.reviewsUrl,
22+
networkId: state?.blockchain.networkId,
23+
host: state?.blockchain.host,
24+
// TODO(damian-molinski): use DTO after #2135 is merged.
25+
transactionBuilderConfig: state?.blockchain.transactionBuilderConfig.asMap(),
26+
);
27+
},
28+
);
29+
}
30+
}
31+
32+
class _ConfigCard extends StatelessWidget {
33+
// TODO(damian-molinski): change it after #2135 is merged.
34+
final String? env;
35+
final String? gatewayUrl;
36+
final String? reviewsUrl;
37+
final NetworkId? networkId;
38+
final CatalystIdHost? host;
39+
final Map<String, dynamic>? transactionBuilderConfig;
40+
41+
const _ConfigCard({
42+
this.env,
43+
this.gatewayUrl,
44+
this.reviewsUrl,
45+
this.networkId,
46+
this.host,
47+
this.transactionBuilderConfig,
48+
});
49+
50+
@override
51+
Widget build(BuildContext context) {
52+
return InfoCard(
53+
title: const Text('Config'),
54+
children: [
55+
ValueText(name: const Text('Env'), value: Text(env ?? '-')),
56+
ValueText(name: const Text('Gateway'), value: Text(gatewayUrl ?? '-')),
57+
ValueText(name: const Text('Reviews'), value: Text(reviewsUrl ?? '-')),
58+
ValueText(name: const Text('NetworkId'), value: Text(networkId?.name ?? '-')),
59+
ValueText(name: const Text('Host'), value: Text(host?.name ?? '-')),
60+
ValueText(
61+
name: const Text('TransactionBuilderConfig'),
62+
value: Text('${transactionBuilderConfig ?? {}}'),
63+
),
64+
],
65+
);
66+
}
67+
}
68+
69+
extension on TransactionBuilderConfig {
70+
Map<String, dynamic> asMap() {
71+
return {
72+
'feeAlgo': {
73+
'constant': feeAlgo.constant,
74+
'coefficient': feeAlgo.coefficient,
75+
'multiplier': feeAlgo.multiplier,
76+
'sizeIncrement': feeAlgo.sizeIncrement,
77+
'refScriptByteCost': feeAlgo.refScriptByteCost,
78+
'maxRefScriptSize': feeAlgo.maxRefScriptSize,
79+
},
80+
'maxTxSize': maxTxSize,
81+
'maxValueSize': maxValueSize,
82+
'coinsPerUtxoByte': CryptocurrencyFormatter.formatExactAmount(coinsPerUtxoByte),
83+
'selectionStrategy': selectionStrategy.runtimeType.toString(),
84+
};
85+
}
86+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import 'package:catalyst_voices/pages/dev_tools/widgets/info_card.dart';
2+
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
3+
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class GatewayInfoCard extends StatelessWidget {
7+
const GatewayInfoCard({super.key});
8+
9+
@override
10+
Widget build(BuildContext context) {
11+
return BlocSelector<DevToolsBloc, DevToolsState, GatewayInfo?>(
12+
selector: (state) => state.systemInfo?.gateway,
13+
builder: (context, state) => const _GatewayInfoCard(),
14+
);
15+
}
16+
}
17+
18+
class _GatewayInfoCard extends StatelessWidget {
19+
const _GatewayInfoCard();
20+
21+
@override
22+
Widget build(BuildContext context) {
23+
return const InfoCard(
24+
title: Text('Gateway Info'),
25+
children: [],
26+
);
27+
}
28+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import 'package:catalyst_voices/common/ext/build_context_ext.dart';
2+
import 'package:flutter/material.dart';
3+
4+
class InfoCard extends StatelessWidget {
5+
final Widget title;
6+
final List<Widget> children;
7+
8+
const InfoCard({
9+
super.key,
10+
required this.title,
11+
required this.children,
12+
});
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return Container(
17+
decoration: BoxDecoration(
18+
border: Border.all(),
19+
borderRadius: BorderRadius.circular(8),
20+
color: context.colors.elevationsOnSurfaceNeutralLv1White,
21+
),
22+
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
23+
child: Column(
24+
mainAxisSize: MainAxisSize.min,
25+
crossAxisAlignment: CrossAxisAlignment.start,
26+
children: [
27+
_Title(child: title),
28+
const SizedBox(height: 12),
29+
Column(
30+
mainAxisSize: MainAxisSize.min,
31+
crossAxisAlignment: CrossAxisAlignment.start,
32+
spacing: 8,
33+
children: children,
34+
),
35+
],
36+
),
37+
);
38+
}
39+
}
40+
41+
class _Title extends StatelessWidget {
42+
final Widget child;
43+
44+
const _Title({
45+
required this.child,
46+
});
47+
48+
@override
49+
Widget build(BuildContext context) {
50+
return DefaultTextStyle(
51+
style: (context.textTheme.titleLarge ?? const TextStyle())
52+
.copyWith(color: context.colors.textPrimary),
53+
child: child,
54+
);
55+
}
56+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import 'package:catalyst_voices/common/ext/build_context_ext.dart';
2+
import 'package:flutter/material.dart';
3+
4+
class ValueText extends StatelessWidget {
5+
final Widget name;
6+
final Widget? value;
7+
8+
const ValueText({
9+
super.key,
10+
required this.name,
11+
this.value,
12+
});
13+
14+
@override
15+
Widget build(BuildContext context) {
16+
return DefaultTextStyle(
17+
style: context.textTheme.bodyMedium ?? const TextStyle(),
18+
child: Row(
19+
mainAxisSize: MainAxisSize.min,
20+
children: [
21+
name,
22+
const Text(': '),
23+
Flexible(
24+
child: SelectionArea(
25+
child: DefaultTextStyle.merge(
26+
style: const TextStyle(fontWeight: FontWeight.bold),
27+
child: value ?? const Text('-'),
28+
),
29+
),
30+
),
31+
],
32+
),
33+
);
34+
}
35+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'dart:async';
2+
3+
import 'package:catalyst_voices/widgets/widgets.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class XCloseButton extends StatelessWidget {
7+
const XCloseButton({super.key});
8+
9+
@override
10+
Widget build(BuildContext context) {
11+
return XButton(
12+
onTap: () => unawaited(Navigator.of(context).maybePop()),
13+
);
14+
}
15+
}

0 commit comments

Comments
 (0)