mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-26 06:08:40 +01:00
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:
co-authored by
Robert Malikowski
parent
e6969d868c
commit
a8a70f5bb9
@@ -1,6 +1,5 @@
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
|
||||
class ModalHeader extends StatelessWidget {
|
||||
const ModalHeader(
|
||||
@@ -17,38 +16,49 @@ class ModalHeader extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(16)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
spacing: 10,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: iconPath, width: 36, height: 36),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Text(
|
||||
message,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
spacing: 10,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: iconPath, width: 36, height: 36),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
textAlign: TextAlign.center,
|
||||
)),
|
||||
if(bottomWidget != null) ...[
|
||||
Padding(padding: EdgeInsets.symmetric(horizontal: 18), child: Container(height:1, color: Theme.of(context).colorScheme.surfaceContainerHigh),),
|
||||
bottomWidget!
|
||||
]
|
||||
],
|
||||
),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Text(
|
||||
message,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
textAlign: TextAlign.center,
|
||||
)),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
if (bottomWidget != null) ...[
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 18),
|
||||
child:
|
||||
Container(height: 1, color: Theme.of(context).colorScheme.surfaceContainerHigh),
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.vertical(bottom: Radius.circular(16)),
|
||||
child: bottomWidget!)
|
||||
]
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -19,20 +19,21 @@ part 'node_list_view_model.g.dart';
|
||||
|
||||
class NodeSpeed {
|
||||
final String iconPath;
|
||||
final String darkIconPath;
|
||||
|
||||
// fraction of best node ping needed to be classified as this speed.
|
||||
final double treshold;
|
||||
|
||||
const NodeSpeed._(this.iconPath, this.treshold);
|
||||
const NodeSpeed._(this.iconPath, this.darkIconPath, this.treshold);
|
||||
|
||||
static const disconnected = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/disconnected.svg", 0);
|
||||
"assets/new-ui/node_speed_badges/disconnected.svg", "assets/new-ui/node_speed_badges/disconnected-dark.svg", 0);
|
||||
static const slow = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/slow.svg", 0);
|
||||
"assets/new-ui/node_speed_badges/slow.svg", "assets/new-ui/node_speed_badges/slow-dark.svg", 0);
|
||||
static const medium = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/medium.svg", 0.5);
|
||||
"assets/new-ui/node_speed_badges/medium.svg", "assets/new-ui/node_speed_badges/medium.svg", 0.5);
|
||||
static const fast = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/fast.svg", 0.8);
|
||||
"assets/new-ui/node_speed_badges/fast.svg", "assets/new-ui/node_speed_badges/fast.svg", 0.8);
|
||||
|
||||
static const all = [fast, medium, slow, disconnected];
|
||||
}
|
||||
|
||||
@@ -162,6 +162,8 @@ abstract class ConnectionSyncViewModelBase with Store {
|
||||
@action
|
||||
void setUseBlinkProtection(bool value) => _settingsStore.useBlinkProtection = value;
|
||||
|
||||
bool get hasRescan => _wallet.hasRescan && _wallet.type != WalletType.bitcoin && _wallet.type != WalletType.litecoin;
|
||||
|
||||
@action
|
||||
void setUseEtherscan(bool value) {
|
||||
_settingsStore.useEtherscan = value;
|
||||
|
||||
Reference in New Issue
Block a user