Node UI Fixes (#3275)

* UI fixes, updated icons, and temporarily revert Rescan button * readd ping test button to node list, readd rescan to connections, fixup ui * increase gap for node edit button * remove rescan from connections for sp * remove rescan from connections for mweb --------- Co-authored-by: Robert Malikowski <malikowskirobert@gmail.com>

tuxsudo committed Jun 2, 2026 at 13:45 UTC a8a70f5bb9490684f570c6ead3cd685f0cb4915b
15 files changed +186 -133
cw_monero/pubspec.lock
+1 -1
@@ -592,7 +592,7 @@ packages:
592 path: "impls/monero.dart"
593 ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
594 resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
595 - url: "http://github.com/mrcyjanek/monero_c.git"
595 + url: "https://github.com/mrcyjanek/monero_c.git"
596 source: git
597 version: "0.0.0"
598 mutex:
cw_wownero/pubspec.lock
+1 -1
@@ -504,7 +504,7 @@ packages:
504 path: "impls/monero.dart"
505 ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
506 resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
507 - url: "http://github.com/mrcyjanek/monero_c.git"
507 + url: "https://github.com/mrcyjanek/monero_c.git"
508 source: git
509 version: "0.0.0"
510 mutex:
cw_zano/pubspec.lock
+1 -1
@@ -509,7 +509,7 @@ packages:
509 path: "impls/monero.dart"
510 ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
511 resolved-ref: "3bfb3856a838f2bf6b729501837bb0295dedf25d"
512 - url: "http://github.com/mrcyjanek/monero_c.git"
512 + url: "https://github.com/mrcyjanek/monero_c.git"
513 source: git
514 version: "0.0.0"
515 nested:
lib/new-ui/widgets/modal_header.dart
+41 -31
@@ -1,6 +1,5 @@
1 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
2 import 'package:flutter/material.dart';
3 -import 'package:flutter_svg/svg.dart';
3
4 class ModalHeader extends StatelessWidget {
5 const ModalHeader(
@@ -17,38 +16,49 @@ class ModalHeader extends StatelessWidget {
16 decoration: BoxDecoration(
17 color: Theme.of(context).colorScheme.surfaceContainer,
18 borderRadius: BorderRadius.circular(16)),
20 - child: Padding(
21 - padding: const EdgeInsets.all(12.0),
22 - child: Column(
23 - spacing: 10,
24 - mainAxisAlignment: MainAxisAlignment.center,
25 - crossAxisAlignment: CrossAxisAlignment.center,
26 - children: [
27 - CakeImageWidget(
28 - imageUrl: iconPath, width: 36, height: 36),
29 - Text(
30 - title,
31 - style: TextStyle(
32 - fontSize: 16,
33 - fontWeight: FontWeight.w500,
34 - color: Theme.of(context).colorScheme.onSurface),
19 + child: Column(
20 + children: [
21 + Padding(
22 + padding: const EdgeInsets.all(12.0),
23 + child: Column(
24 + spacing: 10,
25 + mainAxisAlignment: MainAxisAlignment.center,
26 + crossAxisAlignment: CrossAxisAlignment.center,
27 + children: [
28 + CakeImageWidget(
29 + imageUrl: iconPath, width: 36, height: 36),
30 + Text(
31 + title,
32 + style: TextStyle(
33 + fontSize: 16,
34 + fontWeight: FontWeight.w500,
35 + color: Theme.of(context).colorScheme.onSurface),
36 + ),
37 + Padding(
38 + padding: EdgeInsets.symmetric(horizontal: 32),
39 + child: Text(
40 + message,
41 + style: TextStyle(
42 + fontSize: 12,
43 + fontWeight: FontWeight.w400,
44 + color: Theme.of(context).colorScheme.onSurfaceVariant),
45 + textAlign: TextAlign.center,
46 + )),
47 +
48 + ],
49 ),
50 + ),
51 + if (bottomWidget != null) ...[
52 Padding(
37 - padding: EdgeInsets.symmetric(horizontal: 32),
38 - child: Text(
39 - message,
40 - style: TextStyle(
41 - fontSize: 12,
42 - fontWeight: FontWeight.w400,
43 - color: Theme.of(context).colorScheme.onSurfaceVariant),
44 - textAlign: TextAlign.center,
45 - )),
46 - if(bottomWidget != null) ...[
47 - Padding(padding: EdgeInsets.symmetric(horizontal: 18), child: Container(height:1, color: Theme.of(context).colorScheme.surfaceContainerHigh),),
48 - bottomWidget!
49 - ]
50 - ],
51 - ),
53 + padding: EdgeInsets.symmetric(horizontal: 18),
54 + child:
55 + Container(height: 1, color: Theme.of(context).colorScheme.surfaceContainerHigh),
56 + ),
57 + ClipRRect(
58 + borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),
59 + child: bottomWidget!)
60 + ]
61 + ],
62 ),
63 );
64 }
lib/src/screens/nodes/widgets/node_list_row.dart
+43 -29
@@ -10,7 +10,10 @@ class NodeListRow extends StatelessWidget {
10 required this.onTap,
11 required this.onEditComplete,
12 required this.isSelected,
13 - required this.isPow, this.speed});
13 + required this.isPow,
14 + this.speed,
15 + this.vertical = 10.0,
16 + this.horizontal = 12.0});
17
18 final Node node;
19 final bool isPow;
@@ -18,6 +21,8 @@ class NodeListRow extends StatelessWidget {
21 final Future<void> Function(Object?) onEditComplete;
22 final bool isSelected;
23 final NodeSpeed? speed;
24 + final double vertical;
25 + final double horizontal;
26
27 @override
28 Widget build(BuildContext context) {
@@ -26,32 +31,34 @@ class NodeListRow extends StatelessWidget {
31
32 final hasLabel = node.label != null && node.label!.isNotEmpty;
33 final uriText = "${node.uri.host}:${node.uri.port}";
29 - return GestureDetector(
30 - behavior: HitTestBehavior.opaque,
31 - onTap: onTap,
32 - child: Padding(
33 - padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 12),
34 - child: Row(
35 - spacing: 12,
36 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
37 - children: <Widget>[
38 - leading,
39 - Expanded(
40 - child: Column(crossAxisAlignment:CrossAxisAlignment.start,spacing:4,children: [
41 - Row(
42 - spacing: 4,
43 - mainAxisAlignment: MainAxisAlignment.start,
44 - children: [
45 - Text(hasLabel ? node.label! : uriText, style: TextStyle(fontSize: 12),),
46 - if(badgePath != null)
47 - CakeImageWidget(imageUrl: badgePath, colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary,BlendMode.srcIn),)
48 - ],
49 - ),
50 - if(hasLabel) Text(uriText, style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),),
51 - ],),
52 - ),
53 - trailing,
54 - ],
34 + return Material(
35 + color: Colors.transparent,
36 + child: InkWell(
37 + onTap: onTap,
38 + child: Padding(
39 + padding: EdgeInsets.symmetric(vertical: vertical, horizontal: horizontal),
40 + child: Row(
41 + spacing: 12,
42 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
43 + children: <Widget>[
44 + leading,
45 + Expanded(
46 + child: Column(crossAxisAlignment:CrossAxisAlignment.start,spacing:4,children: [
47 + Row(
48 + spacing: 4,
49 + mainAxisAlignment: MainAxisAlignment.start,
50 + children: [
51 + Text(hasLabel ? node.label! : uriText, style: TextStyle(fontSize: 12),),
52 + if(badgePath != null)
53 + CakeImageWidget(imageUrl: badgePath, colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary,BlendMode.srcIn),)
54 + ],
55 + ),
56 + if(hasLabel) Text(uriText, style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),),
57 + ],),
58 + ),
59 + trailing,
60 + ],
61 + ),
62 ),
63 ),
64 );
@@ -71,7 +78,14 @@ class NodeListRow extends StatelessWidget {
78 Widget buildTrailing(BuildContext context) {
79 return Row(
80 children: [
74 - if (speed != null) CakeImageWidget(imageUrl: speed!.iconPath, width: 24, height: 24),
81 + if (speed != null)
82 + CakeImageWidget(
83 + imageUrl: Theme.of(context).brightness == Brightness.dark
84 + ? speed!.darkIconPath
85 + : speed!.iconPath,
86 + width: 24,
87 + height: 24,
88 + ),
89 GestureDetector(
90 behavior: HitTestBehavior.opaque,
91 onTap: () async {
@@ -80,7 +94,7 @@ class NodeListRow extends StatelessWidget {
94 await onEditComplete(res);
95 },
96 child: Padding(
83 - padding: const EdgeInsets.symmetric(horizontal: 8.0),
97 + padding: const EdgeInsets.only(right: 8.0, left: 12.0),
98 child: CakeImageWidget(
99 imageUrl: "assets/new-ui/3dots_vertical.svg",
100 colorFilter:
lib/src/screens/settings/connection_sync_page.dart
+6
@@ -208,6 +208,12 @@ class ConnectionSyncPage extends BasePage {
208 label: S.of(context).domain_looks_up,
209 onTap: () => Navigator.of(context).pushNamed(Routes.domainLookupsPage)
210 ),
211 + if(_connectionSyncViewModel.hasRescan)
212 + ListItemRegularRow(
213 + keyValue: "rescan",
214 + label: S.of(context).rescan,
215 + onTap: ()=>Navigator.of(context).pushNamed(Routes.rescan)
216 + )
217 ],
218 }
219 )
lib/src/screens/settings/manage_nodes_page.dart
+60 -55
@@ -71,6 +71,8 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
71 title: S.of(context).nodes,
72 bottomWidget: Observer(
73 builder: (_) => NodeListRow(
74 + // vertical: 0,
75 + // horizontal: 0,
76 node: widget.nodeListViewModel.currentNode,
77 speed: widget.nodeListViewModel.nodeSpeedFor(widget.nodeListViewModel.currentNode),
78 onEditComplete: (res)async{
@@ -90,63 +92,66 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
92 decoration: BoxDecoration(
93 color: Theme.of(context).colorScheme.surfaceContainer,
94 borderRadius: BorderRadius.circular(18)),
93 - child: Observer(
94 - builder: (BuildContext context) {
95 - int itemsCount = widget.nodeListViewModel.nonCurrentNodes.length;
96 - return ListView.separated(
97 - controller: ModalScrollController.of(context),
98 - shrinkWrap: true,
99 - physics: BouncingScrollPhysics(),
100 - itemCount: itemsCount,
101 - separatorBuilder: (context, index) => Padding(
102 - padding: EdgeInsets.symmetric(horizontal: 12),
103 - child: Container(
104 - height: 1,
105 - color: Theme.of(context).colorScheme.surfaceContainerHigh,
95 + child: ClipRRect(
96 + borderRadius: BorderRadius.circular(18),
97 + child: Observer(
98 + builder: (BuildContext context) {
99 + int itemsCount = widget.nodeListViewModel.nonCurrentNodes.length;
100 + return ListView.separated(
101 + controller: ModalScrollController.of(context),
102 + shrinkWrap: true,
103 + physics: BouncingScrollPhysics(),
104 + itemCount: itemsCount,
105 + separatorBuilder: (context, index) => Padding(
106 + padding: EdgeInsets.symmetric(horizontal: 12),
107 + child: Container(
108 + height: 1,
109 + color: Theme.of(context).colorScheme.surfaceContainerHigh,
110 + ),
111 ),
107 - ),
108 - itemBuilder: (_, index) {
109 - return Observer(
110 - builder: (context) {
111 - final node = widget.nodeListViewModel.nonCurrentNodes[index];
112 - final nodeListRow = NodeListRow(
113 - node: node,
114 - isSelected: false,
115 - isPow: widget.isPow,
116 - speed: widget.nodeListViewModel.nodeSpeedFor(node),
117 - onEditComplete: (res) async {
118 - if(res != null && res is Node) {
119 - widget.nodeListViewModel.nodes.removeWhere((item)=>item.id == res.id);
120 - widget.nodeListViewModel.nodes.add(res);
121 - }
112 + itemBuilder: (_, index) {
113 + return Observer(
114 + builder: (context) {
115 + final node = widget.nodeListViewModel.nonCurrentNodes[index];
116 + final nodeListRow = NodeListRow(
117 + node: node,
118 + isSelected: false,
119 + isPow: widget.isPow,
120 + speed: widget.nodeListViewModel.nodeSpeedFor(node),
121 + onEditComplete: (res) async {
122 + if(res != null && res is Node) {
123 + widget.nodeListViewModel.nodes.removeWhere((item)=>item.id == res.id);
124 + widget.nodeListViewModel.nodes.add(res);
125 + }
126
123 - },
124 - onTap: () async {
125 - await showPopUp<void>(
126 - context: context,
127 - builder: (BuildContext context) {
128 - return AlertWithTwoActions(
129 - alertTitle: S.of(context).change_current_node_title,
130 - alertContent:
131 - widget.nodeListViewModel.getAlertContent(node.uriRaw),
132 - leftButtonText: S.of(context).cancel,
133 - rightButtonText: S.of(context).change,
134 - actionLeftButton: () => Navigator.of(context).pop(),
135 - actionRightButton: () async {
136 - await widget.nodeListViewModel.setAsCurrent(node);
137 - Navigator.of(context).pop();
138 - },
139 - );
140 - },
141 - );
142 - },
143 - );
144 - return nodeListRow;
145 - },
146 - );
147 - },
148 - );
149 - },
127 + },
128 + onTap: () async {
129 + await showPopUp<void>(
130 + context: context,
131 + builder: (BuildContext context) {
132 + return AlertWithTwoActions(
133 + alertTitle: S.of(context).change_current_node_title,
134 + alertContent:
135 + widget.nodeListViewModel.getAlertContent(node.uriRaw),
136 + leftButtonText: S.of(context).cancel,
137 + rightButtonText: S.of(context).change,
138 + actionLeftButton: () => Navigator.of(context).pop(),
139 + actionRightButton: () async {
140 + await widget.nodeListViewModel.setAsCurrent(node);
141 + Navigator.of(context).pop();
142 + },
143 + );
144 + },
145 + );
146 + },
147 + );
148 + return nodeListRow;
149 + },
150 + );
151 + },
152 + );
153 + },
154 + ),
155 ),
156 ),
157 ],
lib/view_model/node_list/node_list_view_model.dart
+6 -5
@@ -19,20 +19,21 @@ part 'node_list_view_model.g.dart';
19
20 class NodeSpeed {
21 final String iconPath;
22 + final String darkIconPath;
23
24 // fraction of best node ping needed to be classified as this speed.
25 final double treshold;
26
26 - const NodeSpeed._(this.iconPath, this.treshold);
27 + const NodeSpeed._(this.iconPath, this.darkIconPath, this.treshold);
28
29 static const disconnected = NodeSpeed._(
29 - "assets/new-ui/node_speed_badges/disconnected.svg", 0);
30 + "assets/new-ui/node_speed_badges/disconnected.svg", "assets/new-ui/node_speed_badges/disconnected-dark.svg", 0);
31 static const slow = NodeSpeed._(
31 - "assets/new-ui/node_speed_badges/slow.svg", 0);
32 + "assets/new-ui/node_speed_badges/slow.svg", "assets/new-ui/node_speed_badges/slow-dark.svg", 0);
33 static const medium = NodeSpeed._(
33 - "assets/new-ui/node_speed_badges/medium.svg", 0.5);
34 + "assets/new-ui/node_speed_badges/medium.svg", "assets/new-ui/node_speed_badges/medium.svg", 0.5);
35 static const fast = NodeSpeed._(
35 - "assets/new-ui/node_speed_badges/fast.svg", 0.8);
36 + "assets/new-ui/node_speed_badges/fast.svg", "assets/new-ui/node_speed_badges/fast.svg", 0.8);
37
38 static const all = [fast, medium, slow, disconnected];
39 }
lib/view_model/settings/connection_sync_view_model.dart
+2
@@ -162,6 +162,8 @@ abstract class ConnectionSyncViewModelBase with Store {
162 @action
163 void setUseBlinkProtection(bool value) => _settingsStore.useBlinkProtection = value;
164
165 + bool get hasRescan => _wallet.hasRescan && _wallet.type != WalletType.bitcoin && _wallet.type != WalletType.litecoin;
166 +
167 @action
168 void setUseEtherscan(bool value) {
169 _settingsStore.useEtherscan = value;
res/pictures/node_speed_badges/disconnected-dark.svg new
+6
@@ -0,0 +1,6 @@
1 +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<path opacity="0.35" d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625Z" fill="#D7E2F7"/>
3 +<path opacity="0.35" d="M14 15.4141V18.5C14 18.9166 13.8541 19.2709 13.5625 19.5625C13.2709 19.8541 12.9166 20 12.5 20C12.0834 20 11.7291 19.8541 11.4375 19.5625C11.1459 19.2709 11 18.9166 11 18.5V12.4141L14 15.4141Z" fill="#D7E2F7"/>
4 +<rect x="3" y="4.41406" width="2" height="24" rx="1" transform="rotate(-45 3 4.41406)" fill="#FFB4AB"/>
5 +<path opacity="0.35" d="M18.5 4C18.9166 4.00004 19.2709 4.14587 19.5625 4.4375C19.8541 4.72914 20 5.0834 20 5.5V18.5C20 18.5277 19.9974 18.555 19.9961 18.582L17 15.586V5.5C17 5.08333 17.1458 4.72917 17.4375 4.4375C17.7292 4.14585 18.0833 4 18.5 4Z" fill="#D7E2F7"/>
6 +</svg>
res/pictures/node_speed_badges/disconnected.svg
+4 -2
@@ -1,4 +1,6 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625ZM11.4375 19.5625C11.1458 19.2708 11 18.9167 11 18.5V10.5C11 10.0833 11.1458 9.72917 11.4375 9.4375C11.7292 9.14583 12.0833 9 12.5 9C12.9167 9 13.2708 9.14583 13.5625 9.4375C13.8542 9.72917 14 10.0833 14 10.5V18.5C14 18.9167 13.8542 19.2708 13.5625 19.5625C13.2708 19.8542 12.9167 20 12.5 20C12.0833 20 11.7292 19.8542 11.4375 19.5625ZM17.4375 19.5625C17.1458 19.2708 17 18.9167 17 18.5V5.5C17 5.08333 17.1458 4.72917 17.4375 4.4375C17.7292 4.14583 18.0833 4 18.5 4C18.9167 4 19.2708 4.14583 19.5625 4.4375C19.8542 4.72917 20 5.08333 20 5.5V18.5C20 18.9167 19.8542 19.2708 19.5625 19.5625C19.2708 19.8542 18.9167 20 18.5 20C18.0833 20 17.7292 19.8542 17.4375 19.5625Z" fill="#FFB4AB" fill-opacity="0.5"/>
3 - <path d="M16.4916 18.4367L14.6743 20.2178C14.4363 20.4552 14.1388 20.5794 13.7818 20.5902C13.4249 20.601 13.1166 20.4768 12.857 20.2178C12.619 19.9803 12.5 19.678 12.5 19.311C12.5 18.944 12.619 18.6418 12.857 18.4043L14.6743 16.5908L12.857 14.7773C12.619 14.5399 12.5 14.2376 12.5 13.8706C12.5 13.5036 12.619 13.2014 12.857 12.9639C13.0949 12.7264 13.3978 12.6077 13.7656 12.6077C14.1334 12.6077 14.4363 12.7264 14.6743 12.9639L16.4916 14.7773L18.3089 12.9639C18.5468 12.7264 18.8443 12.6023 19.2013 12.5915C19.5583 12.5807 19.8665 12.7048 20.1262 12.9639C20.3641 13.2014 20.4831 13.5036 20.4831 13.8706C20.4831 14.2376 20.3641 14.5399 20.1262 14.7773L18.3413 16.5908L20.1262 18.4043C20.3641 18.6418 20.4885 18.9386 20.4994 19.2948C20.5102 19.6511 20.3858 19.9587 20.1262 20.2178C19.8882 20.4552 19.5853 20.574 19.2175 20.574C18.8497 20.574 18.5468 20.4552 18.3089 20.2178L16.4916 18.4367Z" fill="white"/>
2 +<path opacity="0.35" d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625Z" fill="#1C1B1C"/>
3 +<path opacity="0.35" d="M14 15.4141V18.5C14 18.9166 13.8541 19.2709 13.5625 19.5625C13.2709 19.8541 12.9166 20 12.5 20C12.0834 20 11.7291 19.8541 11.4375 19.5625C11.1459 19.2709 11 18.9166 11 18.5V12.4141L14 15.4141Z" fill="#1C1B1C"/>
4 +<rect x="3" y="4.41406" width="2" height="24" rx="1" transform="rotate(-45 3 4.41406)" fill="#BA1A1A"/>
5 +<path opacity="0.35" d="M18.5 4C18.9166 4.00004 19.2709 4.14587 19.5625 4.4375C19.8541 4.72914 20 5.0834 20 5.5V18.5C20 18.5277 19.9974 18.5549 19.9961 18.582L17 15.586V5.5C17 5.08333 17.1458 4.72917 17.4375 4.4375C17.7292 4.14585 18.0833 4 18.5 4Z" fill="#1C1B1C"/>
6 </svg>
res/pictures/node_speed_badges/fast.svg
+1 -1
@@ -1,3 +1,3 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625ZM11.4375 19.5625C11.1458 19.2708 11 18.9167 11 18.5V10.5C11 10.0833 11.1458 9.72917 11.4375 9.4375C11.7292 9.14583 12.0833 9 12.5 9C12.9167 9 13.2708 9.14583 13.5625 9.4375C13.8542 9.72917 14 10.0833 14 10.5V18.5C14 18.9167 13.8542 19.2708 13.5625 19.5625C13.2708 19.8542 12.9167 20 12.5 20C12.0833 20 11.7292 19.8542 11.4375 19.5625ZM17.4375 19.5625C17.1458 19.2708 17 18.9167 17 18.5V5.5C17 5.08333 17.1458 4.72917 17.4375 4.4375C17.7292 4.14583 18.0833 4 18.5 4C18.9167 4 19.2708 4.14583 19.5625 4.4375C19.8542 4.72917 20 5.08333 20 5.5V18.5C20 18.9167 19.8542 19.2708 19.5625 19.5625C19.2708 19.8542 18.9167 20 18.5 20C18.0833 20 17.7292 19.8542 17.4375 19.5625Z" fill="#4DA865"/>
2 +<path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625ZM11.4375 19.5625C11.1458 19.2708 11 18.9167 11 18.5V10.5C11 10.0833 11.1458 9.72917 11.4375 9.4375C11.7292 9.14583 12.0833 9 12.5 9C12.9167 9 13.2708 9.14583 13.5625 9.4375C13.8542 9.72917 14 10.0833 14 10.5V18.5C14 18.9167 13.8542 19.2708 13.5625 19.5625C13.2708 19.8542 12.9167 20 12.5 20C12.0833 20 11.7292 19.8542 11.4375 19.5625ZM17.4375 19.5625C17.1458 19.2708 17 18.9167 17 18.5V5.5C17 5.08333 17.1458 4.72917 17.4375 4.4375C17.7292 4.14583 18.0833 4 18.5 4C18.9167 4 19.2708 4.14583 19.5625 4.4375C19.8542 4.72917 20 5.08333 20 5.5V18.5C20 18.9167 19.8542 19.2708 19.5625 19.5625C19.2708 19.8542 18.9167 20 18.5 20C18.0833 20 17.7292 19.8542 17.4375 19.5625Z" fill="#4DA865"/>
3 </svg>
res/pictures/node_speed_badges/medium.svg
+2 -2
@@ -1,4 +1,4 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625ZM11.4375 19.5625C11.1458 19.2708 11 18.9167 11 18.5V10.5C11 10.0833 11.1458 9.72917 11.4375 9.4375C11.7292 9.14583 12.0833 9 12.5 9C12.9167 9 13.2708 9.14583 13.5625 9.4375C13.8542 9.72917 14 10.0833 14 10.5V18.5C14 18.9167 13.8542 19.2708 13.5625 19.5625C13.2708 19.8542 12.9167 20 12.5 20C12.0833 20 11.7292 19.8542 11.4375 19.5625Z" fill="#FAC06A"/>
3 - <path d="M17 18.5C17 18.9167 17.1458 19.2708 17.4375 19.5625C17.7292 19.8542 18.0833 20 18.5 20C18.9167 20 19.2708 19.8542 19.5625 19.5625C19.8542 19.2708 20 18.9167 20 18.5V5.5C20 5.08333 19.8542 4.72917 19.5625 4.4375C19.2708 4.14583 18.9167 4 18.5 4C18.0833 4 17.7292 4.14583 17.4375 4.4375C17.1458 4.72917 17 5.08333 17 5.5V18.5Z" fill="#FAC06A" fill-opacity="0.5"/>
2 +<path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625ZM11.4375 19.5625C11.1458 19.2708 11 18.9167 11 18.5V10.5C11 10.0833 11.1458 9.72917 11.4375 9.4375C11.7292 9.14583 12.0833 9 12.5 9C12.9167 9 13.2708 9.14583 13.5625 9.4375C13.8542 9.72917 14 10.0833 14 10.5V18.5C14 18.9167 13.8542 19.2708 13.5625 19.5625C13.2708 19.8542 12.9167 20 12.5 20C12.0833 20 11.7292 19.8542 11.4375 19.5625Z" fill="#FFB84E"/>
3 +<path d="M17 18.5C17 18.9167 17.1458 19.2708 17.4375 19.5625C17.7292 19.8542 18.0833 20 18.5 20C18.9167 20 19.2708 19.8542 19.5625 19.5625C19.8542 19.2708 20 18.9167 20 18.5V5.5C20 5.08333 19.8542 4.72917 19.5625 4.4375C19.2708 4.14583 18.9167 4 18.5 4C18.0833 4 17.7292 4.14583 17.4375 4.4375C17.1458 4.72917 17 5.08333 17 5.5V18.5Z" fill="#FFB84E" fill-opacity="0.5"/>
4 </svg>
res/pictures/node_speed_badges/slow-dark.svg new
+7
@@ -0,0 +1,7 @@
1 +<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 +<path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625Z" fill="#FFB4AB"/>
3 +<g opacity="0.35">
4 +<path d="M11 18.5C11 18.9167 11.1458 19.2708 11.4375 19.5625C11.7292 19.8542 12.0833 20 12.5 20C12.9167 20 13.2708 19.8542 13.5625 19.5625C13.8542 19.2708 14 18.9167 14 18.5V10.5C14 10.0833 13.8542 9.72917 13.5625 9.4375C13.2708 9.14583 12.9167 9 12.5 9C12.0833 9 11.7292 9.14583 11.4375 9.4375C11.1458 9.72917 11 10.0833 11 10.5V18.5Z" fill="#FFB4AB"/>
5 +<path d="M17 18.5C17 18.9167 17.1458 19.2708 17.4375 19.5625C17.7292 19.8542 18.0833 20 18.5 20C18.9167 20 19.2708 19.8542 19.5625 19.5625C19.8542 19.2708 20 18.9167 20 18.5V5.5C20 5.08333 19.8542 4.72917 19.5625 4.4375C19.2708 4.14583 18.9167 4 18.5 4C18.0833 4 17.7292 4.14583 17.4375 4.4375C17.1458 4.72917 17 5.08333 17 5.5V18.5Z" fill="#FFB4AB"/>
6 +</g>
7 +</svg>
res/pictures/node_speed_badges/slow.svg
+5 -5
@@ -1,7 +1,7 @@
1 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2 - <path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625Z" fill="#FFB4AB"/>
3 - <g opacity="0.5">
4 - <path d="M11 18.5C11 18.9167 11.1458 19.2708 11.4375 19.5625C11.7292 19.8542 12.0833 20 12.5 20C12.9167 20 13.2708 19.8542 13.5625 19.5625C13.8542 19.2708 14 18.9167 14 18.5V10.5C14 10.0833 13.8542 9.72917 13.5625 9.4375C13.2708 9.14583 12.9167 9 12.5 9C12.0833 9 11.7292 9.14583 11.4375 9.4375C11.1458 9.72917 11 10.0833 11 10.5V18.5Z" fill="#FFB4AB"/>
5 - <path d="M17 18.5C17 18.9167 17.1458 19.2708 17.4375 19.5625C17.7292 19.8542 18.0833 20 18.5 20C18.9167 20 19.2708 19.8542 19.5625 19.5625C19.8542 19.2708 20 18.9167 20 18.5V5.5C20 5.08333 19.8542 4.72917 19.5625 4.4375C19.2708 4.14583 18.9167 4 18.5 4C18.0833 4 17.7292 4.14583 17.4375 4.4375C17.1458 4.72917 17 5.08333 17 5.5V18.5Z" fill="#FFB4AB"/>
6 - </g>
2 +<path d="M5.4375 19.5625C5.14583 19.2708 5 18.9167 5 18.5V15.5C5 15.0833 5.14583 14.7292 5.4375 14.4375C5.72917 14.1458 6.08333 14 6.5 14C6.91667 14 7.27083 14.1458 7.5625 14.4375C7.85417 14.7292 8 15.0833 8 15.5V18.5C8 18.9167 7.85417 19.2708 7.5625 19.5625C7.27083 19.8542 6.91667 20 6.5 20C6.08333 20 5.72917 19.8542 5.4375 19.5625Z" fill="#BA1A1A"/>
3 +<g opacity="0.35">
4 +<path d="M11 18.5C11 18.9167 11.1458 19.2708 11.4375 19.5625C11.7292 19.8542 12.0833 20 12.5 20C12.9167 20 13.2708 19.8542 13.5625 19.5625C13.8542 19.2708 14 18.9167 14 18.5V10.5C14 10.0833 13.8542 9.72917 13.5625 9.4375C13.2708 9.14583 12.9167 9 12.5 9C12.0833 9 11.7292 9.14583 11.4375 9.4375C11.1458 9.72917 11 10.0833 11 10.5V18.5Z" fill="#BA1A1A"/>
5 +<path d="M17 18.5C17 18.9167 17.1458 19.2708 17.4375 19.5625C17.7292 19.8542 18.0833 20 18.5 20C18.9167 20 19.2708 19.8542 19.5625 19.5625C19.8542 19.2708 20 18.9167 20 18.5V5.5C20 5.08333 19.8542 4.72917 19.5625 4.4375C19.2708 4.14583 18.9167 4 18.5 4C18.0833 4 17.7292 4.14583 17.4375 4.4375C17.1458 4.72917 17 5.08333 17 5.5V18.5Z" fill="#BA1A1A"/>
6 +</g>
7 </svg>