mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 01:37:54 +00:00
Merge remote-tracking branch 'origin/staging' into ui-fixes
This commit is contained in:
commit
c7930ba32f
23 changed files with 732 additions and 611 deletions
|
@ -1 +1 @@
|
|||
Subproject commit e81b1b7c2d8114435a9458ab2e439f4393f626e7
|
||||
Subproject commit e62cfc2cae093346bd547ed1379f99c1ed1fe537
|
|
@ -57,7 +57,10 @@ class AddressEntryData extends ChangeNotifier {
|
|||
}
|
||||
|
||||
bool get isValidAddress {
|
||||
if (_address == null || coin == null) {
|
||||
if ( coin == null) {
|
||||
return true;
|
||||
}
|
||||
if (_address == null) {
|
||||
return false;
|
||||
}
|
||||
return AddressUtils.validateAddress(_address!, _coin!);
|
||||
|
|
|
@ -2,9 +2,7 @@ import 'package:decimal/decimal.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
|
||||
import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
|
@ -325,28 +323,28 @@ class ExchangeFormState extends ChangeNotifier {
|
|||
required bool shouldNotifyListeners,
|
||||
}) async {
|
||||
try {
|
||||
switch (exchange.name) {
|
||||
case ChangeNowExchange.exchangeName:
|
||||
if (!_exchangeSupported(
|
||||
exchangeName: exchange.name,
|
||||
sendCurrency: sendCurrency,
|
||||
receiveCurrency: receiveCurrency,
|
||||
exchangeRateType: exchangeRateType,
|
||||
)) {
|
||||
_exchange = MajesticBankExchange.instance;
|
||||
}
|
||||
break;
|
||||
case MajesticBankExchange.exchangeName:
|
||||
if (!_exchangeSupported(
|
||||
exchangeName: exchange.name,
|
||||
sendCurrency: sendCurrency,
|
||||
receiveCurrency: receiveCurrency,
|
||||
exchangeRateType: exchangeRateType,
|
||||
)) {
|
||||
_exchange = ChangeNowExchange.instance;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// switch (exchange.name) {
|
||||
// case ChangeNowExchange.exchangeName:
|
||||
// if (!_exchangeSupported(
|
||||
// exchangeName: exchange.name,
|
||||
// sendCurrency: sendCurrency,
|
||||
// receiveCurrency: receiveCurrency,
|
||||
// exchangeRateType: exchangeRateType,
|
||||
// )) {
|
||||
// _exchange = MajesticBankExchange.instance;
|
||||
// }
|
||||
// break;
|
||||
// case MajesticBankExchange.exchangeName:
|
||||
// if (!_exchangeSupported(
|
||||
// exchangeName: exchange.name,
|
||||
// sendCurrency: sendCurrency,
|
||||
// receiveCurrency: receiveCurrency,
|
||||
// exchangeRateType: exchangeRateType,
|
||||
// )) {
|
||||
// _exchange = ChangeNowExchange.instance;
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
|
||||
await _updateRanges(shouldNotifyListeners: false);
|
||||
await _updateEstimate(shouldNotifyListeners: false);
|
||||
|
|
|
@ -138,270 +138,228 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
),
|
||||
),
|
||||
child: StreamBuilder<UTXO?>(
|
||||
stream: streamUTXO,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
utxo = snapshot.data!;
|
||||
}
|
||||
return ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return DesktopDialog(
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
stream: streamUTXO,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
utxo = snapshot.data!;
|
||||
}
|
||||
return ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return DesktopDialog(
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 32),
|
||||
child: Text(
|
||||
"Output details",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: () {
|
||||
Navigator.of(context)
|
||||
.pop(_popWithRefresh ? "refresh" : null);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
IntrinsicHeight(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
top: 10,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
IntrinsicHeight(
|
||||
child: RoundedContainer(
|
||||
padding: EdgeInsets.zero,
|
||||
color: Colors.transparent,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondaryButton(
|
||||
buttonHeight: ButtonHeight.l,
|
||||
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
|
||||
onPressed: _toggleFreeze,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RoundedContainer(
|
||||
padding: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 32),
|
||||
child: Text(
|
||||
"Output details",
|
||||
style: STextStyles.desktopH3(context),
|
||||
if (isDesktop)
|
||||
UTXOStatusIcon(
|
||||
blocked: utxo!.isBlocked,
|
||||
status: confirmed
|
||||
? UTXOStatusIconStatus.confirmed
|
||||
: UTXOStatusIconStatus.unconfirmed,
|
||||
background: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
selected: false,
|
||||
width: 32,
|
||||
height: 32,
|
||||
),
|
||||
),
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: () {
|
||||
Navigator.of(context)
|
||||
.pop(_popWithRefresh ? "refresh" : null);
|
||||
},
|
||||
if (isDesktop)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo!.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.pageTitleH2(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
IntrinsicHeight(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
top: 10,
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
IntrinsicHeight(
|
||||
child: RoundedContainer(
|
||||
padding: EdgeInsets.zero,
|
||||
color: Colors.transparent,
|
||||
borderColor: Theme.of(context)
|
||||
Text(
|
||||
utxo!.isBlocked
|
||||
? "Frozen"
|
||||
: confirmed
|
||||
? "Available"
|
||||
: "Unconfirmed",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: utxo!.isBlocked
|
||||
? const Color(0xFF7FA2D4) // todo theme
|
||||
: confirmed
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
SecondaryButton(
|
||||
buttonHeight: ButtonHeight.l,
|
||||
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
|
||||
onPressed: _toggleFreeze,
|
||||
),
|
||||
],
|
||||
),
|
||||
.accentColorGreen
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorYellow,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
RoundedContainer(
|
||||
padding: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
if (isDesktop)
|
||||
UTXOStatusIcon(
|
||||
blocked: utxo!.isBlocked,
|
||||
status: confirmed
|
||||
? UTXOStatusIconStatus.confirmed
|
||||
: UTXOStatusIconStatus.unconfirmed,
|
||||
background: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
selected: false,
|
||||
width: 32,
|
||||
height: 32,
|
||||
),
|
||||
if (isDesktop)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Text(
|
||||
"${Format.satoshisToAmount(
|
||||
utxo!.value,
|
||||
coin: coin,
|
||||
).toStringAsFixed(
|
||||
coin.decimals,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.pageTitleH2(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
utxo!.isBlocked
|
||||
? "Frozen"
|
||||
: confirmed
|
||||
? "Available"
|
||||
: "Unconfirmed",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: utxo!.isBlocked
|
||||
? const Color(0xFF7FA2D4) // todo theme
|
||||
: confirmed
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorGreen
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorYellow,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Label",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
SimpleEditButton(
|
||||
editValue: utxo!.name,
|
||||
editLabel: "label",
|
||||
onValueChanged: (newName) {
|
||||
MainDB.instance.putUTXO(
|
||||
utxo!.copyWith(
|
||||
name: newName,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.name,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Address",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: utxo!.address!,
|
||||
)
|
||||
: SimpleCopyButton(
|
||||
data: utxo!.address!,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.address!,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (label != null && label!.value.isNotEmpty) const _Div(),
|
||||
if (label != null && label!.value.isNotEmpty)
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Address label",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: utxo!.address!,
|
||||
)
|
||||
: SimpleCopyButton(
|
||||
data: label!.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
label!.value,
|
||||
style: STextStyles.w500_14(context),
|
||||
"Label",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
SimpleEditButton(
|
||||
editValue: utxo!.name,
|
||||
editLabel: "label",
|
||||
onValueChanged: (newName) {
|
||||
MainDB.instance.putUTXO(
|
||||
utxo!.copyWith(
|
||||
name: newName,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.name,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Address",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: utxo!.address!,
|
||||
)
|
||||
: SimpleCopyButton(
|
||||
data: utxo!.address!,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.address!,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (label != null && label!.value.isNotEmpty) const _Div(),
|
||||
if (label != null && label!.value.isNotEmpty)
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
|
@ -417,7 +375,7 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction ID",
|
||||
"Address label",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
@ -426,10 +384,10 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: utxo!.address!,
|
||||
data: label!.value,
|
||||
)
|
||||
: SimpleCopyButton(
|
||||
data: utxo!.txid,
|
||||
data: label!.value,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -437,114 +395,155 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
|
|||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.txid,
|
||||
label!.value,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Confirmations",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
"${utxo!.getConfirmations(currentHeight)}",
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (utxo!.isBlocked) const _Div(),
|
||||
if (utxo!.isBlocked)
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context)
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Transaction ID",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Freeze reason",
|
||||
style:
|
||||
STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
SimpleEditButton(
|
||||
editValue: utxo!.blockedReason ?? "",
|
||||
editLabel: "freeze reason",
|
||||
onValueChanged: (newReason) {
|
||||
MainDB.instance.putUTXO(
|
||||
utxo!.copyWith(
|
||||
blockedReason: newReason,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.blockedReason ?? "",
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
isDesktop
|
||||
? IconCopyButton(
|
||||
data: utxo!.txid,
|
||||
)
|
||||
: SimpleCopyButton(
|
||||
data: utxo!.txid,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.txid,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const _Div(),
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Confirmations",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
if (!isDesktop) const _Div(),
|
||||
],
|
||||
),
|
||||
if (!isDesktop) const Spacer(),
|
||||
if (!isDesktop)
|
||||
SecondaryButton(
|
||||
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
|
||||
onPressed: _toggleFreeze,
|
||||
),
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
"${utxo!.getConfirmations(currentHeight)}",
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (utxo!.isBlocked) const _Div(),
|
||||
if (utxo!.isBlocked)
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
RoundedContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.all(16)
|
||||
: const EdgeInsets.all(12),
|
||||
color: isDesktop
|
||||
? Colors.transparent
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Freeze reason",
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
),
|
||||
),
|
||||
SimpleEditButton(
|
||||
editValue: utxo!.blockedReason ?? "",
|
||||
editLabel: "freeze reason",
|
||||
onValueChanged: (newReason) {
|
||||
MainDB.instance.putUTXO(
|
||||
utxo!.copyWith(
|
||||
blockedReason: newReason,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
Text(
|
||||
utxo!.blockedReason ?? "",
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (!isDesktop) const _Div(),
|
||||
],
|
||||
),
|
||||
if (!isDesktop) const Spacer(),
|
||||
if (!isDesktop)
|
||||
SecondaryButton(
|
||||
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
|
||||
onPressed: _toggleFreeze,
|
||||
),
|
||||
if (!isDesktop)
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
|
|||
import 'package:stackwallet/pages/buy_view/sub_widgets/crypto_selection_view.dart';
|
||||
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -95,11 +94,12 @@ class _ExchangeCurrencySelectionViewState
|
|||
if (widget.pairedTicker == null) {
|
||||
return await _getCurrencies();
|
||||
}
|
||||
List<Currency> currencies = await ExchangeDataLoadingService
|
||||
.instance.isar.currencies
|
||||
.where()
|
||||
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
||||
.findAll();
|
||||
List<Currency> currencies = [];
|
||||
// await ExchangeDataLoadingService
|
||||
// .instance.isar.currencies
|
||||
// .where()
|
||||
// .exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
||||
// .findAll();
|
||||
|
||||
final cn = await ChangeNowExchange.instance.getPairedCurrencies(
|
||||
widget.pairedTicker!,
|
||||
|
|
|
@ -579,7 +579,7 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
time,
|
||||
]);
|
||||
|
||||
final txData = results.last
|
||||
final txData = results.first
|
||||
as Map<String, dynamic>;
|
||||
|
||||
if (!wasCancelled) {
|
||||
|
|
|
@ -71,11 +71,12 @@ class _ExchangeProviderOptionsState
|
|||
sendCurrency: sendCurrency,
|
||||
receiveCurrency: receivingCurrency,
|
||||
);
|
||||
final showMajesticBank = exchangeSupported(
|
||||
exchangeName: MajesticBankExchange.exchangeName,
|
||||
sendCurrency: sendCurrency,
|
||||
receiveCurrency: receivingCurrency,
|
||||
);
|
||||
final showMajesticBank = false;
|
||||
// exchangeSupported(
|
||||
// exchangeName: MajesticBankExchange.exchangeName,
|
||||
// sendCurrency: sendCurrency,
|
||||
// receiveCurrency: receivingCurrency,
|
||||
// );
|
||||
|
||||
return RoundedWhiteContainer(
|
||||
padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12),
|
||||
|
|
|
@ -93,7 +93,8 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
|||
.trades
|
||||
.firstWhere((e) => e.tradeId == tradeId);
|
||||
|
||||
if (mounted) {
|
||||
if (mounted &&
|
||||
trade.exchangeName != MajesticBankExchange.exchangeName) {
|
||||
final exchange = Exchange.fromName(trade.exchangeName);
|
||||
final response = await exchange.updateTrade(trade);
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ import 'package:stackwallet/providers/global/wallets_provider.dart';
|
|||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/biometrics.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
|
@ -80,19 +82,47 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
if (widget.popOnSuccess) {
|
||||
Navigator.of(context).pop(widget.routeOnSuccessArguments);
|
||||
} else {
|
||||
unawaited(Navigator.of(context).pushReplacementNamed(
|
||||
widget.routeOnSuccess,
|
||||
arguments: widget.routeOnSuccessArguments,
|
||||
));
|
||||
if (widget.routeOnSuccess == HomeView.routeName &&
|
||||
widget.routeOnSuccessArguments is String) {
|
||||
final loadIntoWallet = widget.routeOnSuccess == HomeView.routeName &&
|
||||
widget.routeOnSuccessArguments is String;
|
||||
|
||||
if (loadIntoWallet) {
|
||||
final walletId = widget.routeOnSuccessArguments as String;
|
||||
unawaited(Navigator.of(context).pushNamed(WalletView.routeName,
|
||||
arguments: Tuple2(
|
||||
|
||||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||
if (manager.coin == Coin.monero || manager.coin == Coin.wownero) {
|
||||
await showLoading(
|
||||
opaqueBG: true,
|
||||
whileFuture: manager.initializeExisting(),
|
||||
context: context,
|
||||
message: "Loading ${manager.coin.prettyName} wallet...",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
Navigator.of(context).pushReplacementNamed(
|
||||
widget.routeOnSuccess,
|
||||
arguments: widget.routeOnSuccessArguments,
|
||||
),
|
||||
);
|
||||
|
||||
if (loadIntoWallet) {
|
||||
final walletId = widget.routeOnSuccessArguments as String;
|
||||
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletView.routeName,
|
||||
arguments: Tuple2(
|
||||
walletId,
|
||||
ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManagerProvider(walletId))));
|
||||
.getManagerProvider(walletId),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_native_splash/cli_commands.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
|
||||
class AddressTag extends StatelessWidget {
|
||||
|
@ -16,10 +17,12 @@ class AddressTag extends StatelessWidget {
|
|||
vertical: 5,
|
||||
horizontal: 7,
|
||||
),
|
||||
color: Colors.black,
|
||||
color: Theme.of(context).extension<StackColors>()!.buttonBackPrimary,
|
||||
child: Text(
|
||||
tag.capitalize(),
|
||||
style: STextStyles.w500_14(context),
|
||||
style: STextStyles.w500_14(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.buttonTextPrimary,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -62,6 +62,44 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
|||
late bool saveEnabled;
|
||||
late bool testConnectionEnabled;
|
||||
|
||||
Future<bool> _xmrHelper(String url, int? port) async {
|
||||
final uri = Uri.parse(url);
|
||||
|
||||
final String path = uri.path.isEmpty ? "/json_rpc" : uri.path;
|
||||
|
||||
final uriString = "${uri.scheme}://${uri.host}:${port ?? 0}$path";
|
||||
|
||||
ref.read(nodeFormDataProvider).useSSL = true;
|
||||
|
||||
final response = await testMoneroNodeConnection(
|
||||
Uri.parse(uriString),
|
||||
false,
|
||||
);
|
||||
|
||||
if (response.cert != null) {
|
||||
if (mounted) {
|
||||
final shouldAllowBadCert = await showBadX509CertificateDialog(
|
||||
response.cert!,
|
||||
response.url!,
|
||||
response.port!,
|
||||
context,
|
||||
);
|
||||
|
||||
if (shouldAllowBadCert) {
|
||||
final response =
|
||||
await testMoneroNodeConnection(Uri.parse(uriString), true);
|
||||
ref.read(nodeFormDataProvider).host = url;
|
||||
return response.success;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ref.read(nodeFormDataProvider).host = url;
|
||||
return response.success;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Future<bool> _testConnection({bool showFlushBar = true}) async {
|
||||
final formData = ref.read(nodeFormDataProvider);
|
||||
|
||||
|
@ -86,41 +124,19 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
|||
case Coin.monero:
|
||||
case Coin.wownero:
|
||||
try {
|
||||
final uri = Uri.parse(formData.host!);
|
||||
if (uri.scheme.startsWith("http")) {
|
||||
final String path = uri.path.isEmpty ? "/json_rpc" : uri.path;
|
||||
final url = formData.host!;
|
||||
final uri = Uri.tryParse(url);
|
||||
if (uri != null) {
|
||||
if (!uri.hasScheme) {
|
||||
// try https first
|
||||
testPassed = await _xmrHelper("https://$url", formData.port);
|
||||
|
||||
String uriString =
|
||||
"${uri.scheme}://${uri.host}:${formData.port ?? 0}$path";
|
||||
|
||||
if (uri.host == "https") {
|
||||
ref.read(nodeFormDataProvider).useSSL = true;
|
||||
} else {
|
||||
ref.read(nodeFormDataProvider).useSSL = false;
|
||||
}
|
||||
|
||||
final response = await testMoneroNodeConnection(
|
||||
Uri.parse(uriString),
|
||||
false,
|
||||
);
|
||||
|
||||
if (response.cert != null) {
|
||||
if (mounted) {
|
||||
final shouldAllowBadCert = await showBadX509CertificateDialog(
|
||||
response.cert!,
|
||||
response.url!,
|
||||
response.port!,
|
||||
context,
|
||||
);
|
||||
|
||||
if (shouldAllowBadCert) {
|
||||
final response = await testMoneroNodeConnection(
|
||||
Uri.parse(uriString), true);
|
||||
testPassed = response.success;
|
||||
}
|
||||
if (testPassed == false) {
|
||||
// try http
|
||||
testPassed = await _xmrHelper("http://$url", formData.port);
|
||||
}
|
||||
} else {
|
||||
testPassed = response.success;
|
||||
testPassed = await _xmrHelper(url, formData.port);
|
||||
}
|
||||
}
|
||||
} catch (e, s) {
|
||||
|
@ -158,7 +174,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
|||
break;
|
||||
}
|
||||
|
||||
if (showFlushBar) {
|
||||
if (showFlushBar && mounted) {
|
||||
if (testPassed) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
|
@ -182,7 +198,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
|||
|
||||
bool? shouldSave;
|
||||
|
||||
if (!canConnect) {
|
||||
if (!canConnect && mounted) {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: true,
|
||||
|
@ -975,7 +991,6 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
|||
controller: _usernameController,
|
||||
readOnly: shouldBeReadOnly,
|
||||
enabled: enableField(_usernameController),
|
||||
keyboardType: TextInputType.number,
|
||||
focusNode: _usernameFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
|
@ -1024,7 +1039,7 @@ class _NodeFormState extends ConsumerState<NodeForm> {
|
|||
controller: _passwordController,
|
||||
readOnly: shouldBeReadOnly,
|
||||
enabled: enableField(_passwordController),
|
||||
keyboardType: TextInputType.number,
|
||||
obscureText: true,
|
||||
focusNode: _passwordFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
|
|
|
@ -282,6 +282,7 @@ abstract class SWB {
|
|||
backupWallet['id'] = manager.walletId;
|
||||
backupWallet['isFavorite'] = manager.isFavorite;
|
||||
backupWallet['mnemonic'] = await manager.mnemonic;
|
||||
backupWallet['mnemonicPassphrase'] = await manager.mnemonicPassphrase;
|
||||
backupWallet['coinName'] = manager.coin.name;
|
||||
backupWallet['storedChainHeight'] = DB.instance
|
||||
.get<dynamic>(boxName: manager.walletId, key: 'storedChainHeight');
|
||||
|
@ -363,6 +364,7 @@ abstract class SWB {
|
|||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring,
|
||||
mnemonic: mnemonic,
|
||||
mnemonicPassphrase: mnemonicPassphrase,
|
||||
);
|
||||
|
||||
if (_shouldCancelRestore) {
|
||||
|
@ -432,6 +434,7 @@ abstract class SWB {
|
|||
address: currentAddress,
|
||||
height: restoreHeight,
|
||||
mnemonic: mnemonic,
|
||||
mnemonicPassphrase: mnemonicPassphrase,
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
|
@ -440,6 +443,7 @@ abstract class SWB {
|
|||
restoringStatus: StackRestoringStatus.failed,
|
||||
manager: manager,
|
||||
mnemonic: mnemonic,
|
||||
mnemonicPassphrase: mnemonicPassphrase,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -148,15 +148,16 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
|
|||
),
|
||||
children: infoToggle
|
||||
? [
|
||||
if (Constants.enableExchange)
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data preloaded for a seamless experience.\n\n"),
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data preloaded for a seamless experience."),
|
||||
const TextSpan(
|
||||
text:
|
||||
"\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."),
|
||||
"CoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency).\n\n"),
|
||||
TextSpan(
|
||||
text:
|
||||
"\n\nRecommended for most crypto users.",
|
||||
"Recommended for most crypto users.",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall600(
|
||||
|
@ -170,15 +171,16 @@ class _StackPrivacyCalls extends ConsumerState<StackPrivacyCalls> {
|
|||
),
|
||||
]
|
||||
: [
|
||||
if (Constants.enableExchange)
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data not preloaded (slower experience).\n\n"),
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data not preloaded (slower experience)."),
|
||||
const TextSpan(
|
||||
text:
|
||||
"\n\nCoinGecko disabled (price changes not shown, no wallet value shown in other currencies)."),
|
||||
"CoinGecko disabled (price changes not shown, no wallet value shown in other currencies).\n\n"),
|
||||
TextSpan(
|
||||
text:
|
||||
"\n\nRecommended for the privacy conscious.",
|
||||
"Recommended for the privacy conscious.",
|
||||
style: isDesktop
|
||||
? STextStyles
|
||||
.desktopTextExtraExtraSmall600(
|
||||
|
|
|
@ -44,6 +44,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|||
import 'package:stackwallet/utilities/enums/derive_path_type_enum.dart';
|
||||
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/background.dart';
|
||||
|
@ -260,11 +261,6 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
void _onExchangePressed(BuildContext context) async {
|
||||
final coin = ref.read(managerProvider).coin;
|
||||
|
||||
final currency = ExchangeDataLoadingService.instance.isar.currencies
|
||||
.where()
|
||||
.tickerEqualToAnyExchangeNameName(coin.ticker)
|
||||
.findFirstSync();
|
||||
|
||||
if (coin.isTestNet) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
|
@ -273,6 +269,15 @@ class _WalletViewState extends ConsumerState<WalletView> {
|
|||
),
|
||||
);
|
||||
} else {
|
||||
final currency = await showLoading(
|
||||
whileFuture: ExchangeDataLoadingService.instance.isar.currencies
|
||||
.where()
|
||||
.tickerEqualToAnyExchangeNameName(coin.ticker)
|
||||
.findFirst(),
|
||||
context: context,
|
||||
message: "Loading...",
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
|
|
|
@ -96,9 +96,10 @@ class _StackPrivacyDialog extends ConsumerState<StackPrivacyDialog> {
|
|||
),
|
||||
children: infoToggle
|
||||
? [
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data preloaded for a seamless experience."),
|
||||
if (Constants.enableExchange)
|
||||
const TextSpan(
|
||||
text:
|
||||
"Exchange data preloaded for a seamless experience."),
|
||||
const TextSpan(
|
||||
text:
|
||||
"\n\nCoinGecko enabled: (24 hour price change shown in-app, total wallet value shown in USD or other currency)."),
|
||||
|
|
|
@ -862,6 +862,9 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
Map<String, dynamic>? args}) async {
|
||||
try {
|
||||
int realfee = await nativeFee(satoshiAmount);
|
||||
if (balance.spendable == satoshiAmount) {
|
||||
satoshiAmount = balance.spendable - realfee;
|
||||
}
|
||||
|
||||
Map<String, dynamic> txData = {
|
||||
"fee": realfee,
|
||||
|
@ -906,33 +909,81 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
});
|
||||
debugPrint(transactionFees);
|
||||
dynamic decodeData;
|
||||
try {
|
||||
decodeData = json.decode(transactionFees!);
|
||||
} catch (e) {
|
||||
if (ifErrorEstimateFee) {
|
||||
//Error Not enough funds. Required: 0.56500000, Available: 0.56200000
|
||||
if (transactionFees!.contains("Required")) {
|
||||
var splits = transactionFees!.split(" ");
|
||||
Decimal required = Decimal.zero;
|
||||
Decimal available = Decimal.zero;
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
var word = splits[i];
|
||||
if (word == "Required:") {
|
||||
required = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
} else if (word == "Available:") {
|
||||
available = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
}
|
||||
|
||||
final available = balance.spendable;
|
||||
|
||||
if (available == satoshiAmount) {
|
||||
if (transactionFees!.contains("Required")) {
|
||||
var splits = transactionFees!.split(" ");
|
||||
Decimal required = Decimal.zero;
|
||||
Decimal available = Decimal.zero;
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
var word = splits[i];
|
||||
if (word == "Required:") {
|
||||
required = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
} else if (word == "Available:") {
|
||||
available = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
}
|
||||
int largestSatoshiFee =
|
||||
((required - available) * Decimal.fromInt(100000000))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
Logging.instance.log("largestSatoshiFee $largestSatoshiFee",
|
||||
level: LogLevel.Info);
|
||||
return largestSatoshiFee;
|
||||
}
|
||||
int largestSatoshiFee =
|
||||
((required - available) * Decimal.fromInt(100000000))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
var amountSending = satoshiAmount - largestSatoshiFee;
|
||||
|
||||
//Get fees for this new amount
|
||||
await m.protect(() async {
|
||||
ReceivePort receivePort = await getIsolate({
|
||||
"function": "getTransactionFees",
|
||||
"wallet": wallet!,
|
||||
"amount": amountSending,
|
||||
"minimumConfirmations": MINIMUM_CONFIRMATIONS,
|
||||
}, name: walletName);
|
||||
|
||||
var message = await receivePort.first;
|
||||
if (message is String) {
|
||||
Logging.instance
|
||||
.log("this is a string $message", level: LogLevel.Error);
|
||||
stop(receivePort);
|
||||
throw Exception("getTransactionFees isolate failed");
|
||||
}
|
||||
stop(receivePort);
|
||||
Logging.instance.log('Closing getTransactionFees!\n $message',
|
||||
level: LogLevel.Info);
|
||||
// return message;
|
||||
transactionFees = message['result'] as String;
|
||||
});
|
||||
}
|
||||
decodeData = json.decode(transactionFees!);
|
||||
} else {
|
||||
try {
|
||||
decodeData = json.decode(transactionFees!);
|
||||
} catch (e) {
|
||||
if (ifErrorEstimateFee) {
|
||||
//Error Not enough funds. Required: 0.56500000, Available: 0.56200000
|
||||
if (transactionFees!.contains("Required")) {
|
||||
var splits = transactionFees!.split(" ");
|
||||
Decimal required = Decimal.zero;
|
||||
Decimal available = Decimal.zero;
|
||||
for (int i = 0; i < splits.length; i++) {
|
||||
var word = splits[i];
|
||||
if (word == "Required:") {
|
||||
required = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
} else if (word == "Available:") {
|
||||
available = Decimal.parse(splits[i + 1].replaceAll(",", ""));
|
||||
}
|
||||
}
|
||||
int largestSatoshiFee =
|
||||
((required - available) * Decimal.fromInt(100000000))
|
||||
.toBigInt()
|
||||
.toInt();
|
||||
Logging.instance.log("largestSatoshiFee $largestSatoshiFee",
|
||||
level: LogLevel.Info);
|
||||
return largestSatoshiFee;
|
||||
}
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
|
||||
//TODO: first problem
|
||||
|
@ -1799,7 +1850,7 @@ class EpicCashWallet extends CoinServiceAPI
|
|||
// final chunk = {
|
||||
// "timestamp": txTimeArray[0],
|
||||
// "transactions": [txObject],
|
||||
// };
|
||||
// };sendAll
|
||||
//
|
||||
// // result["dateTimeChunks"].
|
||||
// result["dateTimeChunks"].add(chunk);
|
||||
|
|
|
@ -2490,60 +2490,17 @@ class FiroWallet extends CoinServiceAPI with WalletCache, WalletDB, FiroHive {
|
|||
});
|
||||
}
|
||||
|
||||
// final int utxosIntValue = utxos.satoshiBalance;
|
||||
// final Decimal utxosValue =
|
||||
// Format.satoshisToAmount(utxosIntValue, coin: coin);
|
||||
|
||||
// List<Decimal> balances = List.empty(growable: true);
|
||||
//
|
||||
// Decimal lelantusBalance =
|
||||
// Format.satoshisToAmount(intLelantusBalance, coin: coin);
|
||||
|
||||
// balances.add(lelantusBalance); 0
|
||||
//
|
||||
// balances.add(lelantusBalance * price); 1
|
||||
|
||||
// Decimal _unconfirmedLelantusBalance =
|
||||
// Format.satoshisToAmount(unconfirmedLelantusBalance, coin: coin);
|
||||
|
||||
// balances.add(lelantusBalance + utxosValue + _unconfirmedLelantusBalance); 2
|
||||
//
|
||||
// balances.add(
|
||||
// (lelantusBalance + utxosValue + _unconfirmedLelantusBalance) * price); 3
|
||||
|
||||
// int availableSats =
|
||||
// utxos.satoshiBalance - utxos.satoshiBalanceUnconfirmed;
|
||||
// if (availableSats < 0) {
|
||||
// availableSats = 0;
|
||||
// }
|
||||
// balances.add(Format.satoshisToAmount(availableSats, coin: coin)); 4
|
||||
_balancePrivate = Balance(
|
||||
coin: coin,
|
||||
total: intLelantusBalance + unconfirmedLelantusBalance,
|
||||
spendable: intLelantusBalance,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: unconfirmedLelantusBalance,
|
||||
);
|
||||
await updateCachedBalanceSecondary(_balancePrivate!);
|
||||
|
||||
// wait for updated uxtos to get updated public balance
|
||||
await utxosUpdateFuture;
|
||||
|
||||
// todo: shared total between private and public balances?
|
||||
_balancePrivate = Balance(
|
||||
coin: coin,
|
||||
total: intLelantusBalance + unconfirmedLelantusBalance + balance.total,
|
||||
spendable: intLelantusBalance,
|
||||
blockedTotal: 0,
|
||||
pendingSpendable: unconfirmedLelantusBalance + balance.total,
|
||||
);
|
||||
await updateCachedBalanceSecondary(_balancePrivate!);
|
||||
// _balance = Balance(
|
||||
// coin: coin,
|
||||
// total: utxos.satoshiBalance,
|
||||
// spendable: availableSats,
|
||||
// blockedTotal: 0,
|
||||
// pendingSpendable: utxos.satoshiBalanceUnconfirmed,
|
||||
// );
|
||||
|
||||
// Logging.instance.log("balances $balances", level: LogLevel.Info);
|
||||
// await DB.instance.put<dynamic>(
|
||||
// boxName: walletId,
|
||||
// key: 'totalBalance',
|
||||
// value: balances[2].toString());
|
||||
// return balances;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Exception rethrown in getFullBalance(): $e\n$s",
|
||||
level: LogLevel.Error);
|
||||
|
|
|
@ -273,25 +273,25 @@ class ExchangeDataLoadingService {
|
|||
// }
|
||||
|
||||
Future<void> loadMajesticBankCurrencies() async {
|
||||
final exchange = MajesticBankExchange.instance;
|
||||
final responseCurrencies = await exchange.getAllCurrencies(false);
|
||||
|
||||
if (responseCurrencies.value != null) {
|
||||
await isar.writeTxn(() async {
|
||||
final idsToDelete = await isar.currencies
|
||||
.where()
|
||||
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
||||
.idProperty()
|
||||
.findAll();
|
||||
await isar.currencies.deleteAll(idsToDelete);
|
||||
await isar.currencies.putAll(responseCurrencies.value!);
|
||||
});
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"loadMajesticBankCurrencies: $responseCurrencies",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
}
|
||||
// final exchange = MajesticBankExchange.instance;
|
||||
// final responseCurrencies = await exchange.getAllCurrencies(false);
|
||||
//
|
||||
// if (responseCurrencies.value != null) {
|
||||
await isar.writeTxn(() async {
|
||||
final idsToDelete = await isar.currencies
|
||||
.where()
|
||||
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
||||
.idProperty()
|
||||
.findAll();
|
||||
await isar.currencies.deleteAll(idsToDelete);
|
||||
// await isar.currencies.putAll(responseCurrencies.value!);
|
||||
});
|
||||
// } else {
|
||||
// Logging.instance.log(
|
||||
// "loadMajesticBankCurrencies: $responseCurrencies",
|
||||
// level: LogLevel.Warning,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
// Future<void> loadMajesticBankPairs() async {
|
||||
|
|
|
@ -14,10 +14,11 @@ import 'package:stackwallet/services/exchange/exchange_response.dart';
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
class MajesticBankAPI {
|
||||
static const String scheme = "https";
|
||||
static const String authority = "majesticbank.sc";
|
||||
static const String version = "v1";
|
||||
static const kMajesticBankRefCode = "rjWugM";
|
||||
// ensure no api calls go out to mb
|
||||
static const String scheme = ""; //"""https";
|
||||
static const String authority = ""; //"""majesticbank.sc";
|
||||
static const String version = ""; //"""v1";
|
||||
static const kMajesticBankRefCode = ""; //"""rjWugM";
|
||||
|
||||
MajesticBankAPI._();
|
||||
|
||||
|
@ -33,6 +34,8 @@ class MajesticBankAPI {
|
|||
}
|
||||
|
||||
Future<dynamic> _makeGetRequest(Uri uri) async {
|
||||
return null;
|
||||
|
||||
final client = this.client ?? http.Client();
|
||||
int code = -1;
|
||||
try {
|
||||
|
|
|
@ -7,6 +7,7 @@ import 'package:stackwallet/hive/db.dart';
|
|||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||
import 'package:stackwallet/models/notification_model.dart';
|
||||
import 'package:stackwallet/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/services/trade_service.dart';
|
||||
|
@ -197,57 +198,59 @@ class NotificationsService extends ChangeNotifier {
|
|||
final oldTrade = trades.first;
|
||||
late final ExchangeResponse<Trade> response;
|
||||
|
||||
try {
|
||||
final exchange = Exchange.fromName(oldTrade.exchangeName);
|
||||
response = await exchange.updateTrade(oldTrade);
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final trade = response.value!;
|
||||
|
||||
// only update if status has changed
|
||||
if (trade.status != notification.title) {
|
||||
bool shouldWatchForUpdates = true;
|
||||
// TODO: make sure we set shouldWatchForUpdates to correct value here
|
||||
switch (trade.status) {
|
||||
case "Refunded":
|
||||
case "refunded":
|
||||
case "Failed":
|
||||
case "failed":
|
||||
case "closed":
|
||||
case "expired":
|
||||
case "Finished":
|
||||
case "finished":
|
||||
case "Completed":
|
||||
case "completed":
|
||||
case "Not found":
|
||||
shouldWatchForUpdates = false;
|
||||
break;
|
||||
default:
|
||||
shouldWatchForUpdates = true;
|
||||
if (oldTrade.exchangeName != MajesticBankExchange.exchangeName) {
|
||||
try {
|
||||
final exchange = Exchange.fromName(oldTrade.exchangeName);
|
||||
response = await exchange.updateTrade(oldTrade);
|
||||
} catch (_) {
|
||||
return;
|
||||
}
|
||||
|
||||
final updatedNotification = notification.copyWith(
|
||||
title: trade.status,
|
||||
shouldWatchForUpdates: shouldWatchForUpdates,
|
||||
);
|
||||
|
||||
// remove from watch list if shouldWatchForUpdates was changed
|
||||
if (!shouldWatchForUpdates) {
|
||||
await _deleteWatchedTradeNotification(notification);
|
||||
if (response.value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// replaces the current notification with the updated one
|
||||
unawaited(add(updatedNotification, true));
|
||||
final trade = response.value!;
|
||||
|
||||
// update the trade in db
|
||||
// over write trade stored in db with updated version
|
||||
await tradesService.edit(trade: trade, shouldNotifyListeners: true);
|
||||
// only update if status has changed
|
||||
if (trade.status != notification.title) {
|
||||
bool shouldWatchForUpdates = true;
|
||||
// TODO: make sure we set shouldWatchForUpdates to correct value here
|
||||
switch (trade.status) {
|
||||
case "Refunded":
|
||||
case "refunded":
|
||||
case "Failed":
|
||||
case "failed":
|
||||
case "closed":
|
||||
case "expired":
|
||||
case "Finished":
|
||||
case "finished":
|
||||
case "Completed":
|
||||
case "completed":
|
||||
case "Not found":
|
||||
shouldWatchForUpdates = false;
|
||||
break;
|
||||
default:
|
||||
shouldWatchForUpdates = true;
|
||||
}
|
||||
|
||||
final updatedNotification = notification.copyWith(
|
||||
title: trade.status,
|
||||
shouldWatchForUpdates: shouldWatchForUpdates,
|
||||
);
|
||||
|
||||
// remove from watch list if shouldWatchForUpdates was changed
|
||||
if (!shouldWatchForUpdates) {
|
||||
await _deleteWatchedTradeNotification(notification);
|
||||
}
|
||||
|
||||
// replaces the current notification with the updated one
|
||||
unawaited(add(updatedNotification, true));
|
||||
|
||||
// update the trade in db
|
||||
// over write trade stored in db with updated version
|
||||
await tradesService.edit(trade: trade, shouldNotifyListeners: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
43
lib/utilities/show_loading.dart
Normal file
43
lib/utilities/show_loading.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||
|
||||
Future<T> showLoading<T>({
|
||||
required Future<T> whileFuture,
|
||||
required BuildContext context,
|
||||
required String message,
|
||||
String? subMessage,
|
||||
bool isDesktop = false,
|
||||
bool opaqueBG = false,
|
||||
}) async {
|
||||
unawaited(
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => WillPopScope(
|
||||
onWillPop: () async => false,
|
||||
child: Container(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.overlay
|
||||
.withOpacity(opaqueBG ? 1.0 : 0.6),
|
||||
child: CustomLoadingOverlay(
|
||||
message: message,
|
||||
subMessage: subMessage,
|
||||
eventBus: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final result = await whileFuture;
|
||||
|
||||
if (context.mounted) {
|
||||
Navigator.of(context, rootNavigator: isDesktop).pop();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -33,22 +33,24 @@ class WalletSheetCard extends ConsumerWidget {
|
|||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
final manager = ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(walletId);
|
||||
if (manager.coin == Coin.monero ||
|
||||
manager.coin == Coin.wownero) {
|
||||
final manager =
|
||||
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||
if (manager.coin == Coin.monero || manager.coin == Coin.wownero) {
|
||||
await manager.initializeExisting();
|
||||
}
|
||||
if (popPrevious) Navigator.of(context).pop();
|
||||
Navigator.of(context).pushNamed(
|
||||
WalletView.routeName,
|
||||
arguments: Tuple2(
|
||||
if (context.mounted) {
|
||||
if (popPrevious && context.mounted) Navigator.of(context).pop();
|
||||
|
||||
await Navigator.of(context).pushNamed(
|
||||
WalletView.routeName,
|
||||
arguments: Tuple2(
|
||||
walletId,
|
||||
ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManagerProvider(walletId)),
|
||||
);
|
||||
.getManagerProvider(walletId),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: WalletInfoRow(
|
||||
walletId: walletId,
|
||||
|
|
|
@ -11,7 +11,7 @@ description: Stack Wallet
|
|||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.6.5+147
|
||||
version: 1.6.7+149
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
|
|
Loading…
Reference in a new issue