mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-28 06:28:41 +01:00
new-node-list-ui-on-dev (#3259)
* node list new ui # Conflicts: # cw_core/lib/node_list.dart * increase touch target sizes * fix scroll behavior * fix concurrent modification * Update lib/src/screens/settings/manage_nodes_page.dart [skip ci] * Update lib/src/screens/nodes/node_create_or_edit_page.dart [skip ci] * run speed test in parallel not sequential --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
@@ -3,10 +3,7 @@ import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart';
|
||||
import 'package:cake_wallet/entities/qr_scanner.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/permission_handler.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@@ -20,7 +17,7 @@ class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
|
||||
|
||||
abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
NodeCreateOrEditViewModelBase(
|
||||
this.isPow, this.nodeListViewModel,this.powNodeListViewModel, this.walletType, this._settingsStore, {this.editingNode})
|
||||
this.isPow, this.walletType, this._settingsStore, {this.editingNode})
|
||||
: state = InitialExecutionState(),
|
||||
connectionState = InitialExecutionState(),
|
||||
label = editingNode?.label ?? '',
|
||||
@@ -116,8 +113,6 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
@observable
|
||||
bool isPow;
|
||||
|
||||
final NodeListViewModel? nodeListViewModel;
|
||||
final PowNodeListViewModel? powNodeListViewModel;
|
||||
|
||||
@computed
|
||||
bool get isReady =>
|
||||
@@ -257,12 +252,6 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
@action
|
||||
Future<void> delete({required Node editingNode}) async {
|
||||
await editingNode.delete();
|
||||
if(nodeListViewModel != null) {
|
||||
nodeListViewModel!.bindNodes();
|
||||
}
|
||||
if(powNodeListViewModel != null) {
|
||||
powNodeListViewModel!.bindNodes();
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -287,12 +276,6 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
}
|
||||
|
||||
state = ExecutedSuccessfullyState();
|
||||
if(nodeListViewModel != null) {
|
||||
nodeListViewModel!.bindNodes();
|
||||
}
|
||||
if(powNodeListViewModel != null) {
|
||||
powNodeListViewModel!.bindNodes();
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/node_list.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/entities/node_list.dart';
|
||||
import 'package:cake_wallet/entities/default_settings_migration.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/evm/evm.dart';
|
||||
@@ -14,11 +16,34 @@ import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
|
||||
part 'node_list_view_model.g.dart';
|
||||
|
||||
|
||||
class NodeSpeed {
|
||||
final String iconPath;
|
||||
|
||||
// fraction of best node ping needed to be classified as this speed.
|
||||
final double treshold;
|
||||
|
||||
const NodeSpeed._(this.iconPath, this.treshold);
|
||||
|
||||
static const disconnected = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/disconnected.svg", 0);
|
||||
static const slow = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/slow.svg", 0);
|
||||
static const medium = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/medium.svg", 0.5);
|
||||
static const fast = NodeSpeed._(
|
||||
"assets/new-ui/node_speed_badges/fast.svg", 0.8);
|
||||
|
||||
static const all = [fast, medium, slow, disconnected];
|
||||
}
|
||||
|
||||
|
||||
class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
|
||||
|
||||
abstract class NodeListViewModelBase with Store {
|
||||
NodeListViewModelBase(this._appStore)
|
||||
NodeListViewModelBase(this._appStore, this.isPow)
|
||||
: nodes = ObservableList<Node>(),
|
||||
_nodeSpeeds = ObservableMap<String, int>(),
|
||||
settingsStore = _appStore.settingsStore {
|
||||
bindNodes();
|
||||
|
||||
@@ -37,6 +62,7 @@ abstract class NodeListViewModelBase with Store {
|
||||
bindNodes();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@computed
|
||||
Node get currentNode {
|
||||
@@ -52,7 +78,7 @@ abstract class NodeListViewModelBase with Store {
|
||||
return settingsStore.getCurrentNode(walletType, chainId: chainId);
|
||||
}
|
||||
|
||||
final node = settingsStore.nodes[walletType];
|
||||
final node = isPow ? settingsStore.powNodes[walletType] : settingsStore.nodes[walletType];
|
||||
if (node == null) {
|
||||
throw Exception('No node for wallet type: $walletType');
|
||||
}
|
||||
@@ -73,6 +99,59 @@ abstract class NodeListViewModelBase with Store {
|
||||
final ObservableList<Node> nodes;
|
||||
final SettingsStore settingsStore;
|
||||
final AppStore _appStore;
|
||||
final bool isPow;
|
||||
final ObservableMap<String, int> _nodeSpeeds;
|
||||
|
||||
|
||||
@computed
|
||||
List<Node> get nonCurrentNodes => nodes.where((item)=>item != currentNode).toList();
|
||||
|
||||
@observable
|
||||
bool isTestingNodeSpeed = false;
|
||||
|
||||
Future<void> speedTestNodes() async {
|
||||
try {
|
||||
isTestingNodeSpeed = true;
|
||||
_nodeSpeeds.clear();
|
||||
final nodes = this.nodes.toList();
|
||||
await Future.wait(nodes.map((node) async {
|
||||
final sw = Stopwatch()..start();
|
||||
final res = await node
|
||||
.requestNode()
|
||||
.timeout(const Duration(seconds: 10), onTimeout: () => false);
|
||||
sw.stop();
|
||||
if (res) {
|
||||
_nodeSpeeds[node.uriRaw] = sw.elapsedMilliseconds;
|
||||
}
|
||||
}));
|
||||
} finally {
|
||||
isTestingNodeSpeed = false;
|
||||
}
|
||||
}
|
||||
|
||||
NodeSpeed? nodeSpeedFor(Node node) {
|
||||
final bestSpeed = _bestNodeSpeed;
|
||||
final currentSpeed = _nodeSpeeds[node.uriRaw];
|
||||
if (bestSpeed == null) {
|
||||
return null;
|
||||
}
|
||||
if (currentSpeed == null) {
|
||||
return NodeSpeed.disconnected;
|
||||
}
|
||||
for (final speed in NodeSpeed.all) {
|
||||
if (currentSpeed < (bestSpeed / speed.treshold)) return speed;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
int? get _bestNodeSpeed {
|
||||
try {
|
||||
printV(_nodeSpeeds);
|
||||
return _nodeSpeeds.values.reduce(min);
|
||||
} catch (e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> reset() async {
|
||||
await resetToDefault();
|
||||
@@ -125,7 +204,12 @@ abstract class NodeListViewModelBase with Store {
|
||||
}
|
||||
|
||||
// For non-EVM wallets, use the wallet type directly
|
||||
settingsStore.nodes[walletType] = node;
|
||||
if(isPow) {
|
||||
settingsStore.powNodes[walletType] = node;
|
||||
} else {
|
||||
settingsStore.nodes[walletType] = node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@action
|
||||
@@ -150,7 +234,7 @@ abstract class NodeListViewModelBase with Store {
|
||||
}
|
||||
|
||||
// For non-EVM wallets, use the wallet type directly
|
||||
nodes.addAll(await Node.getAllForWalletType(walletType));
|
||||
nodes.addAll(isPow ? await Node.getAllForWalletTypePow(walletType) : await Node.getAllForWalletType(walletType));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
import 'package:cw_core/node_list.dart';
|
||||
import 'package:cw_core/utils/proxy_wrapper.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/entities/node_list.dart';
|
||||
import 'package:cake_wallet/entities/default_settings_migration.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
part 'pow_node_list_view_model.g.dart';
|
||||
|
||||
class PowNodeListViewModel = PowNodeListViewModelBase with _$PowNodeListViewModel;
|
||||
|
||||
abstract class PowNodeListViewModelBase with Store {
|
||||
PowNodeListViewModelBase(this._appStore)
|
||||
: nodes = ObservableList<Node>(),
|
||||
settingsStore = _appStore.settingsStore {
|
||||
bindNodes();
|
||||
|
||||
reaction((_) => _appStore.wallet, (WalletBase? _wallet) {
|
||||
bindNodes();
|
||||
});
|
||||
}
|
||||
|
||||
@computed
|
||||
Node get currentNode {
|
||||
final node = settingsStore.powNodes[_appStore.wallet!.type];
|
||||
|
||||
if (node == null) {
|
||||
throw Exception('No node for wallet type: ${_appStore.wallet!.type}');
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
String getAlertContent(String uri) =>
|
||||
S.current.change_current_node(uri) +
|
||||
'${uri.endsWith('.onion') || uri.contains('.onion:') ? '\n' + (CakeTor.instance!.enabled ? '' : S.current.orbot_running_alert) : ''}';
|
||||
|
||||
@computed
|
||||
bool get enableAutomaticNodeSwitching => settingsStore.enableAutomaticNodeSwitching;
|
||||
|
||||
@action
|
||||
void setEnableAutomaticNodeSwitching(bool value) =>
|
||||
settingsStore.enableAutomaticNodeSwitching = value;
|
||||
|
||||
final ObservableList<Node> nodes;
|
||||
final SettingsStore settingsStore;
|
||||
final AppStore _appStore;
|
||||
|
||||
Future<void> reset() async {
|
||||
await resetPowToDefault();
|
||||
|
||||
Node node;
|
||||
|
||||
switch (_appStore.wallet!.type) {
|
||||
case WalletType.nano:
|
||||
node = (await getNanoDefaultPowNode())!;
|
||||
break;
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${_appStore.wallet!.type} for pow node list');
|
||||
}
|
||||
|
||||
await setAsCurrent(node);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> delete(Node node) async => node.delete();
|
||||
|
||||
Future<void> setAsCurrent(Node node) async =>
|
||||
settingsStore.powNodes[_appStore.wallet!.type] = node;
|
||||
|
||||
@action
|
||||
Future<void> bindNodes() async {
|
||||
nodes.clear();
|
||||
nodes.addAll(await Node.getAllPow());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user