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>
This commit is contained in:
tuxsudo
2026-06-02 15:45:44 +02:00
committed by GitHub
co-authored by Robert Malikowski
parent e6969d868c
commit a8a70f5bb9
15 changed files with 187 additions and 134 deletions
@@ -10,7 +10,10 @@ class NodeListRow extends StatelessWidget {
required this.onTap,
required this.onEditComplete,
required this.isSelected,
required this.isPow, this.speed});
required this.isPow,
this.speed,
this.vertical = 10.0,
this.horizontal = 12.0});
final Node node;
final bool isPow;
@@ -18,6 +21,8 @@ class NodeListRow extends StatelessWidget {
final Future<void> Function(Object?) onEditComplete;
final bool isSelected;
final NodeSpeed? speed;
final double vertical;
final double horizontal;
@override
Widget build(BuildContext context) {
@@ -26,32 +31,34 @@ class NodeListRow extends StatelessWidget {
final hasLabel = node.label != null && node.label!.isNotEmpty;
final uriText = "${node.uri.host}:${node.uri.port}";
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0, horizontal: 12),
child: Row(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
leading,
Expanded(
child: Column(crossAxisAlignment:CrossAxisAlignment.start,spacing:4,children: [
Row(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(hasLabel ? node.label! : uriText, style: TextStyle(fontSize: 12),),
if(badgePath != null)
CakeImageWidget(imageUrl: badgePath, colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary,BlendMode.srcIn),)
],
),
if(hasLabel) Text(uriText, style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),),
],),
),
trailing,
],
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Padding(
padding: EdgeInsets.symmetric(vertical: vertical, horizontal: horizontal),
child: Row(
spacing: 12,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
leading,
Expanded(
child: Column(crossAxisAlignment:CrossAxisAlignment.start,spacing:4,children: [
Row(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(hasLabel ? node.label! : uriText, style: TextStyle(fontSize: 12),),
if(badgePath != null)
CakeImageWidget(imageUrl: badgePath, colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary,BlendMode.srcIn),)
],
),
if(hasLabel) Text(uriText, style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),),
],),
),
trailing,
],
),
),
),
);
@@ -71,7 +78,14 @@ class NodeListRow extends StatelessWidget {
Widget buildTrailing(BuildContext context) {
return Row(
children: [
if (speed != null) CakeImageWidget(imageUrl: speed!.iconPath, width: 24, height: 24),
if (speed != null)
CakeImageWidget(
imageUrl: Theme.of(context).brightness == Brightness.dark
? speed!.darkIconPath
: speed!.iconPath,
width: 24,
height: 24,
),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () async {
@@ -80,7 +94,7 @@ class NodeListRow extends StatelessWidget {
await onEditComplete(res);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.only(right: 8.0, left: 12.0),
child: CakeImageWidget(
imageUrl: "assets/new-ui/3dots_vertical.svg",
colorFilter:
@@ -208,6 +208,12 @@ class ConnectionSyncPage extends BasePage {
label: S.of(context).domain_looks_up,
onTap: () => Navigator.of(context).pushNamed(Routes.domainLookupsPage)
),
if(_connectionSyncViewModel.hasRescan)
ListItemRegularRow(
keyValue: "rescan",
label: S.of(context).rescan,
onTap: ()=>Navigator.of(context).pushNamed(Routes.rescan)
)
],
}
)
+60 -55
View File
@@ -71,6 +71,8 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
title: S.of(context).nodes,
bottomWidget: Observer(
builder: (_) => NodeListRow(
// vertical: 0,
// horizontal: 0,
node: widget.nodeListViewModel.currentNode,
speed: widget.nodeListViewModel.nodeSpeedFor(widget.nodeListViewModel.currentNode),
onEditComplete: (res)async{
@@ -90,63 +92,66 @@ class _ManageNodesPageState extends State<ManageNodesPage> {
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18)),
child: Observer(
builder: (BuildContext context) {
int itemsCount = widget.nodeListViewModel.nonCurrentNodes.length;
return ListView.separated(
controller: ModalScrollController.of(context),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: itemsCount,
separatorBuilder: (context, index) => Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Container(
height: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
child: ClipRRect(
borderRadius: BorderRadius.circular(18),
child: Observer(
builder: (BuildContext context) {
int itemsCount = widget.nodeListViewModel.nonCurrentNodes.length;
return ListView.separated(
controller: ModalScrollController.of(context),
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: itemsCount,
separatorBuilder: (context, index) => Padding(
padding: EdgeInsets.symmetric(horizontal: 12),
child: Container(
height: 1,
color: Theme.of(context).colorScheme.surfaceContainerHigh,
),
),
),
itemBuilder: (_, index) {
return Observer(
builder: (context) {
final node = widget.nodeListViewModel.nonCurrentNodes[index];
final nodeListRow = NodeListRow(
node: node,
isSelected: false,
isPow: widget.isPow,
speed: widget.nodeListViewModel.nodeSpeedFor(node),
onEditComplete: (res) async {
if(res != null && res is Node) {
widget.nodeListViewModel.nodes.removeWhere((item)=>item.id == res.id);
widget.nodeListViewModel.nodes.add(res);
}
itemBuilder: (_, index) {
return Observer(
builder: (context) {
final node = widget.nodeListViewModel.nonCurrentNodes[index];
final nodeListRow = NodeListRow(
node: node,
isSelected: false,
isPow: widget.isPow,
speed: widget.nodeListViewModel.nodeSpeedFor(node),
onEditComplete: (res) async {
if(res != null && res is Node) {
widget.nodeListViewModel.nodes.removeWhere((item)=>item.id == res.id);
widget.nodeListViewModel.nodes.add(res);
}
},
onTap: () async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_current_node_title,
alertContent:
widget.nodeListViewModel.getAlertContent(node.uriRaw),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () async {
await widget.nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop();
},
);
},
);
},
);
return nodeListRow;
},
);
},
);
},
},
onTap: () async {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_current_node_title,
alertContent:
widget.nodeListViewModel.getAlertContent(node.uriRaw),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () async {
await widget.nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop();
},
);
},
);
},
);
return nodeListRow;
},
);
},
);
},
),
),
),
],