mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-18 05:51:34 +02:00
Cw 602 nano bad rep (#1356)
* add support for paths in node settings * update translations and fixes * fix node path * add rep warning flag * update translations * code cleanup [skip ci] * add additional node options * add migration * update transaction history rpc to be under the limit * review fixes [skip ci] * [skip ci] updates * move n2_node.dart * minor code improvements * more minor code cleanup
This commit is contained in:
@@ -8,3 +8,8 @@ class NodeAddressValidator extends TextValidator {
|
||||
pattern:
|
||||
'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\$|^[0-9a-zA-Z.\-]+\$');
|
||||
}
|
||||
|
||||
class NodePathValidator extends TextValidator {
|
||||
NodePathValidator()
|
||||
: super(errorMessage: S.current.error_text_node_address, pattern: '^([/0-9a-zA-Z.\-]+)?\$');
|
||||
}
|
||||
|
||||
@@ -216,6 +216,10 @@ Future<void> defaultSettingsMigration(
|
||||
await disableServiceStatusFiatDisabled(sharedPreferences);
|
||||
break;
|
||||
|
||||
case 31:
|
||||
await updateNanoNodeList(nodes: nodes);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -230,9 +234,35 @@ Future<void> defaultSettingsMigration(
|
||||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
}
|
||||
|
||||
Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
|
||||
final nodeList = await loadDefaultNanoNodes();
|
||||
var listOfNewEndpoints = <String>[
|
||||
"app.natrium.io",
|
||||
"rainstorm.city",
|
||||
"node.somenano.com",
|
||||
"nanoslo.0x.no",
|
||||
"www.bitrequest.app",
|
||||
];
|
||||
// add new nodes:
|
||||
for (final node in nodeList) {
|
||||
if (listOfNewEndpoints.contains(node.uriRaw)) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
// update the nautilus node:
|
||||
final nautilusNode =
|
||||
nodes.values.firstWhereOrNull((element) => element.uriRaw == "node.perish.co");
|
||||
if (nautilusNode != null) {
|
||||
nautilusNode.uriRaw = "node.nautilus.io";
|
||||
nautilusNode.path = "/api";
|
||||
nautilusNode.useSSL = true;
|
||||
await nautilusNode.save();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> disableServiceStatusFiatDisabled(SharedPreferences sharedPreferences) async {
|
||||
final currentFiat =
|
||||
await sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ?? -1;
|
||||
final currentFiat = await sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ?? -1;
|
||||
if (currentFiat == -1 || currentFiat == FiatApiMode.enabled.raw) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ class PreferencesKey {
|
||||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||
static const shouldShowRepWarning = 'should_show_rep_warning';
|
||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
static const syncModeKey = 'sync_mode';
|
||||
static const syncAllKey = 'sync_all';
|
||||
|
||||
+1
-1
@@ -163,7 +163,7 @@ Future<void> initializeAppConfigs() async {
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 30,
|
||||
initialMigrationVersion: 31,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,16 @@ class CWNano extends Nano {
|
||||
String getRepresentative(Object wallet) {
|
||||
return (wallet as NanoWallet).representative;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<N2Node>> getN2Reps(Object wallet) async {
|
||||
return (wallet as NanoWallet).getN2Reps();
|
||||
}
|
||||
|
||||
@override
|
||||
bool isRepOk(Object wallet) {
|
||||
return (wallet as NanoWallet).isRepOk;
|
||||
}
|
||||
}
|
||||
|
||||
class CWNanoUtil extends NanoUtil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
@@ -183,6 +184,22 @@ class CryptoBalanceWidget extends StatelessWidget {
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
if (!dashboardViewModel.showRepWarning) {
|
||||
return const SizedBox();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: S.current.rep_warning,
|
||||
subTitle: S.current.rep_warning_sub,
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
|
||||
onClose: () {
|
||||
dashboardViewModel.settingsStore.shouldShowRepWarning = false;
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return ListView.separated(
|
||||
|
||||
@@ -5,10 +5,12 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/address_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/n2_node.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
@@ -21,9 +23,7 @@ class NanoChangeRepPage extends BasePage {
|
||||
: _wallet = wallet,
|
||||
_settingsStore = settingsStore,
|
||||
_addressController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>() {
|
||||
_addressController.text = nano!.getRepresentative(wallet);
|
||||
}
|
||||
_formKey = GlobalKey<FormState>() {}
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final WalletBase _wallet;
|
||||
@@ -34,105 +34,314 @@ class NanoChangeRepPage extends BasePage {
|
||||
@override
|
||||
String get title => S.current.change_rep;
|
||||
|
||||
N2Node getCurrentRepNode(List<N2Node> nodes) {
|
||||
final currentRepAccount = nano!.getRepresentative(_wallet);
|
||||
final currentNode = nodes.firstWhere(
|
||||
(node) => node.account == currentRepAccount,
|
||||
orElse: () => N2Node(
|
||||
account: currentRepAccount,
|
||||
alias: currentRepAccount,
|
||||
score: 0,
|
||||
uptime: "???",
|
||||
weight: 0,
|
||||
),
|
||||
);
|
||||
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Form(
|
||||
key: _formKey,
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Container(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: AddressTextField(
|
||||
controller: _addressController,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
_addressController.text = paymentRequest.address;
|
||||
},
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
],
|
||||
buttonColor: Theme.of(context).extension<AddressTheme>()!.actionButtonColor,
|
||||
validator: AddressValidator(type: CryptoCurrency.nano),
|
||||
child: FutureBuilder(
|
||||
future: nano!.getN2Reps(_wallet),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return SizedBox();
|
||||
}
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
topSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
topSection: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: AddressTextField(
|
||||
controller: _addressController,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
_addressController.text = paymentRequest.address;
|
||||
},
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
],
|
||||
buttonColor:
|
||||
Theme.of(context).extension<AddressTheme>()!.actionButtonColor,
|
||||
validator: AddressValidator(type: CryptoCurrency.nano),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
S.current.nano_current_rep,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
_buildSingleRepresentative(
|
||||
context,
|
||||
getCurrentRepNode(snapshot.data as List<N2Node>),
|
||||
isList: false,
|
||||
),
|
||||
Divider(height: 20),
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 12),
|
||||
child: Text(
|
||||
S.current.nano_pick_new_rep,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
child: Column(
|
||||
children: _getRepresentativeWidgets(context, snapshot.data as List<N2Node>),
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () => _onSubmit(context),
|
||||
text: S.of(context).change,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSubmit(BuildContext context) async {
|
||||
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_rep,
|
||||
alertContent: S.of(context).change_rep_message,
|
||||
rightButtonText: S.of(context).change,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
try {
|
||||
_settingsStore.defaultNanoRep = _addressController.text;
|
||||
|
||||
await nano!.changeRep(_wallet, _addressController.text);
|
||||
|
||||
// reset this flag whenever we successfully change reps:
|
||||
_settingsStore.shouldShowRepWarning = true;
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).successful,
|
||||
alertContent: S.of(context).change_rep_successful,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.pop(context));
|
||||
});
|
||||
} catch (e) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: e.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.pop(context));
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> _getRepresentativeWidgets(BuildContext context, List<N2Node>? list) {
|
||||
if (list == null) {
|
||||
return [];
|
||||
}
|
||||
final List<Widget> ret = [];
|
||||
for (final N2Node node in list) {
|
||||
if (node.alias != null && node.alias!.trim().isNotEmpty) {
|
||||
ret.add(_buildSingleRepresentative(context, node));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Widget _buildSingleRepresentative(BuildContext context, N2Node rep, {bool isList = true}) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
if (isList)
|
||||
Divider(
|
||||
height: 2,
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
onPressed: () async {
|
||||
if (!isList) {
|
||||
return;
|
||||
}
|
||||
_addressController.text = rep.account!;
|
||||
},
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: const EdgeInsetsDirectional.only(start: 24),
|
||||
width: MediaQuery.of(context).size.width * 0.50,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
_sanitizeAlias(rep.alias),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 7),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: "${S.current.voting_weight}: ${rep.weight.toString()}%",
|
||||
style: TextStyle(
|
||||
color:
|
||||
Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 4),
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: '',
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "${S.current.uptime}: ",
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.secondaryTextColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: rep.uptime,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.secondaryTextColor,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsetsDirectional.only(end: 24, start: 14),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.verified,
|
||||
color: Theme.of(context).primaryColor,
|
||||
size: 50,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: Container(
|
||||
margin: EdgeInsets.all(13),
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: const AlignmentDirectional(-0.03, 0.03),
|
||||
width: 50,
|
||||
height: 50,
|
||||
child: Text(
|
||||
(rep.score).toString(),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(
|
||||
builder: (_) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(right: 8.0),
|
||||
child: LoadingPrimaryButton(
|
||||
onPressed: () async {
|
||||
if (_formKey.currentState != null &&
|
||||
!_formKey.currentState!.validate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final confirmed = await showPopUp<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_rep,
|
||||
alertContent: S.of(context).change_rep_message,
|
||||
rightButtonText: S.of(context).change,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () => Navigator.pop(context, true),
|
||||
actionLeftButton: () => Navigator.pop(context, false));
|
||||
}) ??
|
||||
false;
|
||||
|
||||
if (confirmed) {
|
||||
try {
|
||||
_settingsStore.defaultNanoRep = _addressController.text;
|
||||
|
||||
await nano!.changeRep(_wallet, _addressController.text);
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).successful,
|
||||
alertContent: S.of(context).change_rep_successful,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.pop(context));
|
||||
});
|
||||
} catch (e) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: e.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.pop(context));
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
},
|
||||
text: S.of(context).change,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
),
|
||||
)),
|
||||
],
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String _sanitizeAlias(String? alias) {
|
||||
if (alias != null) {
|
||||
return alias.replaceAll(RegExp(r'[^a-zA-Z_.!?_;:-]'), '');
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ class NodeCreateOrEditPage extends BasePage {
|
||||
NodeCreateOrEditPage({required this.nodeCreateOrEditViewModel,this.editingNode, this.isSelected})
|
||||
: _formKey = GlobalKey<FormState>(),
|
||||
_addressController = TextEditingController(),
|
||||
_pathController = TextEditingController(),
|
||||
_portController = TextEditingController(),
|
||||
_loginController = TextEditingController(),
|
||||
_passwordController = TextEditingController() {
|
||||
@@ -49,6 +50,8 @@ class NodeCreateOrEditPage extends BasePage {
|
||||
|
||||
_addressController.addListener(
|
||||
() => nodeCreateOrEditViewModel.address = _addressController.text);
|
||||
_pathController.addListener(
|
||||
() => nodeCreateOrEditViewModel.path = _pathController.text);
|
||||
_portController.addListener(
|
||||
() => nodeCreateOrEditViewModel.port = _portController.text);
|
||||
_loginController.addListener(
|
||||
@@ -59,6 +62,7 @@ class NodeCreateOrEditPage extends BasePage {
|
||||
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _pathController;
|
||||
final TextEditingController _portController;
|
||||
final TextEditingController _loginController;
|
||||
final TextEditingController _passwordController;
|
||||
|
||||
@@ -16,13 +16,15 @@ class NodeForm extends StatelessWidget {
|
||||
required this.formKey,
|
||||
this.editingNode,
|
||||
}) : _addressController = TextEditingController(text: editingNode?.uri.host.toString()),
|
||||
_pathController = TextEditingController(text: editingNode?.path.toString()),
|
||||
_portController = TextEditingController(text: editingNode?.uri.port.toString()),
|
||||
_loginController = TextEditingController(text: editingNode?.login),
|
||||
_passwordController = TextEditingController(text: editingNode?.password),
|
||||
_socksAddressController = TextEditingController(text: editingNode?.socksProxyAddress){
|
||||
_socksAddressController = TextEditingController(text: editingNode?.socksProxyAddress) {
|
||||
if (editingNode != null) {
|
||||
nodeViewModel
|
||||
..setAddress((editingNode!.uri.host.toString()))
|
||||
..setPath((editingNode!.path.toString()))
|
||||
..setPort((editingNode!.uri.port.toString()))
|
||||
..setPassword((editingNode!.password ?? ''))
|
||||
..setLogin((editingNode!.login ?? ''))
|
||||
@@ -57,10 +59,12 @@ class NodeForm extends StatelessWidget {
|
||||
});
|
||||
|
||||
_addressController.addListener(() => nodeViewModel.address = _addressController.text);
|
||||
_pathController.addListener(() => nodeViewModel.path = _pathController.text);
|
||||
_portController.addListener(() => nodeViewModel.port = _portController.text);
|
||||
_loginController.addListener(() => nodeViewModel.login = _loginController.text);
|
||||
_passwordController.addListener(() => nodeViewModel.password = _passwordController.text);
|
||||
_socksAddressController.addListener(() => nodeViewModel.socksProxyAddress = _socksAddressController.text);
|
||||
_socksAddressController
|
||||
.addListener(() => nodeViewModel.socksProxyAddress = _socksAddressController.text);
|
||||
}
|
||||
|
||||
final NodeCreateOrEditViewModel nodeViewModel;
|
||||
@@ -68,6 +72,7 @@ class NodeForm extends StatelessWidget {
|
||||
final Node? editingNode;
|
||||
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _pathController;
|
||||
final TextEditingController _portController;
|
||||
final TextEditingController _loginController;
|
||||
final TextEditingController _passwordController;
|
||||
@@ -91,6 +96,18 @@ class NodeForm extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _pathController,
|
||||
hintText: "/path",
|
||||
validator: NodePathValidator(),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
@@ -103,6 +120,26 @@ class NodeForm extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: nodeViewModel.useSSL,
|
||||
gradientBackground: true,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (value) => nodeViewModel.useSSL = value,
|
||||
caption: S.of(context).use_ssl,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10.0),
|
||||
if (nodeViewModel.hasAuthCredentials) ...[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
@@ -123,25 +160,6 @@ class NodeForm extends StatelessWidget {
|
||||
))
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) => StandardCheckbox(
|
||||
value: nodeViewModel.useSSL,
|
||||
gradientBackground: true,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (value) => nodeViewModel.useSSL = value,
|
||||
caption: S.of(context).use_ssl,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
@@ -163,44 +181,44 @@ class NodeForm extends StatelessWidget {
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.useSocksProxy,
|
||||
gradientBackground: true,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (value) {
|
||||
if (!value) {
|
||||
_socksAddressController.text = '';
|
||||
}
|
||||
nodeViewModel.useSocksProxy = value;
|
||||
},
|
||||
caption: 'SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (nodeViewModel.useSocksProxy) ...[
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
StandardCheckbox(
|
||||
value: nodeViewModel.useSocksProxy,
|
||||
gradientBackground: true,
|
||||
borderColor: Theme.of(context).dividerColor,
|
||||
iconColor: Colors.white,
|
||||
onChanged: (value) {
|
||||
if (!value) {
|
||||
_socksAddressController.text = '';
|
||||
}
|
||||
nodeViewModel.useSocksProxy = value;
|
||||
},
|
||||
caption: 'SOCKS Proxy',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (nodeViewModel.useSocksProxy) ...[
|
||||
SizedBox(height: 10.0),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: BaseTextFormField(
|
||||
controller: _socksAddressController,
|
||||
hintText: '[<ip>:]<port>',
|
||||
validator: SocksProxyNodeAddressValidator(),
|
||||
))
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
]
|
||||
],
|
||||
)),
|
||||
]
|
||||
],
|
||||
),
|
||||
|
||||
@@ -4,15 +4,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
|
||||
class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
|
||||
|
||||
DashBoardRoundedCardWidget({
|
||||
required this.onTap,
|
||||
required this.title,
|
||||
required this.subTitle,
|
||||
this.onClose,
|
||||
});
|
||||
|
||||
final VoidCallback onTap;
|
||||
final VoidCallback? onClose;
|
||||
final String title;
|
||||
final String subTitle;
|
||||
|
||||
@@ -26,7 +26,7 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
padding: EdgeInsets.fromLTRB(20, 20, 40, 20),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||
@@ -35,32 +35,40 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
),
|
||||
),
|
||||
child:
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato'),
|
||||
)
|
||||
],
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
Text(
|
||||
subTitle,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: 'Lato'),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
if (onClose != null)
|
||||
Positioned(
|
||||
top: 10,
|
||||
right: 10,
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.close),
|
||||
onPressed: onClose,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,21 @@ import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ScrollableWithBottomSection extends StatefulWidget {
|
||||
ScrollableWithBottomSection(
|
||||
{required this.content,
|
||||
required this.bottomSection,
|
||||
this.contentPadding,
|
||||
this.bottomSectionPadding});
|
||||
ScrollableWithBottomSection({
|
||||
required this.content,
|
||||
required this.bottomSection,
|
||||
this.topSection,
|
||||
this.contentPadding,
|
||||
this.bottomSectionPadding,
|
||||
this.topSectionPadding,
|
||||
});
|
||||
|
||||
final Widget content;
|
||||
final Widget bottomSection;
|
||||
final Widget? topSection;
|
||||
final EdgeInsets? contentPadding;
|
||||
final EdgeInsets? bottomSectionPadding;
|
||||
final EdgeInsets? topSectionPadding;
|
||||
|
||||
@override
|
||||
ScrollableWithBottomSectionState createState() => ScrollableWithBottomSectionState();
|
||||
@@ -22,6 +27,12 @@ class ScrollableWithBottomSectionState extends State<ScrollableWithBottomSection
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
if (widget.topSection != null)
|
||||
Padding(
|
||||
padding: widget.topSectionPadding?.copyWith(top: 10) ??
|
||||
EdgeInsets.only(top: 10, bottom: 20, right: 20, left: 20),
|
||||
child: widget.topSection,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
|
||||
@@ -79,6 +79,7 @@ abstract class SettingsStoreBase with Store {
|
||||
required Map<WalletType, Node> nodes,
|
||||
required Map<WalletType, Node> powNodes,
|
||||
required this.shouldShowYatPopup,
|
||||
required this.shouldShowRepWarning,
|
||||
required this.isBitcoinBuyEnabled,
|
||||
required this.actionlistDisplayMode,
|
||||
required this.pinTimeOutDuration,
|
||||
@@ -225,6 +226,9 @@ abstract class SettingsStoreBase with Store {
|
||||
(bool shouldShowYatPopup) =>
|
||||
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
|
||||
|
||||
reaction((_) => shouldShowRepWarning,
|
||||
(bool val) => sharedPreferences.setBool(PreferencesKey.shouldShowRepWarning, val));
|
||||
|
||||
defaultBuyProviders.observe((change) {
|
||||
final String key = 'buyProvider_${change.key.toString()}';
|
||||
if (change.newValue != null) {
|
||||
@@ -536,6 +540,9 @@ abstract class SettingsStoreBase with Store {
|
||||
@observable
|
||||
bool shouldShowYatPopup;
|
||||
|
||||
@observable
|
||||
bool shouldShowRepWarning;
|
||||
|
||||
@observable
|
||||
bool shouldShowMarketPlaceInDashboard;
|
||||
|
||||
@@ -878,6 +885,8 @@ abstract class SettingsStoreBase with Store {
|
||||
final packageInfo = await PackageInfo.fromPlatform();
|
||||
final deviceName = await _getDeviceName() ?? '';
|
||||
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
|
||||
final shouldShowRepWarning =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? true;
|
||||
|
||||
final generateSubaddresses =
|
||||
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
|
||||
@@ -1034,75 +1043,77 @@ abstract class SettingsStoreBase with Store {
|
||||
'';
|
||||
|
||||
return SettingsStore(
|
||||
secureStorage: secureStorage,
|
||||
sharedPreferences: sharedPreferences,
|
||||
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
|
||||
nodes: nodes,
|
||||
powNodes: powNodes,
|
||||
appVersion: packageInfo.version,
|
||||
deviceName: deviceName,
|
||||
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
|
||||
initialFiatCurrency: currentFiatCurrency,
|
||||
initialBalanceDisplayMode: currentBalanceDisplayMode,
|
||||
initialSaveRecipientAddress: shouldSaveRecipientAddress,
|
||||
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
|
||||
initialMoneroSeedType: moneroSeedType,
|
||||
initialAppSecure: isAppSecure,
|
||||
initialDisableBuy: disableBuy,
|
||||
initialDisableSell: disableSell,
|
||||
initialDisableBulletin: disableBulletin,
|
||||
initialWalletListOrder: walletListOrder,
|
||||
initialWalletListAscending: walletListAscending,
|
||||
initialFiatMode: currentFiatApiMode,
|
||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
initialCake2FAPresetOptions: selectedCake2FAPreset,
|
||||
initialUseTOTP2FA: useTOTP2FA,
|
||||
initialTotpSecretKey: totpSecretKey,
|
||||
initialFailedTokenTrial: tokenTrialNumber,
|
||||
initialExchangeStatus: exchangeStatus,
|
||||
initialTheme: savedTheme,
|
||||
actionlistDisplayMode: actionListDisplayMode,
|
||||
initialPinLength: pinLength,
|
||||
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||
seedPhraseLength: seedPhraseWordCount,
|
||||
initialLanguageCode: savedLanguageCode,
|
||||
sortBalanceBy: sortBalanceBy,
|
||||
pinNativeTokenAtTop: pinNativeTokenAtTop,
|
||||
useEtherscan: useEtherscan,
|
||||
usePolygonScan: usePolygonScan,
|
||||
defaultNanoRep: defaultNanoRep,
|
||||
defaultBananoRep: defaultBananoRep,
|
||||
lookupsTwitter: lookupsTwitter,
|
||||
lookupsMastodon: lookupsMastodon,
|
||||
lookupsYatService: lookupsYatService,
|
||||
lookupsUnstoppableDomains: lookupsUnstoppableDomains,
|
||||
lookupsOpenAlias: lookupsOpenAlias,
|
||||
lookupsENS: lookupsENS,
|
||||
customBitcoinFeeRate: customBitcoinFeeRate,
|
||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||
initialHavenTransactionPriority: havenTransactionPriority,
|
||||
initialLitecoinTransactionPriority: litecoinTransactionPriority,
|
||||
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
||||
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
||||
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
||||
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
||||
initialShouldRequireTOTP2FAForSendsToInternalWallets:
|
||||
shouldRequireTOTP2FAForSendsToInternalWallets,
|
||||
initialShouldRequireTOTP2FAForExchangesToInternalWallets:
|
||||
shouldRequireTOTP2FAForExchangesToInternalWallets,
|
||||
initialShouldRequireTOTP2FAForExchangesToExternalWallets:
|
||||
shouldRequireTOTP2FAForExchangesToExternalWallets,
|
||||
initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts,
|
||||
initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
|
||||
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
initialEthereumTransactionPriority: ethereumTransactionPriority,
|
||||
initialPolygonTransactionPriority: polygonTransactionPriority,
|
||||
backgroundTasks: backgroundTasks,
|
||||
initialSyncMode: savedSyncMode,
|
||||
initialSyncAll: savedSyncAll,
|
||||
shouldShowYatPopup: shouldShowYatPopup);
|
||||
secureStorage: secureStorage,
|
||||
sharedPreferences: sharedPreferences,
|
||||
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
|
||||
nodes: nodes,
|
||||
powNodes: powNodes,
|
||||
appVersion: packageInfo.version,
|
||||
deviceName: deviceName,
|
||||
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
|
||||
initialFiatCurrency: currentFiatCurrency,
|
||||
initialBalanceDisplayMode: currentBalanceDisplayMode,
|
||||
initialSaveRecipientAddress: shouldSaveRecipientAddress,
|
||||
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
|
||||
initialMoneroSeedType: moneroSeedType,
|
||||
initialAppSecure: isAppSecure,
|
||||
initialDisableBuy: disableBuy,
|
||||
initialDisableSell: disableSell,
|
||||
initialDisableBulletin: disableBulletin,
|
||||
initialWalletListOrder: walletListOrder,
|
||||
initialWalletListAscending: walletListAscending,
|
||||
initialFiatMode: currentFiatApiMode,
|
||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
initialCake2FAPresetOptions: selectedCake2FAPreset,
|
||||
initialUseTOTP2FA: useTOTP2FA,
|
||||
initialTotpSecretKey: totpSecretKey,
|
||||
initialFailedTokenTrial: tokenTrialNumber,
|
||||
initialExchangeStatus: exchangeStatus,
|
||||
initialTheme: savedTheme,
|
||||
actionlistDisplayMode: actionListDisplayMode,
|
||||
initialPinLength: pinLength,
|
||||
pinTimeOutDuration: pinCodeTimeOutDuration,
|
||||
seedPhraseLength: seedPhraseWordCount,
|
||||
initialLanguageCode: savedLanguageCode,
|
||||
sortBalanceBy: sortBalanceBy,
|
||||
pinNativeTokenAtTop: pinNativeTokenAtTop,
|
||||
useEtherscan: useEtherscan,
|
||||
usePolygonScan: usePolygonScan,
|
||||
defaultNanoRep: defaultNanoRep,
|
||||
defaultBananoRep: defaultBananoRep,
|
||||
lookupsTwitter: lookupsTwitter,
|
||||
lookupsMastodon: lookupsMastodon,
|
||||
lookupsYatService: lookupsYatService,
|
||||
lookupsUnstoppableDomains: lookupsUnstoppableDomains,
|
||||
lookupsOpenAlias: lookupsOpenAlias,
|
||||
lookupsENS: lookupsENS,
|
||||
customBitcoinFeeRate: customBitcoinFeeRate,
|
||||
initialMoneroTransactionPriority: moneroTransactionPriority,
|
||||
initialBitcoinTransactionPriority: bitcoinTransactionPriority,
|
||||
initialHavenTransactionPriority: havenTransactionPriority,
|
||||
initialLitecoinTransactionPriority: litecoinTransactionPriority,
|
||||
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
||||
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
||||
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
||||
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
||||
initialShouldRequireTOTP2FAForSendsToInternalWallets:
|
||||
shouldRequireTOTP2FAForSendsToInternalWallets,
|
||||
initialShouldRequireTOTP2FAForExchangesToInternalWallets:
|
||||
shouldRequireTOTP2FAForExchangesToInternalWallets,
|
||||
initialShouldRequireTOTP2FAForExchangesToExternalWallets:
|
||||
shouldRequireTOTP2FAForExchangesToExternalWallets,
|
||||
initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts,
|
||||
initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets,
|
||||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
|
||||
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
initialEthereumTransactionPriority: ethereumTransactionPriority,
|
||||
initialPolygonTransactionPriority: polygonTransactionPriority,
|
||||
backgroundTasks: backgroundTasks,
|
||||
initialSyncMode: savedSyncMode,
|
||||
initialSyncAll: savedSyncAll,
|
||||
shouldShowYatPopup: shouldShowYatPopup,
|
||||
shouldShowRepWarning: shouldShowRepWarning,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> reload({required Box<Node> nodeSource}) async {
|
||||
@@ -1198,6 +1209,8 @@ abstract class SettingsStoreBase with Store {
|
||||
languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode;
|
||||
shouldShowYatPopup =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
|
||||
shouldShowRepWarning =
|
||||
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? shouldShowRepWarning;
|
||||
sortBalanceBy = SortBalanceBy
|
||||
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
|
||||
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:cake_wallet/entities/service_status.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||
@@ -370,6 +371,18 @@ abstract class DashboardViewModelBase with Store {
|
||||
@computed
|
||||
bool get hasPowNodes => wallet.type == WalletType.nano || wallet.type == WalletType.banano;
|
||||
|
||||
bool get showRepWarning {
|
||||
if (wallet.type != WalletType.nano) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!settingsStore.shouldShowRepWarning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !nano!.isRepOk(wallet);
|
||||
}
|
||||
|
||||
Future<void> reconnect() async {
|
||||
final node = appStore.settingsStore.getCurrentNode(wallet.type);
|
||||
await wallet.connectToNode(node: node);
|
||||
|
||||
@@ -12,16 +12,15 @@ import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
part 'node_create_or_edit_view_model.g.dart';
|
||||
|
||||
class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase
|
||||
with _$NodeCreateOrEditViewModel;
|
||||
class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase with _$NodeCreateOrEditViewModel;
|
||||
|
||||
abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
NodeCreateOrEditViewModelBase(
|
||||
this._nodeSource, this._walletType, this._settingsStore)
|
||||
NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType, this._settingsStore)
|
||||
: state = InitialExecutionState(),
|
||||
connectionState = InitialExecutionState(),
|
||||
useSSL = false,
|
||||
address = '',
|
||||
path = '',
|
||||
port = '',
|
||||
login = '',
|
||||
password = '',
|
||||
@@ -35,6 +34,9 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
@observable
|
||||
String address;
|
||||
|
||||
@observable
|
||||
String path;
|
||||
|
||||
@observable
|
||||
String port;
|
||||
|
||||
@@ -84,6 +86,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
@action
|
||||
void reset() {
|
||||
address = '';
|
||||
path = '';
|
||||
port = '';
|
||||
login = '';
|
||||
password = '';
|
||||
@@ -99,6 +102,9 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
@action
|
||||
void setAddress(String val) => address = val;
|
||||
|
||||
@action
|
||||
void setPath(String val) => path = val;
|
||||
|
||||
@action
|
||||
void setLogin(String val) => login = val;
|
||||
|
||||
@@ -121,6 +127,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
Future<void> save({Node? editingNode, bool saveAsCurrent = false}) async {
|
||||
final node = Node(
|
||||
uri: uri,
|
||||
path: path,
|
||||
type: _walletType,
|
||||
login: login,
|
||||
password: password,
|
||||
@@ -151,6 +158,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
Future<void> connect() async {
|
||||
final node = Node(
|
||||
uri: uri,
|
||||
path: path,
|
||||
type: _walletType,
|
||||
login: login,
|
||||
password: password,
|
||||
@@ -183,7 +191,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
Future<void> scanQRCodeForNewNode(BuildContext context) async {
|
||||
try {
|
||||
bool isCameraPermissionGranted =
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
await PermissionHandler.checkPermission(Permission.camera, context);
|
||||
if (!isCameraPermissionGranted) return;
|
||||
String code = await presentQRScanner();
|
||||
|
||||
@@ -198,7 +206,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
}
|
||||
|
||||
final userInfo = uri.userInfo.split(':');
|
||||
|
||||
|
||||
if (userInfo.length < 2) {
|
||||
throw Exception('Unexpected scan QR code value: Value is invalid');
|
||||
}
|
||||
@@ -207,8 +215,11 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||
final rpcPassword = userInfo[1];
|
||||
final ipAddress = uri.host;
|
||||
final port = uri.port.toString();
|
||||
final path = uri.path;
|
||||
|
||||
|
||||
setAddress(ipAddress);
|
||||
setPath(path);
|
||||
setPassword(rpcPassword);
|
||||
setLogin(rpcUser);
|
||||
setPort(port);
|
||||
|
||||
Reference in New Issue
Block a user