stack_wallet/lib/widgets/node_options_sheet.dart

412 lines
14 KiB
Dart
Raw Normal View History

/*
2023-05-26 21:21:16 +00:00
* This file is part of Stack Wallet.
*
2023-05-26 21:21:16 +00:00
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
import 'dart:async';
2022-08-26 08:11:35 +00:00
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
import 'package:stackwallet/models/node_model.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
2022-12-12 21:59:06 +00:00
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart';
2022-08-26 08:11:35 +00:00
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/node_details_view.dart';
import 'package:stackwallet/providers/global/active_wallet_provider.dart';
2022-08-26 08:11:35 +00:00
import 'package:stackwallet/providers/providers.dart';
2023-09-08 16:04:56 +00:00
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/themes/stack_colors.dart';
2022-08-26 08:11:35 +00:00
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/sync_type_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/test_epic_box_connection.dart';
2023-05-30 16:38:47 +00:00
import 'package:stackwallet/utilities/test_eth_node_connection.dart';
2022-08-26 08:11:35 +00:00
import 'package:stackwallet/utilities/test_monero_node_connection.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
class NodeOptionsSheet extends ConsumerWidget {
const NodeOptionsSheet({
Key? key,
required this.nodeId,
required this.coin,
required this.popBackToRoute,
}) : super(key: key);
final String nodeId;
final Coin coin;
final String popBackToRoute;
Future<void> _notifyWalletsOfUpdatedNode(WidgetRef ref) async {
final wallets =
ref.read(pWallets).wallets.where((e) => e.info.coin == coin);
2022-08-26 08:11:35 +00:00
final prefs = ref.read(prefsChangeNotifierProvider);
switch (prefs.syncType) {
case SyncingType.currentWalletOnly:
for (final wallet in wallets) {
if (ref.read(currentWalletIdProvider) == wallet.walletId) {
unawaited(wallet.updateNode().then((value) => wallet.refresh()));
2022-08-26 08:11:35 +00:00
} else {
unawaited(wallet.updateNode());
2022-08-26 08:11:35 +00:00
}
}
break;
case SyncingType.selectedWalletsAtStartup:
final List<String> walletIdsToSync = prefs.walletIdsSyncOnStartup;
for (final wallet in wallets) {
if (walletIdsToSync.contains(wallet.walletId)) {
unawaited(wallet.updateNode().then((value) => wallet.refresh()));
2022-08-26 08:11:35 +00:00
} else {
unawaited(wallet.updateNode());
2022-08-26 08:11:35 +00:00
}
}
break;
case SyncingType.allWalletsOnStartup:
for (final wallet in wallets) {
unawaited(wallet.updateNode().then((value) => wallet.refresh()));
2022-08-26 08:11:35 +00:00
}
break;
}
}
Future<bool> _testConnection(
NodeModel node, BuildContext context, WidgetRef ref) async {
bool testPassed = false;
switch (coin) {
case Coin.epicCash:
try {
2022-12-12 21:59:06 +00:00
testPassed = await testEpicNodeConnection(
NodeFormData()
..host = node.host
..useSSL = node.useSSL
..port = node.port,
) !=
null;
2022-08-26 08:11:35 +00:00
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
}
break;
case Coin.monero:
2022-09-28 15:17:16 +00:00
case Coin.wownero:
2022-08-26 08:11:35 +00:00
try {
final uri = Uri.parse(node.host);
if (uri.scheme.startsWith("http")) {
final String path = uri.path.isEmpty ? "/json_rpc" : uri.path;
String uriString = "${uri.scheme}://${uri.host}:${node.port}$path";
2022-11-08 16:18:48 +00:00
final response = await testMoneroNodeConnection(
Uri.parse(uriString),
false,
);
if (response.cert != null) {
// if (mounted) {
final shouldAllowBadCert = await showBadX509CertificateDialog(
response.cert!,
response.url!,
response.port!,
context,
);
if (shouldAllowBadCert) {
final response =
await testMoneroNodeConnection(Uri.parse(uriString), true);
testPassed = response.success;
}
// }
} else {
testPassed = response.success;
}
2022-08-26 08:11:35 +00:00
}
} catch (e, s) {
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
}
break;
case Coin.bitcoin:
2022-10-28 21:50:40 +00:00
case Coin.litecoin:
2022-08-26 08:11:35 +00:00
case Coin.dogecoin:
case Coin.firo:
case Coin.particl:
2022-08-26 08:11:35 +00:00
case Coin.bitcoinTestNet:
case Coin.firoTestNet:
case Coin.dogecoinTestNet:
2022-09-26 20:32:53 +00:00
case Coin.bitcoincash:
2022-10-28 21:50:40 +00:00
case Coin.litecoinTestNet:
2022-09-23 21:02:53 +00:00
case Coin.namecoin:
2022-09-26 20:32:53 +00:00
case Coin.bitcoincashTestnet:
2023-05-30 16:31:49 +00:00
case Coin.eCash:
2022-08-26 08:11:35 +00:00
final client = ElectrumX(
host: node.host,
port: node.port,
useSSL: node.useSSL,
failovers: [],
prefs: ref.read(prefsChangeNotifierProvider),
2023-09-08 16:04:56 +00:00
torService: ref.read(pTorService),
2022-08-26 08:11:35 +00:00
);
try {
testPassed = await client.ping();
} catch (_) {
testPassed = false;
}
break;
2023-05-30 16:38:47 +00:00
case Coin.ethereum:
try {
testPassed = await testEthNodeConnection(node.host);
} catch (_) {
testPassed = false;
}
break;
2023-06-05 20:55:41 +00:00
case Coin.nano:
case Coin.banano:
2023-07-19 14:37:54 +00:00
case Coin.tezos:
2023-07-19 17:08:46 +00:00
case Coin.stellar:
2023-08-23 17:29:10 +00:00
case Coin.stellarTestnet:
2023-07-19 17:08:46 +00:00
throw UnimplementedError();
2023-07-28 16:50:05 +00:00
//TODO: check network/node
2022-08-26 08:11:35 +00:00
}
if (testPassed) {
// showFloatingFlushBar(
// type: FlushBarType.success,
// message: "Server ping success",
// context: context,
// );
} else {
unawaited(showFloatingFlushBar(
2022-08-26 08:11:35 +00:00
type: FlushBarType.warning,
iconAsset: Assets.svg.circleAlert,
message: "Could not connect to node",
context: context,
));
2022-08-26 08:11:35 +00:00
}
return testPassed;
}
@override
Widget build(BuildContext context, WidgetRef ref) {
final maxHeight = MediaQuery.of(context).size.height * 0.60;
final node = ref.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getNodeById(id: nodeId)))!;
final status = ref
.watch(nodeServiceChangeNotifierProvider
.select((value) => value.getPrimaryNodeFor(coin: coin)))
?.id !=
nodeId
? "Disconnected"
: "Connected";
return Container(
decoration: BoxDecoration(
color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: const BorderRadius.vertical(
2022-08-26 08:11:35 +00:00
top: Radius.circular(20),
),
),
child: LimitedBox(
maxHeight: maxHeight,
child: Padding(
padding: const EdgeInsets.only(
left: 24,
right: 24,
top: 10,
bottom: 0,
),
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
2022-08-26 08:11:35 +00:00
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
width: 60,
height: 4,
),
),
const SizedBox(
height: 36,
),
Text(
"Node options",
2022-09-22 22:17:21 +00:00
style: STextStyles.pageTitleH2(context),
2022-08-26 08:11:35 +00:00
textAlign: TextAlign.left,
),
RoundedWhiteContainer(
padding: const EdgeInsets.symmetric(vertical: 38),
child: Row(
children: [
Container(
width: 32,
height: 32,
decoration: BoxDecoration(
color: node.id
.startsWith(DefaultNodes.defaultNodeIdPrefix)
? Theme.of(context)
.extension<StackColors>()!
.textSubtitle4
: Theme.of(context)
.extension<StackColors>()!
.infoItemIcons
2022-09-21 00:46:07 +00:00
.withOpacity(0.2),
2022-08-26 08:11:35 +00:00
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: SvgPicture.asset(
Assets.svg.node,
height: 15,
width: 19,
color: node.id.startsWith(
DefaultNodes.defaultNodeIdPrefix)
? Theme.of(context)
.extension<StackColors>()!
.accentColorDark
: Theme.of(context)
.extension<StackColors>()!
.infoItemIcons,
2022-08-26 08:11:35 +00:00
),
),
),
const SizedBox(
width: 12,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
node.name,
2022-09-22 22:17:21 +00:00
style: STextStyles.titleBold12(context),
2022-08-26 08:11:35 +00:00
),
const SizedBox(
height: 2,
),
Text(
status,
2022-09-22 22:17:21 +00:00
style: STextStyles.label(context),
2022-08-26 08:11:35 +00:00
),
],
),
const Spacer(),
SvgPicture.asset(
Assets.svg.network,
color: status == "Connected"
? Theme.of(context)
.extension<StackColors>()!
.accentColorGreen
: Theme.of(context)
.extension<StackColors>()!
.buttonBackSecondary,
2022-08-26 08:11:35 +00:00
width: 18,
),
],
),
),
Row(
children: [
// if (!node.id.startsWith("default"))
Expanded(
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
2023-01-24 19:29:12 +00:00
.getSecondaryEnabledButtonStyle(context),
2022-08-26 08:11:35 +00:00
onPressed: () {
Navigator.pop(context);
Navigator.of(context).pushNamed(
NodeDetailsView.routeName,
arguments: Tuple3(
coin,
node.id,
popBackToRoute,
),
);
},
child: Text(
"Details",
2022-09-22 22:17:21 +00:00
style: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
2022-08-26 08:11:35 +00:00
),
),
),
// if (!node.id.startsWith("default"))
const SizedBox(
width: 12,
),
Expanded(
child: TextButton(
2022-09-21 00:46:07 +00:00
style: status == "Connected"
? Theme.of(context)
.extension<StackColors>()!
2023-01-24 19:29:12 +00:00
.getPrimaryDisabledButtonStyle(context)
: Theme.of(context)
.extension<StackColors>()!
2023-01-24 19:29:12 +00:00
.getPrimaryEnabledButtonStyle(context),
2022-08-26 08:11:35 +00:00
onPressed: status == "Connected"
? null
: () async {
final canConnect =
await _testConnection(node, context, ref);
if (!canConnect) {
return;
}
await ref
2022-08-26 08:11:35 +00:00
.read(nodeServiceChangeNotifierProvider)
.setPrimaryNodeFor(
coin: coin,
node: node,
shouldNotifyListeners: true,
);
await _notifyWalletsOfUpdatedNode(ref);
2022-08-26 08:11:35 +00:00
},
child: Text(
// status == "Connected" ? "Disconnect" : "Connect",
"Connect",
2022-09-22 22:17:21 +00:00
style: STextStyles.button(context),
2022-08-26 08:11:35 +00:00
),
),
),
],
),
const SizedBox(
height: 24,
),
],
),
),
),
),
);
}
}