mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-25 16:48:48 +00:00
commit
5252c3efff
21 changed files with 366 additions and 236 deletions
|
@ -108,9 +108,36 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
static Decimal maxCrypto = Decimal.parse((10000.00000000).toString());
|
static Decimal maxCrypto = Decimal.parse((10000.00000000).toString());
|
||||||
static String boundedCryptoTicker = '';
|
static String boundedCryptoTicker = '';
|
||||||
|
|
||||||
void fiatFieldOnChanged(String value) async {}
|
String _amountOutOfRangeErrorString = "";
|
||||||
|
void validateAmount() {
|
||||||
|
if (_buyAmountController.text.isEmpty) {
|
||||||
|
setState(() {
|
||||||
|
_amountOutOfRangeErrorString = "";
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void cryptoFieldOnChanged(String value) async {}
|
final value = Decimal.tryParse(_buyAmountController.text);
|
||||||
|
if (value == null) {
|
||||||
|
setState(() {
|
||||||
|
_amountOutOfRangeErrorString = "Invalid amount";
|
||||||
|
});
|
||||||
|
} else if (value > maxFiat && buyWithFiat) {
|
||||||
|
setState(() {
|
||||||
|
_amountOutOfRangeErrorString =
|
||||||
|
"Maximum amount: ${maxFiat.toStringAsFixed(2)}";
|
||||||
|
});
|
||||||
|
} else if (value < minFiat && buyWithFiat) {
|
||||||
|
setState(() {
|
||||||
|
_amountOutOfRangeErrorString =
|
||||||
|
"Minimum amount: ${minFiat.toStringAsFixed(2)}";
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_amountOutOfRangeErrorString = "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void selectCrypto() async {
|
void selectCrypto() async {
|
||||||
if (ref.read(simplexProvider).supportedCryptos.isEmpty) {
|
if (ref.read(simplexProvider).supportedCryptos.isEmpty) {
|
||||||
|
@ -253,6 +280,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
minFiat = fiat.minAmount != minFiat ? fiat.minAmount : minFiat;
|
minFiat = fiat.minAmount != minFiat ? fiat.minAmount : minFiat;
|
||||||
maxFiat = fiat.maxAmount != maxFiat ? fiat.maxAmount : maxFiat;
|
maxFiat = fiat.maxAmount != maxFiat ? fiat.maxAmount : maxFiat;
|
||||||
});
|
});
|
||||||
|
validateAmount();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -359,11 +387,11 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _fetchIconUrlFromTicker(String? ticker) {
|
// String? _fetchIconUrlFromTicker(String? ticker) {
|
||||||
if (ticker == null) return null;
|
// if (ticker == null) return null;
|
||||||
|
//
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
|
|
||||||
bool isStackCoin(String? ticker) {
|
bool isStackCoin(String? ticker) {
|
||||||
if (ticker == null) return false;
|
if (ticker == null) return false;
|
||||||
|
@ -377,13 +405,15 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? getIconForTicker(String ticker) {
|
Widget? getIconForTicker(String ticker) {
|
||||||
String? iconAsset = /*isStackCoin(ticker)
|
String iconAsset = /*isStackCoin(ticker)
|
||||||
?*/
|
?*/
|
||||||
Assets.svg.iconFor(coin: coinFromTickerCaseInsensitive(ticker));
|
Assets.svg.iconFor(coin: coinFromTickerCaseInsensitive(ticker));
|
||||||
// : Assets.svg.buyIconFor(ticker);
|
// : Assets.svg.buyIconFor(ticker);
|
||||||
return (iconAsset != null)
|
// return (iconAsset != null)
|
||||||
? SvgPicture.asset(iconAsset, height: 20, width: 20)
|
// ? SvgPicture.asset(iconAsset, height: 20, width: 20)
|
||||||
: null;
|
// : null;
|
||||||
|
|
||||||
|
return SvgPicture.asset(iconAsset, height: 20, width: 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> previewQuote(SimplexQuote quote) async {
|
Future<void> previewQuote(SimplexQuote quote) async {
|
||||||
|
@ -501,25 +531,25 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Error; probably amount out of bounds
|
// Error; probably amount out of bounds
|
||||||
String errorMessage = "${quoteResponse.exception?.errorMessage}";
|
// String errorMessage = "${quoteResponse.exception?.errorMessage}";
|
||||||
if (errorMessage.contains('must be between')) {
|
// if (errorMessage.contains('must be between')) {
|
||||||
errorMessage = errorMessage.substring(
|
// errorMessage = errorMessage.substring(
|
||||||
(errorMessage.indexOf('getQuote exception: ') ?? 19) + 20,
|
// errorMessage.indexOf('getQuote exception: ') + 20,
|
||||||
errorMessage.indexOf(", value: null"));
|
// errorMessage.indexOf(", value: null"));
|
||||||
_BuyFormState.boundedCryptoTicker = errorMessage.substring(
|
// _BuyFormState.boundedCryptoTicker = errorMessage.substring(
|
||||||
errorMessage.indexOf('The ') + 4,
|
// errorMessage.indexOf('The ') + 4,
|
||||||
errorMessage.indexOf(' amount must be between'));
|
// errorMessage.indexOf(' amount must be between'));
|
||||||
_BuyFormState.minCrypto = Decimal.parse(errorMessage.substring(
|
// _BuyFormState.minCrypto = Decimal.parse(errorMessage.substring(
|
||||||
errorMessage.indexOf('must be between ') + 16,
|
// errorMessage.indexOf('must be between ') + 16,
|
||||||
errorMessage.indexOf(' and ')));
|
// errorMessage.indexOf(' and ')));
|
||||||
_BuyFormState.maxCrypto = Decimal.parse(errorMessage.substring(
|
// _BuyFormState.maxCrypto = Decimal.parse(errorMessage.substring(
|
||||||
errorMessage.indexOf("$minCrypto and ") + "$minCrypto and ".length,
|
// errorMessage.indexOf("$minCrypto and ") + "$minCrypto and ".length,
|
||||||
errorMessage.length));
|
// errorMessage.length));
|
||||||
if (Decimal.parse(_buyAmountController.text) >
|
// if (Decimal.parse(_buyAmountController.text) >
|
||||||
_BuyFormState.maxCrypto) {
|
// _BuyFormState.maxCrypto) {
|
||||||
_buyAmountController.text = _BuyFormState.maxCrypto.toString();
|
// _buyAmountController.text = _BuyFormState.maxCrypto.toString();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
await showDialog<dynamic>(
|
await showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
@ -541,7 +571,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
errorMessage,
|
quoteResponse.exception!.errorMessage,
|
||||||
style: STextStyles.smallMed14(context),
|
style: STextStyles.smallMed14(context),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
@ -603,7 +633,8 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
level: LogLevel.Warning,
|
level: LogLevel.Warning,
|
||||||
);
|
);
|
||||||
return BuyResponse(
|
return BuyResponse(
|
||||||
exception: BuyException(
|
exception: response.exception ??
|
||||||
|
BuyException(
|
||||||
response.toString(),
|
response.toString(),
|
||||||
BuyExceptionType.generic,
|
BuyExceptionType.generic,
|
||||||
),
|
),
|
||||||
|
@ -852,7 +883,11 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
.textFieldDefaultBG,
|
.textFieldDefaultBG,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 12.0, top: 12.0, right: 12.0, bottom: 12.0),
|
left: 12.0,
|
||||||
|
top: 12.0,
|
||||||
|
right: 12.0,
|
||||||
|
bottom: 12.0,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
|
@ -878,7 +913,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
width: 8,
|
width: 8,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${selectedFiat?.ticker ?? 'ERR'}",
|
selectedFiat?.ticker ?? 'ERR',
|
||||||
style: STextStyles.largeMedium14(context),
|
style: STextStyles.largeMedium14(context),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
@ -886,7 +921,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"${selectedFiat?.name ?? 'Error'}",
|
selectedFiat?.name ?? 'Error',
|
||||||
style: STextStyles.largeMedium14(context),
|
style: STextStyles.largeMedium14(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -924,6 +959,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
setState(() {
|
setState(() {
|
||||||
buyWithFiat = !buyWithFiat;
|
buyWithFiat = !buyWithFiat;
|
||||||
});
|
});
|
||||||
|
validateAmount();
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -938,10 +974,11 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
color: Theme.of(context).extension<StackColors>()!.textDark,
|
color: Theme.of(context).extension<StackColors>()!.textDark,
|
||||||
),
|
),
|
||||||
key: const Key("buyAmountInputFieldTextFieldKey"),
|
key: const Key("buyAmountInputFieldTextFieldKey"),
|
||||||
controller: _buyAmountController
|
controller: _buyAmountController,
|
||||||
..text = _BuyFormState.buyWithFiat
|
// note: setting the text value here will set it every time this widget rebuilds
|
||||||
? _BuyFormState.minFiat.toStringAsFixed(2) ?? '50.00'
|
// ..text = _BuyFormState.buyWithFiat
|
||||||
: _BuyFormState.minCrypto.toStringAsFixed(8),
|
// ? _BuyFormState.minFiat.toStringAsFixed(2) ?? '50.00'
|
||||||
|
// : _BuyFormState.minCrypto.toStringAsFixed(8),
|
||||||
focusNode: _buyAmountFocusNode,
|
focusNode: _buyAmountFocusNode,
|
||||||
keyboardType: Util.isDesktop
|
keyboardType: Util.isDesktop
|
||||||
? null
|
? null
|
||||||
|
@ -950,7 +987,10 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
decimal: true,
|
decimal: true,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
inputFormatters: [NumericalRangeFormatter()],
|
// inputFormatters: [NumericalRangeFormatter()],
|
||||||
|
onChanged: (_) {
|
||||||
|
validateAmount();
|
||||||
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
contentPadding: const EdgeInsets.only(
|
contentPadding: const EdgeInsets.only(
|
||||||
// top: 22,
|
// top: 22,
|
||||||
|
@ -985,8 +1025,8 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
format.simpleCurrencySymbol(
|
format.simpleCurrencySymbol(
|
||||||
selectedFiat?.ticker ??
|
selectedFiat?.ticker.toUpperCase() ??
|
||||||
"ERR".toUpperCase()),
|
"ERR"),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: STextStyles.smallMed12(context).copyWith(
|
style: STextStyles.smallMed12(context).copyWith(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
|
@ -1023,18 +1063,20 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
key: const Key(
|
key: const Key(
|
||||||
"buyViewClearAmountFieldButtonKey"),
|
"buyViewClearAmountFieldButtonKey"),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (_BuyFormState.buyWithFiat) {
|
// if (_BuyFormState.buyWithFiat) {
|
||||||
_buyAmountController.text = _BuyFormState
|
// _buyAmountController.text = _BuyFormState
|
||||||
.minFiat
|
// .minFiat
|
||||||
.toStringAsFixed(2);
|
// .toStringAsFixed(2);
|
||||||
} else {
|
// } else {
|
||||||
if (selectedCrypto?.ticker ==
|
// if (selectedCrypto?.ticker ==
|
||||||
_BuyFormState.boundedCryptoTicker) {
|
// _BuyFormState.boundedCryptoTicker) {
|
||||||
_buyAmountController.text = _BuyFormState
|
// _buyAmountController.text = _BuyFormState
|
||||||
.minCrypto
|
// .minCrypto
|
||||||
.toStringAsFixed(8);
|
// .toStringAsFixed(8);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
_buyAmountController.text = "";
|
||||||
|
validateAmount();
|
||||||
},
|
},
|
||||||
child: const XIcon(),
|
child: const XIcon(),
|
||||||
)
|
)
|
||||||
|
@ -1051,7 +1093,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
_buyAmountController.text =
|
_buyAmountController.text =
|
||||||
amountString.toString();
|
amountString.toString();
|
||||||
|
|
||||||
setState(() {});
|
validateAmount();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: _buyAmountController.text.isEmpty
|
child: _buyAmountController.text.isEmpty
|
||||||
|
@ -1064,6 +1106,14 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: isDesktop ? 10 : 4,
|
||||||
|
),
|
||||||
|
if (_amountOutOfRangeErrorString.isNotEmpty)
|
||||||
|
Text(
|
||||||
|
_amountOutOfRangeErrorString,
|
||||||
|
style: STextStyles.errorSmall(context),
|
||||||
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 20 : 12,
|
height: isDesktop ? 20 : 12,
|
||||||
),
|
),
|
||||||
|
@ -1171,7 +1221,7 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
_receiveAddressController.text = "";
|
_receiveAddressController.text = "";
|
||||||
_address = "";
|
_address = "";
|
||||||
setState(() {
|
setState(() {
|
||||||
_addressToggleFlag = true;
|
_addressToggleFlag = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: const XIcon(),
|
child: const XIcon(),
|
||||||
|
@ -1342,27 +1392,15 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: isDesktop ? 20 : 12,
|
height: isDesktop ? 20 : 12,
|
||||||
),
|
),
|
||||||
MouseRegion(
|
PrimaryButton(
|
||||||
cursor: SystemMouseCursors.click,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
if (_receiveAddressController.text.isNotEmpty &&
|
|
||||||
_buyAmountController.text.isNotEmpty) {
|
|
||||||
previewQuote(quote);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: PrimaryButton(
|
|
||||||
buttonHeight: isDesktop ? ButtonHeight.l : null,
|
buttonHeight: isDesktop ? ButtonHeight.l : null,
|
||||||
enabled: _receiveAddressController.text.isNotEmpty &&
|
enabled: _addressToggleFlag &&
|
||||||
|
_amountOutOfRangeErrorString.isEmpty &&
|
||||||
_buyAmountController.text.isNotEmpty,
|
_buyAmountController.text.isNotEmpty,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_receiveAddressController.text.isNotEmpty &&
|
|
||||||
_buyAmountController.text.isNotEmpty) {
|
|
||||||
previewQuote(quote);
|
previewQuote(quote);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
label: "Preview quote",
|
label: "Preview quote",
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -1371,51 +1409,53 @@ class _BuyFormState extends ConsumerState<BuyForm> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://stackoverflow.com/a/68072967
|
// might need this again in the future
|
||||||
class NumericalRangeFormatter extends TextInputFormatter {
|
|
||||||
NumericalRangeFormatter();
|
|
||||||
|
|
||||||
@override
|
// // See https://stackoverflow.com/a/68072967
|
||||||
TextEditingValue formatEditUpdate(
|
// class NumericalRangeFormatter extends TextInputFormatter {
|
||||||
TextEditingValue oldValue,
|
// NumericalRangeFormatter();
|
||||||
TextEditingValue newValue,
|
//
|
||||||
) {
|
// @override
|
||||||
TextSelection newSelection = newValue.selection;
|
// TextEditingValue formatEditUpdate(
|
||||||
String newVal = _BuyFormState.buyWithFiat
|
// TextEditingValue oldValue,
|
||||||
? Decimal.parse(newValue.text).toStringAsFixed(2)
|
// TextEditingValue newValue,
|
||||||
: Decimal.parse(newValue.text).toStringAsFixed(8);
|
// ) {
|
||||||
if (newValue.text == '') {
|
// TextSelection newSelection = newValue.selection;
|
||||||
return newValue;
|
// String newVal = _BuyFormState.buyWithFiat
|
||||||
} else {
|
// ? Decimal.parse(newValue.text).toStringAsFixed(2)
|
||||||
if (_BuyFormState.buyWithFiat) {
|
// : Decimal.parse(newValue.text).toStringAsFixed(8);
|
||||||
if (Decimal.parse(newValue.text) < _BuyFormState.minFiat) {
|
// if (newValue.text == '') {
|
||||||
newVal = _BuyFormState.minFiat.toStringAsFixed(2);
|
// return newValue;
|
||||||
// _BuyFormState._buyAmountController.selection =
|
// } else {
|
||||||
// TextSelection.collapsed(
|
// if (_BuyFormState.buyWithFiat) {
|
||||||
// offset: _BuyFormState.buyWithFiat
|
// if (Decimal.parse(newValue.text) < _BuyFormState.minFiat) {
|
||||||
// ? _BuyFormState._buyAmountController.text.length - 2
|
// newVal = _BuyFormState.minFiat.toStringAsFixed(2);
|
||||||
// : _BuyFormState._buyAmountController.text.length - 8);
|
// // _BuyFormState._buyAmountController.selection =
|
||||||
} else if (Decimal.parse(newValue.text) > _BuyFormState.maxFiat) {
|
// // TextSelection.collapsed(
|
||||||
newVal = _BuyFormState.maxFiat.toStringAsFixed(2);
|
// // offset: _BuyFormState.buyWithFiat
|
||||||
}
|
// // ? _BuyFormState._buyAmountController.text.length - 2
|
||||||
} else if (!_BuyFormState.buyWithFiat &&
|
// // : _BuyFormState._buyAmountController.text.length - 8);
|
||||||
_BuyFormState.selectedCrypto?.ticker ==
|
// } else if (Decimal.parse(newValue.text) > _BuyFormState.maxFiat) {
|
||||||
_BuyFormState.boundedCryptoTicker) {
|
// newVal = _BuyFormState.maxFiat.toStringAsFixed(2);
|
||||||
if (Decimal.parse(newValue.text) < _BuyFormState.minCrypto) {
|
// }
|
||||||
newVal = _BuyFormState.minCrypto.toStringAsFixed(8);
|
// } else if (!_BuyFormState.buyWithFiat &&
|
||||||
} else if (Decimal.parse(newValue.text) > _BuyFormState.maxCrypto) {
|
// _BuyFormState.selectedCrypto?.ticker ==
|
||||||
newVal = _BuyFormState.maxCrypto.toStringAsFixed(8);
|
// _BuyFormState.boundedCryptoTicker) {
|
||||||
}
|
// if (Decimal.parse(newValue.text) < _BuyFormState.minCrypto) {
|
||||||
}
|
// newVal = _BuyFormState.minCrypto.toStringAsFixed(8);
|
||||||
}
|
// } else if (Decimal.parse(newValue.text) > _BuyFormState.maxCrypto) {
|
||||||
|
// newVal = _BuyFormState.maxCrypto.toStringAsFixed(8);
|
||||||
final regexString = _BuyFormState.buyWithFiat
|
// }
|
||||||
? r'^([0-9]*[,.]?[0-9]{0,2}|[,.][0-9]{0,2})$'
|
// }
|
||||||
: r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$';
|
// }
|
||||||
|
//
|
||||||
// return RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$')
|
// final regexString = _BuyFormState.buyWithFiat
|
||||||
return RegExp(regexString).hasMatch(newVal)
|
// ? r'^([0-9]*[,.]?[0-9]{0,2}|[,.][0-9]{0,2})$'
|
||||||
? TextEditingValue(text: newVal, selection: newSelection)
|
// : r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$';
|
||||||
: oldValue;
|
//
|
||||||
}
|
// // return RegExp(r'^([0-9]*[,.]?[0-9]{0,8}|[,.][0-9]{0,8})$')
|
||||||
}
|
// return RegExp(regexString).hasMatch(newVal)
|
||||||
|
// ? TextEditingValue(text: newVal, selection: newSelection)
|
||||||
|
// : oldValue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
@ -5,7 +5,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/no_transactions_found.dart';
|
import 'package:stackwallet/pages/wallet_view/sub_widgets/no_transactions_found.dart';
|
||||||
import 'package:stackwallet/providers/blockchain/dogecoin/current_height_provider.dart';
|
|
||||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
import 'package:stackwallet/route_generator.dart';
|
import 'package:stackwallet/route_generator.dart';
|
||||||
|
@ -85,7 +84,13 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
||||||
children: [
|
children: [
|
||||||
TransactionCard(
|
TransactionCard(
|
||||||
// this may mess with combined firo transactions
|
// this may mess with combined firo transactions
|
||||||
key: Key(tx.txid + tx.type.name + tx.address.value.toString()), //
|
key: Key(tx.txid +
|
||||||
|
tx.type.name +
|
||||||
|
tx.address.value.toString() +
|
||||||
|
ref
|
||||||
|
.watch(widget.managerProvider
|
||||||
|
.select((value) => value.currentHeight))
|
||||||
|
.toString()), //
|
||||||
transaction: tx,
|
transaction: tx,
|
||||||
walletId: widget.walletId,
|
walletId: widget.walletId,
|
||||||
),
|
),
|
||||||
|
@ -180,7 +185,13 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
||||||
),
|
),
|
||||||
child: TransactionCard(
|
child: TransactionCard(
|
||||||
// this may mess with combined firo transactions
|
// this may mess with combined firo transactions
|
||||||
key: Key(tx.txid + tx.type.name + tx.address.value.toString()), //
|
key: Key(tx.txid +
|
||||||
|
tx.type.name +
|
||||||
|
tx.address.value.toString() +
|
||||||
|
ref
|
||||||
|
.watch(widget.managerProvider
|
||||||
|
.select((value) => value.currentHeight))
|
||||||
|
.toString()), //
|
||||||
transaction: tx,
|
transaction: tx,
|
||||||
walletId: widget.walletId,
|
walletId: widget.walletId,
|
||||||
),
|
),
|
||||||
|
@ -188,13 +199,6 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateHeightProvider(Manager manager) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
|
||||||
ref.read(currentHeightProvider(manager.coin).state).state =
|
|
||||||
manager.currentHeight;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
managerProvider = widget.managerProvider;
|
managerProvider = widget.managerProvider;
|
||||||
|
@ -203,14 +207,9 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// final managerProvider = ref
|
|
||||||
// .watch(walletsChangeNotifierProvider)
|
|
||||||
// .getManagerProvider(widget.walletId);
|
|
||||||
|
|
||||||
final manager = ref.watch(walletsChangeNotifierProvider
|
final manager = ref.watch(walletsChangeNotifierProvider
|
||||||
.select((value) => value.getManager(widget.walletId)));
|
.select((value) => value.getManager(widget.walletId)));
|
||||||
|
|
||||||
updateHeightProvider(manager);
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: manager.transactions,
|
future: manager.transactions,
|
||||||
builder: (fbContext, AsyncSnapshot<List<Transaction>> snapshot) {
|
builder: (fbContext, AsyncSnapshot<List<Transaction>> snapshot) {
|
||||||
|
|
|
@ -360,62 +360,6 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (ref.watch(walletsChangeNotifierProvider.select((value) =>
|
|
||||||
value.getManager(widget.walletId).hasPaynymSupport)))
|
|
||||||
RawMaterialButton(
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minWidth: 66,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
if (scale == 0) {
|
|
||||||
setState(() {
|
|
||||||
scale = 1;
|
|
||||||
});
|
|
||||||
} else if (scale == 1) {
|
|
||||||
setState(() {
|
|
||||||
scale = 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
splashColor:
|
|
||||||
Theme.of(context).extension<StackColors>()!.highlight,
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
widget.height / 2.0,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Spacer(),
|
|
||||||
const SizedBox(
|
|
||||||
height: 2,
|
|
||||||
),
|
|
||||||
SvgPicture.asset(
|
|
||||||
Assets.svg.bars,
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 6,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"More",
|
|
||||||
style: STextStyles.buttonSmall(context),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
width: 12,
|
|
||||||
),
|
|
||||||
if (widget.coin.hasBuySupport)
|
if (widget.coin.hasBuySupport)
|
||||||
RawMaterialButton(
|
RawMaterialButton(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
|
@ -455,7 +399,62 @@ class _WalletNavigationBarState extends ConsumerState<WalletNavigationBar> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (widget.coin.hasBuySupport)
|
if (ref.watch(walletsChangeNotifierProvider.select((value) =>
|
||||||
|
value.getManager(widget.walletId).hasPaynymSupport)))
|
||||||
|
RawMaterialButton(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 66,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
if (scale == 0) {
|
||||||
|
setState(() {
|
||||||
|
scale = 1;
|
||||||
|
});
|
||||||
|
} else if (scale == 1) {
|
||||||
|
setState(() {
|
||||||
|
scale = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
splashColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.highlight,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
widget.height / 2.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
const SizedBox(
|
||||||
|
height: 2,
|
||||||
|
),
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.bars,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.bottomNavIconIcon,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 6,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"More",
|
||||||
|
style: STextStyles.buttonSmall(context),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 12,
|
width: 12,
|
||||||
),
|
),
|
||||||
|
|
|
@ -10,7 +10,6 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_search_filter_view.dart';
|
||||||
import 'package:stackwallet/providers/blockchain/dogecoin/current_height_provider.dart';
|
|
||||||
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
import 'package:stackwallet/providers/ui/transaction_filter_provider.dart';
|
||||||
|
@ -131,7 +130,9 @@ class _TransactionDetailsViewState extends ConsumerState<AllTransactionsView> {
|
||||||
// check if address book name contains
|
// check if address book name contains
|
||||||
contains |= contacts
|
contains |= contacts
|
||||||
.where((e) =>
|
.where((e) =>
|
||||||
e.addresses.where((a) => a.address == tx.address).isNotEmpty &&
|
e.addresses
|
||||||
|
.where((a) => a.address == tx.address.value?.value)
|
||||||
|
.isNotEmpty &&
|
||||||
e.name.toLowerCase().contains(keyword))
|
e.name.toLowerCase().contains(keyword))
|
||||||
.isNotEmpty;
|
.isNotEmpty;
|
||||||
|
|
||||||
|
@ -853,7 +854,8 @@ class _DesktopTransactionCardRowState
|
||||||
prefix = "";
|
prefix = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
final currentHeight = ref.watch(currentHeightProvider(coin).state).state;
|
final currentHeight = ref.watch(walletsChangeNotifierProvider
|
||||||
|
.select((value) => value.getManager(walletId).currentHeight));
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
|
|
@ -11,7 +11,6 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/dialogs/cancelling_transaction_progress_dialog.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/edit_note_view.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
import 'package:stackwallet/providers/blockchain/dogecoin/current_height_provider.dart';
|
|
||||||
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
import 'package:stackwallet/providers/global/address_book_service_provider.dart';
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
||||||
|
@ -298,7 +297,8 @@ class _TransactionDetailsViewState
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final currentHeight = ref.watch(currentHeightProvider(coin).state).state;
|
final currentHeight = ref.watch(walletsChangeNotifierProvider
|
||||||
|
.select((value) => value.getManager(walletId).currentHeight));
|
||||||
|
|
||||||
return ConditionalParent(
|
return ConditionalParent(
|
||||||
condition: !isDesktop,
|
condition: !isDesktop,
|
||||||
|
|
|
@ -774,9 +774,6 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onBuyPressed: () {
|
onBuyPressed: () {
|
||||||
// TODO set default coin to currently open wallet here by passing it as an argument
|
|
||||||
// final coin = ref.read(managerProvider).coin;
|
|
||||||
|
|
||||||
unawaited(Navigator.of(context).pushNamed(
|
unawaited(Navigator.of(context).pushNamed(
|
||||||
BuyInWalletView.routeName,
|
BuyInWalletView.routeName,
|
||||||
arguments: coin,
|
arguments: coin,
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
import 'package:dart_numerics/dart_numerics.dart';
|
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|
||||||
|
|
||||||
final currentHeightProvider =
|
|
||||||
StateProvider.family<int, Coin>((ref, coin) => int64MaxValue);
|
|
|
@ -1,4 +1,8 @@
|
||||||
enum BuyExceptionType { generic, serializeResponseError }
|
enum BuyExceptionType {
|
||||||
|
generic,
|
||||||
|
serializeResponseError,
|
||||||
|
cryptoAmountOutOfRange,
|
||||||
|
}
|
||||||
|
|
||||||
class BuyException implements Exception {
|
class BuyException implements Exception {
|
||||||
String errorMessage;
|
String errorMessage;
|
||||||
|
|
|
@ -210,7 +210,20 @@ class SimplexAPI {
|
||||||
|
|
||||||
BuyResponse<SimplexQuote> _parseQuote(dynamic jsonArray) {
|
BuyResponse<SimplexQuote> _parseQuote(dynamic jsonArray) {
|
||||||
try {
|
try {
|
||||||
String cryptoAmount = "${jsonArray['digital_money']['amount']}";
|
// final Map<String, dynamic> lol =
|
||||||
|
// Map<String, dynamic>.from(jsonArray as Map);
|
||||||
|
|
||||||
|
String? cryptoAmount = jsonArray['digital_money']?['amount'] as String?;
|
||||||
|
|
||||||
|
if (cryptoAmount == null) {
|
||||||
|
String error = jsonArray['error'] as String;
|
||||||
|
return BuyResponse(
|
||||||
|
exception: BuyException(
|
||||||
|
error,
|
||||||
|
BuyExceptionType.cryptoAmountOutOfRange,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
SimplexQuote quote = jsonArray['quote'] as SimplexQuote;
|
SimplexQuote quote = jsonArray['quote'] as SimplexQuote;
|
||||||
final SimplexQuote _quote = SimplexQuote(
|
final SimplexQuote _quote = SimplexQuote(
|
||||||
|
|
|
@ -251,6 +251,14 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
@ -1314,6 +1322,8 @@ class BitcoinWallet extends CoinServiceAPI
|
||||||
checkChangeAddressForTransactions: _checkChangeAddressForTransactions,
|
checkChangeAddressForTransactions: _checkChangeAddressForTransactions,
|
||||||
addDerivation: addDerivation,
|
addDerivation: addDerivation,
|
||||||
addDerivations: addDerivations,
|
addDerivations: addDerivations,
|
||||||
|
dustLimitP2PKH: DUST_LIMIT_P2PKH,
|
||||||
|
minConfirms: MINIMUM_CONFIRMATIONS,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,6 +217,14 @@ class BitcoinCashWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -226,6 +226,14 @@ class DogecoinWallet extends CoinServiceAPI
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -1416,6 +1416,14 @@ class EpicCashWallet extends CoinServiceAPI
|
||||||
});
|
});
|
||||||
|
|
||||||
await updateCachedChainHeight(latestHeight!);
|
await updateCachedChainHeight(latestHeight!);
|
||||||
|
if (latestHeight! > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return latestHeight!;
|
return latestHeight!;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -4897,6 +4897,14 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -241,6 +241,14 @@ class LitecoinWallet extends CoinServiceAPI
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -236,6 +236,14 @@ class NamecoinWallet extends CoinServiceAPI
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -231,6 +231,14 @@ class ParticlWallet extends CoinServiceAPI with WalletCache, WalletDB {
|
||||||
final result = await _electrumXClient.getBlockHeadTip();
|
final result = await _electrumXClient.getBlockHeadTip();
|
||||||
final height = result["height"] as int;
|
final height = result["height"] as int;
|
||||||
await updateCachedChainHeight(height);
|
await updateCachedChainHeight(height);
|
||||||
|
if (height > storedChainHeight) {
|
||||||
|
GlobalEventBus.instance.fire(
|
||||||
|
UpdatedInBackgroundEvent(
|
||||||
|
"Updated current chain height in $walletId $walletName!",
|
||||||
|
walletId,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return height;
|
return height;
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
Logging.instance.log("Exception caught in chainHeight: $e\n$s",
|
||||||
|
|
|
@ -189,7 +189,8 @@ mixin ElectrumXParsing {
|
||||||
|
|
||||||
TransactionSubType txSubType = TransactionSubType.none;
|
TransactionSubType txSubType = TransactionSubType.none;
|
||||||
if (this is PaynymWalletInterface && outs.length > 1 && ins.isNotEmpty) {
|
if (this is PaynymWalletInterface && outs.length > 1 && ins.isNotEmpty) {
|
||||||
List<String>? scriptChunks = outs[1].scriptPubKeyAsm?.split(" ");
|
for (int i = 0; i < outs.length; i++) {
|
||||||
|
List<String>? scriptChunks = outs[i].scriptPubKeyAsm?.split(" ");
|
||||||
if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
|
if (scriptChunks?.length == 2 && scriptChunks?[0] == "OP_RETURN") {
|
||||||
final blindedPaymentCode = scriptChunks![1];
|
final blindedPaymentCode = scriptChunks![1];
|
||||||
final bytes = blindedPaymentCode.fromHex;
|
final bytes = blindedPaymentCode.fromHex;
|
||||||
|
@ -200,6 +201,7 @@ mixin ElectrumXParsing {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final tx = Transaction(
|
final tx = Transaction(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
|
|
|
@ -15,7 +15,6 @@ import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||||
import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
|
import 'package:stackwallet/exceptions/wallet/insufficient_balance_exception.dart';
|
||||||
import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
import 'package:stackwallet/exceptions/wallet/paynym_send_exception.dart';
|
||||||
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
|
||||||
import 'package:stackwallet/utilities/bip32_utils.dart';
|
import 'package:stackwallet/utilities/bip32_utils.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||||
|
@ -35,6 +34,8 @@ mixin PaynymWalletInterface {
|
||||||
late final MainDB _db;
|
late final MainDB _db;
|
||||||
late final ElectrumX _electrumXClient;
|
late final ElectrumX _electrumXClient;
|
||||||
late final SecureStorageInterface _secureStorage;
|
late final SecureStorageInterface _secureStorage;
|
||||||
|
late final int _dustLimitP2PKH;
|
||||||
|
late final int _minConfirms;
|
||||||
|
|
||||||
// passed in wallet functions
|
// passed in wallet functions
|
||||||
late final Future<List<String>> Function() _getMnemonic;
|
late final Future<List<String>> Function() _getMnemonic;
|
||||||
|
@ -79,6 +80,8 @@ mixin PaynymWalletInterface {
|
||||||
required MainDB db,
|
required MainDB db,
|
||||||
required ElectrumX electrumXClient,
|
required ElectrumX electrumXClient,
|
||||||
required SecureStorageInterface secureStorage,
|
required SecureStorageInterface secureStorage,
|
||||||
|
required int dustLimitP2PKH,
|
||||||
|
required int minConfirms,
|
||||||
required Future<List<String>> Function() getMnemonic,
|
required Future<List<String>> Function() getMnemonic,
|
||||||
required Future<int> Function() getChainHeight,
|
required Future<int> Function() getChainHeight,
|
||||||
required Future<String> Function() getCurrentChangeAddress,
|
required Future<String> Function() getCurrentChangeAddress,
|
||||||
|
@ -125,6 +128,8 @@ mixin PaynymWalletInterface {
|
||||||
_db = db;
|
_db = db;
|
||||||
_electrumXClient = electrumXClient;
|
_electrumXClient = electrumXClient;
|
||||||
_secureStorage = secureStorage;
|
_secureStorage = secureStorage;
|
||||||
|
_dustLimitP2PKH = dustLimitP2PKH;
|
||||||
|
_minConfirms = minConfirms;
|
||||||
_getMnemonic = getMnemonic;
|
_getMnemonic = getMnemonic;
|
||||||
_getChainHeight = getChainHeight;
|
_getChainHeight = getChainHeight;
|
||||||
_getCurrentChangeAddress = getCurrentChangeAddress;
|
_getCurrentChangeAddress = getCurrentChangeAddress;
|
||||||
|
@ -353,7 +358,7 @@ mixin PaynymWalletInterface {
|
||||||
int additionalOutputs = 0,
|
int additionalOutputs = 0,
|
||||||
List<UTXO>? utxos,
|
List<UTXO>? utxos,
|
||||||
}) async {
|
}) async {
|
||||||
const amountToSend = DUST_LIMIT;
|
final amountToSend = _dustLimitP2PKH;
|
||||||
final List<UTXO> availableOutputs =
|
final List<UTXO> availableOutputs =
|
||||||
utxos ?? await _db.getUTXOs(_walletId).findAll();
|
utxos ?? await _db.getUTXOs(_walletId).findAll();
|
||||||
final List<UTXO> spendableOutputs = [];
|
final List<UTXO> spendableOutputs = [];
|
||||||
|
@ -362,8 +367,8 @@ mixin PaynymWalletInterface {
|
||||||
// Build list of spendable outputs and totaling their satoshi amount
|
// Build list of spendable outputs and totaling their satoshi amount
|
||||||
for (var i = 0; i < availableOutputs.length; i++) {
|
for (var i = 0; i < availableOutputs.length; i++) {
|
||||||
if (availableOutputs[i].isBlocked == false &&
|
if (availableOutputs[i].isBlocked == false &&
|
||||||
availableOutputs[i].isConfirmed(
|
availableOutputs[i]
|
||||||
await _getChainHeight(), MINIMUM_CONFIRMATIONS) ==
|
.isConfirmed(await _getChainHeight(), _minConfirms) ==
|
||||||
true) {
|
true) {
|
||||||
spendableOutputs.add(availableOutputs[i]);
|
spendableOutputs.add(availableOutputs[i]);
|
||||||
spendableSatoshiValue += availableOutputs[i].value;
|
spendableSatoshiValue += availableOutputs[i].value;
|
||||||
|
@ -440,13 +445,13 @@ mixin PaynymWalletInterface {
|
||||||
feeForWithChange = vSizeForWithChange * 1000;
|
feeForWithChange = vSizeForWithChange * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (satoshisBeingUsed - amountToSend > feeForNoChange + DUST_LIMIT) {
|
if (satoshisBeingUsed - amountToSend > feeForNoChange + _dustLimitP2PKH) {
|
||||||
// try to add change output due to "left over" amount being greater than
|
// try to add change output due to "left over" amount being greater than
|
||||||
// the estimated fee + the dust limit
|
// the estimated fee + the dust limit
|
||||||
int changeAmount = satoshisBeingUsed - amountToSend - feeForWithChange;
|
int changeAmount = satoshisBeingUsed - amountToSend - feeForWithChange;
|
||||||
|
|
||||||
// check estimates are correct and build notification tx
|
// check estimates are correct and build notification tx
|
||||||
if (changeAmount >= DUST_LIMIT &&
|
if (changeAmount >= _dustLimitP2PKH &&
|
||||||
satoshisBeingUsed - amountToSend - changeAmount == feeForWithChange) {
|
satoshisBeingUsed - amountToSend - changeAmount == feeForWithChange) {
|
||||||
final txn = await _createNotificationTx(
|
final txn = await _createNotificationTx(
|
||||||
targetPaymentCodeString: targetPaymentCodeString,
|
targetPaymentCodeString: targetPaymentCodeString,
|
||||||
|
@ -572,7 +577,8 @@ mixin PaynymWalletInterface {
|
||||||
);
|
);
|
||||||
|
|
||||||
// todo: modify address once segwit support is in our bip47
|
// todo: modify address once segwit support is in our bip47
|
||||||
txb.addOutput(targetPaymentCode.notificationAddressP2PKH(), DUST_LIMIT);
|
txb.addOutput(
|
||||||
|
targetPaymentCode.notificationAddressP2PKH(), _dustLimitP2PKH);
|
||||||
txb.addOutput(opReturnScript, 0);
|
txb.addOutput(opReturnScript, 0);
|
||||||
|
|
||||||
// TODO: add possible change output and mark output as dangerous
|
// TODO: add possible change output and mark output as dangerous
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:stackwallet/models/isar/models/isar_models.dart';
|
||||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
import 'package:stackwallet/pages/wallet_view/sub_widgets/tx_icon.dart';
|
||||||
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
|
||||||
import 'package:stackwallet/providers/blockchain/dogecoin/current_height_provider.dart';
|
|
||||||
import 'package:stackwallet/providers/providers.dart';
|
import 'package:stackwallet/providers/providers.dart';
|
||||||
import 'package:stackwallet/utilities/constants.dart';
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
@ -121,7 +120,8 @@ class _TransactionCardState extends ConsumerState<TransactionCard> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final currentHeight = ref.watch(currentHeightProvider(coin).state).state;
|
final currentHeight = ref.watch(walletsChangeNotifierProvider
|
||||||
|
.select((value) => value.getManager(walletId).currentHeight));
|
||||||
|
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
|
|
@ -80,6 +80,8 @@ void main() {
|
||||||
|
|
||||||
when(wallets.getManager("wallet-id"))
|
when(wallets.getManager("wallet-id"))
|
||||||
.thenAnswer((realInvocation) => Manager(wallet));
|
.thenAnswer((realInvocation) => Manager(wallet));
|
||||||
|
|
||||||
|
when(wallet.storedChainHeight).thenAnswer((_) => 6000000);
|
||||||
//
|
//
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
|
@ -173,6 +175,7 @@ void main() {
|
||||||
.thenAnswer((realInvocation) => Tuple2(Decimal.ten, 0.00));
|
.thenAnswer((realInvocation) => Tuple2(Decimal.ten, 0.00));
|
||||||
|
|
||||||
when(wallet.coin).thenAnswer((_) => Coin.firo);
|
when(wallet.coin).thenAnswer((_) => Coin.firo);
|
||||||
|
when(wallet.storedChainHeight).thenAnswer((_) => 6000000);
|
||||||
|
|
||||||
when(wallets.getManager("wallet-id"))
|
when(wallets.getManager("wallet-id"))
|
||||||
.thenAnswer((realInvocation) => Manager(wallet));
|
.thenAnswer((realInvocation) => Manager(wallet));
|
||||||
|
@ -271,6 +274,8 @@ void main() {
|
||||||
when(wallets.getManager("wallet-id"))
|
when(wallets.getManager("wallet-id"))
|
||||||
.thenAnswer((realInvocation) => Manager(wallet));
|
.thenAnswer((realInvocation) => Manager(wallet));
|
||||||
|
|
||||||
|
when(wallet.storedChainHeight).thenAnswer((_) => 6000000);
|
||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
ProviderScope(
|
ProviderScope(
|
||||||
overrides: [
|
overrides: [
|
||||||
|
@ -358,6 +363,8 @@ void main() {
|
||||||
when(wallets.getManager("wallet id"))
|
when(wallets.getManager("wallet id"))
|
||||||
.thenAnswer((realInvocation) => Manager(wallet));
|
.thenAnswer((realInvocation) => Manager(wallet));
|
||||||
|
|
||||||
|
when(wallet.storedChainHeight).thenAnswer((_) => 6000000);
|
||||||
|
|
||||||
mockingjay
|
mockingjay
|
||||||
.when(() => navigator.pushNamed("/transactionDetails",
|
.when(() => navigator.pushNamed("/transactionDetails",
|
||||||
arguments: Tuple3(tx, Coin.firo, "wallet id")))
|
arguments: Tuple3(tx, Coin.firo, "wallet id")))
|
||||||
|
@ -395,6 +402,7 @@ void main() {
|
||||||
verify(mockPrefs.currency).called(2);
|
verify(mockPrefs.currency).called(2);
|
||||||
verify(mockLocaleService.locale).called(4);
|
verify(mockLocaleService.locale).called(4);
|
||||||
verify(wallet.coin.ticker).called(2);
|
verify(wallet.coin.ticker).called(2);
|
||||||
|
verify(wallet.storedChainHeight).called(2);
|
||||||
|
|
||||||
verifyNoMoreInteractions(wallet);
|
verifyNoMoreInteractions(wallet);
|
||||||
verifyNoMoreInteractions(mockLocaleService);
|
verifyNoMoreInteractions(mockLocaleService);
|
||||||
|
|
Loading…
Reference in a new issue